How can I react to or intercept modifications to a document? For example to move an entity when another entity has been moved or to prevent an entity from being deleted.
Reacting to document modifications
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.
Reacting to document modifications
From a QCAD developer:
Re: Reacting to document modifications
What you are looking for is called a "listener" in QCAD.
The listeners that are notified whenever a document changes are:
- RTransactionListener
- RInterTransactionListener
The difference is that the transaction has been settled when RTransactionListener is notified. When RInterTransactionListener is notified, the transaction is still in progress and may be amended if desired.
You can find an example for an RTransactionListener (in ECMAScript) at:
https://github.com/qcad/qcad/blob/maste ... istener.js
To try the example with your QCAD installation, choose Misc > Examples > Listeners > Transaction Listener. This installs a transaction listener and prints information about every transaction to the command line history of QCAD.
Other listeners exist to:
- react to changes of layers (RLayerListener)
- react to changes of blocks (RBLockListener)
- react when entities are being exported / displayed (REntityExportListener)
- react when documents are being exported / saved (RExportListener)
- react when documents are being imported / loaded (RImportListener)
- react when the focus changes from one document to another (RFocusListener)
- react when the state of the document changes from modified to unmodified and vice versa (RModifiedListener)
- react to mouse coordinate changes (RMouseCoordinateListener)
- react to new documents being created (RNewDocumentListener)
For a complete overview, please refer to:
http://www.qcad.org/doc/qcad/latest/dev ... tated.html
And search for "listener".
The listeners that are notified whenever a document changes are:
- RTransactionListener
- RInterTransactionListener
The difference is that the transaction has been settled when RTransactionListener is notified. When RInterTransactionListener is notified, the transaction is still in progress and may be amended if desired.
You can find an example for an RTransactionListener (in ECMAScript) at:
https://github.com/qcad/qcad/blob/maste ... istener.js
To try the example with your QCAD installation, choose Misc > Examples > Listeners > Transaction Listener. This installs a transaction listener and prints information about every transaction to the command line history of QCAD.
Other listeners exist to:
- react to changes of layers (RLayerListener)
- react to changes of blocks (RBLockListener)
- react when entities are being exported / displayed (REntityExportListener)
- react when documents are being exported / saved (RExportListener)
- react when documents are being imported / loaded (RImportListener)
- react when the focus changes from one document to another (RFocusListener)
- react when the state of the document changes from modified to unmodified and vice versa (RModifiedListener)
- react to mouse coordinate changes (RMouseCoordinateListener)
- react to new documents being created (RNewDocumentListener)
For a complete overview, please refer to:
http://www.qcad.org/doc/qcad/latest/dev ... tated.html
And search for "listener".
-
- Full Member
- Posts: 58
- Joined: Wed Mar 16, 2016 5:10 pm
Re: Reacting to document modifications
Greetings.
First of all, good question and good answer.
I have tried to apply a listening function on the code I'm working on. I did the call on the .js file I was already working and it seems to call correctly in the example provided.
I wanted to make a few changes though, I tried to make it so that the notification only happens when entities are added or deleted. According to your post I'm let to believe the (REntityExportListener) Is whan I'm looking for. Do correct me if I'm wrong.
I tried:
I receive on: AutoRefresh.transactionUpdated.connect(function(document, vl_changes) the error:
Uncaught exception at scripts/IuSYS/iuSYS_Cam/iuSYS_Cam.js:1683: TypeError: Result of expression 'AutoRefresh.transactionUpdated' [undefined] is not an object.
I've tried swimming through the vast ocean of information that is the Qcad documentation but returned only with questions.
For one, after reading the docs, I've grown suspicious that this function RTransactionListener is not called when any entity is changed, but is only called when a specific entity is changed, as in indicated in: REntityExportListener. I would like confirmation on this.
Assuming this does what I need it to, I suppose the "transactionUpdated" part needs to be replaced by something else. May I request assistance here?
Somewhat off-topic.
Currently, I am searching for specific entities by making:
the custom_ID sometimes comes from the autorefresh fucntion and others comes from a tablewidget that holds the IDs of every entity on the document. Sometimes I need to cross reference the data between the table and the entitylist so Ibasically I need to do a for within a for to find the correct IDs. My question is: Is there a more effective way, in code size and processing speed, to find an entity in the entityIds pool that this one? Some way, perhaps that uses inbuilt Qcad instructions?
I love you all.
Thanks for the assistance.
First of all, good question and good answer.
I have tried to apply a listening function on the code I'm working on. I did the call on the .js file I was already working and it seems to call correctly in the example provided.
I wanted to make a few changes though, I tried to make it so that the notification only happens when entities are added or deleted. According to your post I'm let to believe the (REntityExportListener) Is whan I'm looking for. Do correct me if I'm wrong.
I tried:
Code: Select all
AutoRefresh = new REntityExportListenerAdapter(); //Considera alterações às entidades
appWin.addEntityExportListener(AutoRefresh);
// ...
AutoRefresh.transactionUpdated.connect(function(document, vl_changes) { //detects change?
//does something
}
Uncaught exception at scripts/IuSYS/iuSYS_Cam/iuSYS_Cam.js:1683: TypeError: Result of expression 'AutoRefresh.transactionUpdated' [undefined] is not an object.
I've tried swimming through the vast ocean of information that is the Qcad documentation but returned only with questions.
For one, after reading the docs, I've grown suspicious that this function RTransactionListener is not called when any entity is changed, but is only called when a specific entity is changed, as in indicated in: REntityExportListener. I would like confirmation on this.
Assuming this does what I need it to, I suppose the "transactionUpdated" part needs to be replaced by something else. May I request assistance here?
Somewhat off-topic.
Currently, I am searching for specific entities by making:
Code: Select all
for (i = 0; i < entityIds.length; i++) {
entity = doc.queryEntity(entityIds[i]);
Entity_ID = Entity_to_text(entity);
if (Entity_ID == custom_ID){
//Does stuff
break;
}
}
}
I love you all.
Thanks for the assistance.
Last edited by Ghost_of_Magellan on Thu Aug 04, 2016 3:28 pm, edited 1 time in total.
Re: Reacting to document modifications
You appear to be mixing up RTransactionListenerAdapter and REntityExportListener in your post.
The code you've posted using RTransactionListenerAdapter looks fine though. You also might want to look at this complete and working example for RTransactionListenerAdapter:
https://github.com/qcad/qcad/blob/maste ... istener.js
I'm guessing the exception is caused by something else (perhaps in the // ... skipped code part).
Also, please make sure you are using the latest version of QCAD.
Please split unrelated questions into separate topics, thanks.
The code you've posted using RTransactionListenerAdapter looks fine though. You also might want to look at this complete and working example for RTransactionListenerAdapter:
https://github.com/qcad/qcad/blob/maste ... istener.js
I'm guessing the exception is caused by something else (perhaps in the // ... skipped code part).
Also, please make sure you are using the latest version of QCAD.
Please split unrelated questions into separate topics, thanks.
-
- Full Member
- Posts: 58
- Joined: Wed Mar 16, 2016 5:10 pm
Re: Reacting to document modifications
Apologies, you are absolutely correct.
And yes, my example with the transaction method works perfectly. I just wanted to limit it only to changes in entities.
The example is the same, but with;
I suppose it's best if I change my original post.
And yes, my example with the transaction method works perfectly. I just wanted to limit it only to changes in entities.
The example is the same, but with;
Code: Select all
AutoRefresh = new REntityExportListenerAdapter(); //Considera alterações às entidades
appWin.addEntityExportListener(AutoRefresh);
Re: Reacting to document modifications
RTransactionListenerAdapter would be the correct listener to use to monitor changes. REntityExportListenerAdapter listens to entities being exported (e.g. to a graphics scene or to a file).
Re: Reacting to document modifications
Ghost_of_Magellan: I've split your other question to this new topic:
http://www.qcad.org/rsforum/viewtopic.php?f=30&t=4339
http://www.qcad.org/rsforum/viewtopic.php?f=30&t=4339
-
- Full Member
- Posts: 58
- Joined: Wed Mar 16, 2016 5:10 pm
Re: Reacting to document modifications
Thank you, andrew.
Btw, I believe it's also relevant to mention that the listener is changed when an entity is added, deleted AND when the points are changed.
Example: Existing line from 0:0 to 0;10. Same entity is changed to 10;0 to 0;10. Listener activated.
Just is case anybody was wondering.
Thank you.
Btw, I believe it's also relevant to mention that the listener is changed when an entity is added, deleted AND when the points are changed.
Example: Existing line from 0:0 to 0;10. Same entity is changed to 10;0 to 0;10. Listener activated.
Just is case anybody was wondering.
Thank you.
-
- Full Member
- Posts: 58
- Joined: Wed Mar 16, 2016 5:10 pm
Re: Reacting to document modifications
Just wondering if there is any manner of flag in this process that is activated according to the type of change that is made on an entity.
For example, RTransactionListenerAdapter indicates that a change occured, and some other listener additionally informs that the change was in the color of the entity, or the inicial or ending point of the line or arc.
I am asking too much, perhaps?
Thank you
For example, RTransactionListenerAdapter indicates that a change occured, and some other listener additionally informs that the change was in the color of the entity, or the inicial or ending point of the line or arc.
I am asking too much, perhaps?
Thank you
-
- Full Member
- Posts: 58
- Joined: Wed Mar 16, 2016 5:10 pm
Re: Reacting to document modifications
So let's see.
As a simple test I did:
The result of vl_change is:
RPropertyChange(RPropertyTypeId(9, "", "", "", "Color") , QVariant(RColor, ) -> QVariant(RColor, )) when color is changed.
RPropertyChange(RPropertyTypeId(117, "", "", "End Point", "X") , QVariant(double, 19) -> QVariant(double, 28)) ,RPropertyChange(RPropertyTypeId(118, "", "", "End Point", "Y") , QVariant(double, 19) -> QVariant(double, 17)) ,RPropertyChange(RPropertyTypeId(30, "", "", "", "Total Length") , QVariant(double, 9.43398) -> QVariant(double, 17.2047)) when the end point is changed.
Is there anyway to get a simpler result or am I supposed to take this and split/slice this as a string to get the Id type of the change?
Edit:
I can get by with the following If, like me, you're a noob, and you only want the type of change and not any details of the change itself, this will do:
The result will be the ID of the change. 9 for color, in this case but there's end point X, end point Y, lenght, etc.
Not the best solution, nor the most professional, but for now, it works.
Is there a way to get clearer results?
Thank you very much.
As a simple test I did:
Code: Select all
AutoRefresh.transactionUpdated.connect(function(document, vl_changes) {
if (isNull(document) || isNull(vl_changes)) {
return;
}
vl_objIds = vl_changes.getAffectedObjects();
//Since vl_objIds gets me the id of the changed entity anyway I use it to get the specific change
vl_change = vl_changes.getPropertyChanges(vl_objIds[i]);
RPropertyChange(RPropertyTypeId(9, "", "", "", "Color") , QVariant(RColor, ) -> QVariant(RColor, )) when color is changed.
RPropertyChange(RPropertyTypeId(117, "", "", "End Point", "X") , QVariant(double, 19) -> QVariant(double, 28)) ,RPropertyChange(RPropertyTypeId(118, "", "", "End Point", "Y") , QVariant(double, 19) -> QVariant(double, 17)) ,RPropertyChange(RPropertyTypeId(30, "", "", "", "Total Length") , QVariant(double, 9.43398) -> QVariant(double, 17.2047)) when the end point is changed.
Is there anyway to get a simpler result or am I supposed to take this and split/slice this as a string to get the Id type of the change?
Edit:
I can get by with the following If, like me, you're a noob, and you only want the type of change and not any details of the change itself, this will do:
vl_change_list = vl_changes.getPropertyChanges(vl_objIds); vl_change_list = vl_change_list[0].toString(); var vl_pos1 = vl_change_list.search("Id")+3; var vl_pos2 = vl_change_list.search(","); vl_change_list = vl_change_list.slice(vl_pos1, vl_pos2);
The result will be the ID of the change. 9 for color, in this case but there's end point X, end point Y, lenght, etc.
Not the best solution, nor the most professional, but for now, it works.
Is there a way to get clearer results?
Thank you very much.
Last edited by Ghost_of_Magellan on Fri Aug 05, 2016 4:47 pm, edited 1 time in total.
-
- Full Member
- Posts: 58
- Joined: Wed Mar 16, 2016 5:10 pm
Re: Reacting to document modifications
On the same line of thought.
I noticed that the getPropertyChanged that I used on the example on my last post did not seem to tell me which color it was changed to, and changed from. Is there any way to receive that information through this process we were discussing? Or does this method do that already but I messed up somewhere?
Might have something to do with this, but I can't seem to make it work.
Thank you very much.
I noticed that the getPropertyChanged that I used on the example on my last post did not seem to tell me which color it was changed to, and changed from. Is there any way to receive that information through this process we were discussing? Or does this method do that already but I messed up somewhere?
Might have something to do with this, but I can't seem to make it work.
Thank you very much.
Re: Reacting to document modifications
getPropertyChanges returns an array. You can iterate through that array using a for loop.
As you can see in the API doc, each item in the array is of type RPropertyChange.
Please click the above link to see how you can extract the ID of the property that was changed, the new value, the old value, etc.
Parsing strings to fetch information is certainly not the recommended way to retrieve any information from entities, document, transactions, etc. These output strings you are using are meant for debugging only and can change significantly in any future update which means your code will break.
As you can see in the API doc, each item in the array is of type RPropertyChange.
Please click the above link to see how you can extract the ID of the property that was changed, the new value, the old value, etc.
Parsing strings to fetch information is certainly not the recommended way to retrieve any information from entities, document, transactions, etc. These output strings you are using are meant for debugging only and can change significantly in any future update which means your code will break.
-
- Full Member
- Posts: 58
- Joined: Wed Mar 16, 2016 5:10 pm
Re: Reacting to document modifications
Thank you for the heads up.andrew wrote:Parsing strings to fetch information is certainly not the recommended way to retrieve any information from entities, document, transactions, etc. These output strings you are using are meant for debugging only and can change significantly in any future update which means your code will break.
I tried applying the RPropertyChange method, as you said and came up with a few problems (probably doing something stupid, as usual). This is what I have tried:
vl_objIds = vl_changes.getAffectedObjects(); vl_change_list = vl_changes.getPropertyChanges(vl_objIds); test1 = vl_change_list.getNewValue(); test2 = vl_change_list.getOldValue(); test3 = vl_change_list.getPropertyTypeId();
Give an error, saying that getNewValue[undefined] is not a function. So I have obviously messed up in this one.
vl_objIds = vl_changes.getAffectedObjects(); vl_change_list = vl_changes.getPropertyChanges(vl_objIds); test1 = vl_change_list.getNewValue; test2 = vl_change_list.getOldValue; test3 = vl_change_list.getPropertyTypeId;
The first thing that I find odd is that vl_changes.getPropertyChanges(vl_objIds) returns: RPropertyChange(RPropertyTypeId(9, "", "", "", "Color") , QVariant(RColor, ) -> QVariant(RColor, )). The QVariants that supposedly holds the color seems to be empty. Then, the test1 to 3 that I placed return empty.
Then I tried to use the vl_change_list as an array.
vl_objIds = vl_changes.getAffectedObjects(); vl_change_list = vl_changes.getPropertyChanges(vl_objIds); test1 = vl_change_list[0].getNewValue; test2 = vl_change_list[0].getOldValue; test3 = vl_change_list[0].getPropertyTypeId;
all 3 test variables return: function () { [native code] }. which I have to say I have absolutely no idea what it means.
I apreciate any assistance.
thank you very much.
Re: Reacting to document modifications
Ghost_of_Magellan wrote:Then I tried to use the vl_change_list as an array.vl_objIds = vl_changes.getAffectedObjects(); vl_change_list = vl_changes.getPropertyChanges(vl_objIds); test1 = vl_change_list[0].getNewValue; test2 = vl_change_list[0].getOldValue; test3 = vl_change_list[0].getPropertyTypeId;
all 3 test variables return: function () { [native code] }. which I have to say I have absolutely no idea what it means.
This was pretty close. Try test1 = vl_change_list[0].getNewValue(); Note the ().