[SOLVED] user interaction from widget
Moderator: andrew
Forum rules
Always indicate your operating system and QCAD version.
Attach drawing files, scripts and screenshots.
Post one question per topic.
Always indicate your operating system and QCAD version.
Attach drawing files, scripts and screenshots.
Post one question per topic.
[SOLVED] user interaction from widget
Hi,
for the model railroad scripts currently I'm working on a widget that should insert a track in the drawing at an user specified position (similar to BlockInsert, but the track must be connected to an existing track and therefore rotated automatically). The existing widgets like BlockList widget or LayerList widget connect to other scripts through button.setDefaultAction(RGUIAction...), but after the coordinate is picked, I need to have a reference to the scope (this) of the current widget to get some more parameters.
Is there an elegant way of letting the user pick a coordinate / entity / checked block and then starting another script and exchange parameters with it?
Thanks in advance, best regards
Stefan
for the model railroad scripts currently I'm working on a widget that should insert a track in the drawing at an user specified position (similar to BlockInsert, but the track must be connected to an existing track and therefore rotated automatically). The existing widgets like BlockList widget or LayerList widget connect to other scripts through button.setDefaultAction(RGUIAction...), but after the coordinate is picked, I need to have a reference to the scope (this) of the current widget to get some more parameters.
Is there an elegant way of letting the user pick a coordinate / entity / checked block and then starting another script and exchange parameters with it?
Thanks in advance, best regards
Stefan
Last edited by smf on Tue Dec 23, 2014 5:15 pm, edited 1 time in total.
Re: user interaction from widget
...now I'm trying with a global variable and access like Block.getActiveBlockId - this really seems to be the intended way to do things like this. I will report after success or failure.
Re: user interaction from widget
I'm very sorry, but I'm trying for hours now and never succeed in handing out a simple reference to an instance created by another script. The global variable thing didn't worked out, I always get the unmodified initialization of my "global" variable. So I tried to replicate the BlockListWidget-AddBlock-duo. But this didn't worked out either.
First: attaching an action to the toolbutton of my widget, I tried:
But this always returns null (file exists, and using the shortcut "QB" defined there is working). Replacing the getbyScriptFile-parameter by the AddBlock.js, it returns a RGuiAction. But why?
Second: Trying to access the list of type RTrackListQt inside TrackListWidget, I always get a reference to RListWidget - which is the parent of RTrackListQt not what I need to access the required variables.
I'm very used to Java which is completely different in terms of classes, instances and references to them. So any suggestion is welcome, ECMA is driving me crazy.
First: attaching an action to the toolbutton of my widget, I tried:
Code: Select all
var saction = RGuiAction.getByScriptFile("scripts/QCTrack/TrackWidgetInsert/TrackWidgetInsert.js");
qDebug("saction: ", saction); //always returns null although script existing and working if started by shortcut
Second: Trying to access the list of type RTrackListQt inside TrackListWidget, I always get a reference to RListWidget - which is the parent of RTrackListQt not what I need to access the required variables.
Code: Select all
var trackList = EAction.getMainWindow().findChild("TrackList");
qDebug("trackList: ", trackList); //always returns a RListWidget instead of RTrackListQt
Re: user interaction from widget
There are several ways to share information between different scripts or between widgets, etc:
- If the information is application wide and persistent, it can be stored in the QCAD3.ini file, in this case, use RSettings:
There is one script engine running per document and one global script engine which runs global scripts such as the init functions to add tools to menus or create widgets (property editor, library browser, layer list, etc.).
What you are experiencing is likely a problem of accessing information from different script engines. Your widget is presumably created by the global script engine at the start of QCAD. Your action, however, is run by the script engine that belongs to the current document.
If your widget needs to store information that is not stored inside a child widget (such as a text in a QLineEdit would be), you can attach this information to your widget using the setProperty() method of the QObject class as outlined above. This information will be stored on the C++ level inside your QWidget object. Any script in any context can then access this information by looking up the widget (e.g. RMainWindowQt.getMainWindow().findChild("MyObjectName")) and using the property() method to access the user defined property.
Your ECMAScript class might have member variables. This works fine for everything that is limited to one script engine (i.e. only concerns an action or a widget). If you design your class with getter / setter functions, you can simply rewrite those to use QObject::setProperty(), QObject::property:
- If the information is application wide and persistent, it can be stored in the QCAD3.ini file, in this case, use RSettings:
RSettings.setValue("Key/SubKey", value); value = RSettings.getValue("Key/SubKey", defaultValue);- If the information is application wide and not persistent, one way is to attach it to a QObject, for example the main window or any other widget that might be more appropriate:
RMainWindowQt.getMainWindow().setProperty("MyUniqueName", 7); value = RMainWindowQt.getMainWindow().property("MyUniqueName");- If the information is tied to a document, store it as part of the document:
document.setVariable("Key", value); value = document.getVariable("Key", defaultValue);- If the information is tied to a drawing object (layer, entity, block, ...), attach it to the object:
object.setCustomProperty("QCAD", "Key", value); value = object.getCustomProperty("QCAD", "Key", defaultValue);Every other piece of information created by a script as a local or global variable is limited to the current script engine.
There is one script engine running per document and one global script engine which runs global scripts such as the init functions to add tools to menus or create widgets (property editor, library browser, layer list, etc.).
What you are experiencing is likely a problem of accessing information from different script engines. Your widget is presumably created by the global script engine at the start of QCAD. Your action, however, is run by the script engine that belongs to the current document.
If your widget needs to store information that is not stored inside a child widget (such as a text in a QLineEdit would be), you can attach this information to your widget using the setProperty() method of the QObject class as outlined above. This information will be stored on the C++ level inside your QWidget object. Any script in any context can then access this information by looking up the widget (e.g. RMainWindowQt.getMainWindow().findChild("MyObjectName")) and using the property() method to access the user defined property.
Your ECMAScript class might have member variables. This works fine for everything that is limited to one script engine (i.e. only concerns an action or a widget). If you design your class with getter / setter functions, you can simply rewrite those to use QObject::setProperty(), QObject::property:
MyWidget.setMyValue = function(value) { var widget = RMainWindowQt.getMainWindow().findChild("MyWidget"); widget.setProperty("MyProperty", value); }; MyWidget.getMyValue = function() { var widget = RMainWindowQt.getMainWindow().findChild("MyWidget"); return widget.property("MyProperty"); };
Re: user interaction from widget
wow. Many thanks to this explanation! This different-script-engine-thing indeed answers my problems. I will try to adopt your suggestions and report later.
Again: many thanks!
Again: many thanks!
Re: user interaction from widget
Hm, either this is not working the way I need it or I'm too stupid. The required information is not persistent and does not belong to a document, so I thought it would be best to give the widget-property a try. Unfortunately, it seems like the property is copied, so it can not hold a reference which is requested once and reflects changes of the original object.
Perhaps I try to explain what I want to do so one can see what I am missing. I have a widget displayed together with block list and layer list, depending on the tracks defined in the current document. There the user can select a track (similar to a block) and per track a "connection end" (1, 2, 3, ... depending on the track). There is an "add" button that shell add the currently selected track (at an user picked coordinate, this part is not yet working), and there is a "rotate" button that rotates the currently selected track (i.e. changes the connection end).
The "add" function as well as the "rotate" function can be activated by shortcuts - this is not needed hardly, but I couldn't find a way to let the user pick a coordinate from within the TrackListWidget which made me try to "outsource" the adding to another script. Therefore I need to get the currently selected track and the connection end and possibly need to change a spin box.
If there's a simple way to let the user pick a coordinate similar to other actions with setState, escapeEvent, pickEntity... this would be my favorite, but I couldn't get this run so I tried to adopt the BlockList/AddBlock-behavior. The data exchange there is done through Block.getActiveBlockId, but there only the currently selected item.text is used - I need more which would require my ECMA-added fields to be copied.
Perhaps I try to explain what I want to do so one can see what I am missing. I have a widget displayed together with block list and layer list, depending on the tracks defined in the current document. There the user can select a track (similar to a block) and per track a "connection end" (1, 2, 3, ... depending on the track). There is an "add" button that shell add the currently selected track (at an user picked coordinate, this part is not yet working), and there is a "rotate" button that rotates the currently selected track (i.e. changes the connection end).
The "add" function as well as the "rotate" function can be activated by shortcuts - this is not needed hardly, but I couldn't find a way to let the user pick a coordinate from within the TrackListWidget which made me try to "outsource" the adding to another script. Therefore I need to get the currently selected track and the connection end and possibly need to change a spin box.
If there's a simple way to let the user pick a coordinate similar to other actions with setState, escapeEvent, pickEntity... this would be my favorite, but I couldn't get this run so I tried to adopt the BlockList/AddBlock-behavior. The data exchange there is done through Block.getActiveBlockId, but there only the currently selected item.text is used - I need more which would require my ECMA-added fields to be copied.
- Attachments
-
- Screenshot of TrackWidget
- TrackWidget.png (11.85 KiB) Viewed 13230 times
Re: user interaction from widget
Don't store a reference to your ECMAScript object. You cannot (never) access an ECMAScript object created in one engine from another engine. What you can do is copy values back and forth using widget properties (ints, strings, doubles, etc.).smf wrote:Hm, either this is not working the way I need it or I'm too stupid. The required information is not persistent and does not belong to a document, so I thought it would be best to give the widget-property a try. Unfortunately, it seems like the property is copied, so it can not hold a reference which is requested once and reflects changes of the original object.
Re: user interaction from widget
Many thanks for the fast and clear answer.
So my idea is kind of dead. If I can not access a widget from a shortcut-script, I will have no chance to modify e.g. a specific spinbox inside this widget.
So my idea is kind of dead. If I can not access a widget from a shortcut-script, I will have no chance to modify e.g. a specific spinbox inside this widget.
Re: user interaction from widget
You can access all your widgets anytime from anywhere using their objectName. What you cannot access are references to ECMAScript objects.smf wrote:So my idea is kind of dead. If I can not access a widget from a shortcut-script, I will have no chance to modify e.g. a specific spinbox inside this widget.
Example 1:
var w = new QLineEdit(); w.objectName = "MyLineEdit";You can access this QLineEdit anytime from any script in any context for as long as it exists:
var w = RMainWindowQt.getMainWindow().findChild("MyLineEdit");Example 2:
var w = new MyScriptClassDerivedFromQWidget(); w.objectName = "MyScriptClassObject";Although you can also get a reference to the widget created here from anywhere just like above, that reference will be of type QWidget (not of type MyScriptClassDerivedFromQWidget). In this case your widget object lives in C++ up to QWidget. However, the rest of your object that is defined in ECMAScript lives in the script engine it was created in. So when accessing this widget from another script engine, you loose everything that is not defined in QWidget. Any custom information you want to access would have to be attached to the QWidget using properties.
Re: user interaction from widget
Thanks for clarification, that is what I understood of your last post. The access of the QWidget (even QListWidget) did work, the access of the ECMA added variables did not - and this is not because I did something wrong, it is caused by multiple script engines. I would have spent even more days on "how do I get those variables".In this case your widget object lives in C++ up to QWidget. However, the rest of your object that is defined in ECMAScript lives in the script engine it was created in. So when accessing this widget from another script engine, you loose everything that is not defined in QWidget.
Many thanks for your responses, so I have to think of a completely other solution.
Re: [SOLVED] user interaction from widget
...now added the current version of QCTrack here:
viewtopic.php?f=107&t=3172
The plan for the here discussed widget was to replace the option "consecutive extension", which at the moment first asks for a track end to extend and then always shows a dialog by which track the existing track is to be extended.
viewtopic.php?f=107&t=3172
The plan for the here discussed widget was to replace the option "consecutive extension", which at the moment first asks for a track end to extend and then always shows a dialog by which track the existing track is to be extended.