Διαδραστικές ενέργειες σεναρίου
Εισαγωγή
Ενότητα με τίτλο «Εισαγωγή»Οι ενέργειες σεναρίου είναι σενάρια που προσθέτουν μια καταχώρηση σε ένα μενού και/ή γραμμή εργαλείων και που μπορούν να χειριστούν αλληλεπιδράσεις με τον χρήστη. Οι ενέργειες σεναρίου παραμένουν ενεργές μέχρι να τερματιστούν από τον χρήστη ή μέχρι να αυτοτερματιστούν.
Συμβάντα
Ενότητα με τίτλο «Συμβάντα»Μόλις ξεκινήσει η ενέργεια σεναρίου, χειρίζεται διάφορα συμβάντα μέχρι να τερματιστεί. Ένα συμβάν είναι κάτι που προκύπτει αν κάτι συμβαίνει. Για παράδειγμα, αν ξεκινήσει η ενέργεια σεναρίου, καλείται η beginEvent. Αν ο χρήστης κάνει κλικ σε μια οντότητα, ενεργοποιείται ένα συμβάν pickEntity, αν ο χρήστης κάνει κλικ σε μια συντεταγμένη, προκύπτει ένα συμβάν pickCoordinate κ.λπ.
Η ελάχιστη δομή μιας ενέργειας σεναρίου είναι η εξής:
include("scripts/EAction.js");
function ExMyMinimal(guiAction) { EAction.call(this, guiAction);}
ExMyMinimal.prototype = new EAction();
ExMyMinimal.init = function(basePath) { var action = new RGuiAction(qsTr("&Minimal Example"), RMainWindowQt.getMainWindow()); action.setRequiresDocument(true); action.setScriptFile(basePath + "/ExMyMinimal.js"); action.setGroupSortOrder(100000); action.setSortOrder(0); action.setWidgetNames(["ExamplesMenu"]);};Αυτό το παράδειγμα σεναρίου προσθέτει ένα μενού στο κάτω μέρος του μενού Διάφορα > Παραδείγματα. Το κείμενο του μενού είναι “Minimal Example”.
Σημειώστε ότι για να βρεθεί το σενάριο, το όνομα του αρχείου πρέπει να ταιριάζει με το όνομα της κλάσης, δηλ. “ExMyMinimal.js” σε αυτήν την περίπτωση. Πρέπει επίσης να βρίσκεται μέσα σε έναν κατάλογο με το ίδιο όνομα “ExMyMinimal”, οπότε αυτό το σενάριο μπορεί για παράδειγμα να τοποθετηθεί στο scripts/Misc/ExMyMinimal/ExMyMinimal.js.
Μπορείτε επίσης να τοποθετήσετε τα σενάριά σας σε έναν τοπικό φάκελο scripts μέσα στον προσωπικό σας φάκελο χρήστη. Για να βρείτε τον ακριβή φάκελο, ανοίξτε το παράθυρο διαλόγου «Σχετικά» (Βοήθεια > Σχετικά με το QCAD…) και μεταβείτε στην καρτέλα Σύστημα. Εκεί μπορείτε να δείτε την τοποθεσία των δεδομένων στο Data directory. Αυτός είναι ο κατάλογος μέσα στον οποίο πρέπει να δημιουργήσετε έναν υποφάκελο με το όνομα scripts και μέσα σε αυτόν υποφακέλους, έναν φάκελο για κάθε εργαλείο σεναρίου, για παράδειγμα /διαδρομή/προς/τον κατάλογο δεδομένων/scripts/MyScripts/MyScript1/MyScript1.js
Η ακριβής τοποθεσία εξαρτάται από το σύστημά σας και τη διαμόρφωσή του.
Προσθήκη beginEvent
Ενότητα με τίτλο «Προσθήκη beginEvent»Το παραπάνω σενάριο είναι πλήρως λειτουργικό και μπορεί να ενεργοποιηθεί. Ωστόσο, δεν κάνει στην πραγματικότητα τίποτα όταν ενεργοποιείται. Επιπλέον, μόλις ενεργοποιηθεί, το σενάριο παραμένει ενεργό μέχρι ο χρήστης να το τερματίσει κάνοντας κλικ στο δεξί κουμπί του ποντικιού. Για να το αλλάξουμε αυτό, ας υλοποιήσουμε την beginEvent ώστε να εκτυπώσει κάτι στο ιστορικό γραμμής εντολών του QCAD και να τερματίσει την ενέργεια:
include("scripts/EAction.js");
function ExMyMinimal(guiAction) { EAction.call(this, guiAction);}
ExMyMinimal.prototype = new EAction();
ExMyMinimal.prototype.beginEvent = function() { EAction.prototype.beginEvent.call(this);
EAction.handleUserMessage("Hello World!");
this.terminate();};
ExMyMinimal.init = function(basePath) { var action = new RGuiAction(qsTr("&Minimal Example"), RMainWindowQt.getMainWindow()); action.setRequiresDocument(true); action.setScriptFile(basePath + "/ExMyMinimal.js"); action.setGroupSortOrder(100000); action.setSortOrder(0); action.setWidgetNames(["ExamplesMenu"]);};Αν το εργαλείο Διάφορα > Παραδείγματα > Minimal Example ξεκινήσει τώρα, εκτυπώνει “Hello World!” στο ιστορικό γραμμής εντολών (γραμμή 12) και στη συνέχεια τερματίζεται (γραμμή 14).
Αν ένα σενάριο δεν απαιτεί καμία αλληλεπίδραση με τον χρήστη, ένα τέτοιο σενάριο μπορεί να χρησιμοποιηθεί για να προσθέσει ένα μενού που κάνει κάτι και στη συνέχεια τερματίζεται. Παραδείγματα τέτοιων ενεργειών είναι Προβολή > Αυτόματη εστίαση, Επιλογή > Επιλογή όλων, Επεξεργασία > Διαγραφή κ.λπ.
Προσθήκη αλληλεπίδρασης
Ενότητα με τίτλο «Προσθήκη αλληλεπίδρασης»Μόλις ένα σενάριο απαιτεί οποιονδήποτε τύπο αλληλεπίδρασης με τον χρήστη, πρέπει να υλοποιήσουμε περισσότερους χειριστές συμβάντων και να πούμε στο σενάριο τι πρέπει να κάνει ο χρήστης στη συνέχεια (π.χ. επιλογή μιας οντότητας ή ορισμός μιας συντεταγμένης). Στο επόμενο βήμα, εισερχόμαστε σε μια κατάσταση στην οποία η ενέργεια αναμένει μια συντεταγμένη από τον χρήστη. Στη συνέχεια σχεδιάζουμε έναν κύκλο σε κάθε θέση όπου ο χρήστης κάνει κλικ ή εισάγει.
include("scripts/EAction.js");
function ExMyMinimal(guiAction) { EAction.call(this, guiAction);
this.pos = undefined;}
ExMyMinimal.prototype = new EAction();
ExMyMinimal.prototype.beginEvent = function() { EAction.prototype.beginEvent.call(this);
var di = this.getDocumentInterface(); di.setClickMode(RAction.PickCoordinate);};
ExMyMinimal.prototype.pickCoordinate = function(event, preview) { this.pos = event.getModelPosition();
if (preview) { this.updatePreview(); } else { this.applyOperation(); }};
ExMyMinimal.prototype.getOperation = function(preview) { var doc = this.getDocument();
var op = new RAddObjectOperation(); var circle = new RCircle(this.pos, 1); op.addObject(shapeToEntity(doc, circle)); return op;};
ExMyMinimal.init = function(basePath) { var action = new RGuiAction(qsTr("&Minimal Example"), RMainWindowQt.getMainWindow()); action.setRequiresDocument(true); action.setScriptFile(basePath + "/ExMyMinimal.js"); action.setGroupSortOrder(100000); action.setSortOrder(0); action.setWidgetNames(["ExamplesMenu"]);};Στην beginEvent, δεν τερματίζουμε πλέον την ενέργεια αμέσως, αλλά την αφήνουμε να εκτελείται μέχρι ο χρήστης να την τερματίσει (δεξί κλικ ή Escape). Στη συνέχεια υλοποιούμε την pickCoordinate για να αποθηκεύσουμε τη θέση του δρομέα του ποντικιού ή τη συντεταγμένη που εισήχθη και είτε να ενημερώσουμε την προεπισκόπηση είτε να εφαρμόσουμε τη λειτουργία (δηλ. να προσθέσουμε τον κύκλο). Η pickCoordinate καλείται κάθε φορά που ο χρήστης μετακινεί το ποντίκι για να εμφανιστεί μια προεπισκόπηση της σχεδιαζόμενης λειτουργίας. Όταν ο χρήστης κάνει κλικ ή εισάγει μια συντεταγμένη, καλείται με την παράμετρο preview ορισμένη σε false για να υποδείξει ότι έχει επιλεγεί ή εισαχθεί μια οριστική συντεταγμένη.
Η updatePreview στη γραμμή 22 προεπισκοπεί τη λειτουργία που επιστρέφεται από την getOperation, ενώ η applyOperation στη γραμμή 25 εφαρμόζει πραγματικά τη λειτουργία στο έγγραφό μας.
Η getOperation πρέπει να υλοποιηθεί ώστε να επιστρέφει τη λειτουργία προς προεπισκόπηση ή εφαρμογή στο έγγραφο. Αυτό είναι ελαφρώς πιο σύνθετο από αυτό που είδαμε στο απλό API παραπάνω. Αυτό συμβαίνει επειδή μια μεμονωμένη λειτουργία μπορεί να χρησιμοποιηθεί για την προσθήκη πολλαπλών αντικειμένων, την τροποποίηση αντικειμένων ή τη διαγραφή αντικειμένων.
Προσθήκη γραφικών στοιχείων στη γραμμή εργαλείων επιλογών
Ενότητα με τίτλο «Προσθήκη γραφικών στοιχείων στη γραμμή εργαλείων επιλογών»Ο κύκλος που σχεδιάστηκε στο παράδειγμά μας έχει πάντα ακτίνα 1 μονάδας σχεδίασης (δείτε τη γραμμή 33). Σε ένα επόμενο βήμα, θέλουμε να επιτρέψουμε στον χρήστη να εισαγάγει μια ακτίνα για τον κύκλο. Το QCAD χρησιμοποιεί συνήθως τη γραμμή εργαλείων επιλογών στο επάνω μέρος για να εμφανίζει και να αλλάζει τέτοιες παραμέτρους εργαλείου. Για αυτό, πρέπει να ορίσουμε ποια γραφικά στοιχεία θέλουμε να εμφανίσουμε στη γραμμή εργαλείων επιλογών και ποιες παραμέτρους ελέγχουν. Αυτό μπορεί να γίνει με ένα αρχείο UI, ένα αρχείο XML που ορίζει ένα γραφικό στοιχείο και τα περιεχόμενά του. Τα αρχεία UI μπορούν να σχεδιαστούν άνετα χρησιμοποιώντας ένα λογισμικό που ονομάζεται Qt Designer, το οποίο έρχεται ως μέρος της εργαλειοθήκης Qt. Για αυτό το παράδειγμα, χρησιμοποιούμε ένα απλό αρχείο UI που μπορεί επίσης να δημιουργηθεί σε έναν επεξεργαστή κειμένου (αρχείο ExMyMinimal.ui):
<?xml version="1.0" encoding="UTF-8"?><ui version="4.0"> <class>ExMyMinimal</class> <widget class="QWidget" name="ExMyMinimal"> <layout class="QHBoxLayout"> <item> <widget class="QLabel" name="RadiusLabel"> <property name="text"> <string>&Radius:</string> </property> <property name="buddy"> <cstring>Radius</cstring> </property> </widget> </item> <item> <widget class="RMathLineEdit" name="Radius"> <property name="text"> <string notr="true">1</string> </property> </widget> </item> </layout> </widget> <customwidgets> <customwidget> <class>RMathLineEdit</class> <extends>QLineEdit</extends> <header>RMathLineEdit.h</header> </customwidget> </customwidgets> <resources/> <connections/></ui>Το αρχείο UI ορίζει δύο γραφικά στοιχεία: μια ετικέτα (QLabel) και ένα πεδίο επεξεργασίας γραμμής (RMathLineEdit). Σημαντικό είναι το όνομα του πεδίου επεξεργασίας γραμμής (“Radius”). Το γραφικό στοιχείο συνδέεται αυτόματα με το σενάριό μας μέσω αυτού του ονόματος. Το μόνο που πρέπει να κάνουμε στο σενάριό μας είναι να ορίσουμε ποιο αρχείο UI θέλουμε να χρησιμοποιήσουμε (γραμμή 9) και να υλοποιήσουμε έναν νέο χειριστή συμβάντων που ονομάζεται slotRadiusChanged, δηλαδή “slot” + [το όνομα του πεδίου επεξεργασίας γραμμής μας] + “Changed” (γραμμή 45):
include("scripts/EAction.js");
function ExMyMinimal(guiAction) { EAction.call(this, guiAction);
this.pos = undefined; this.radius = undefined;
this.setUiOptions("ExMyMinimal.ui");}
ExMyMinimal.prototype = new EAction();
ExMyMinimal.prototype.beginEvent = function() { EAction.prototype.beginEvent.call(this);
var di = this.getDocumentInterface(); di.setClickMode(RAction.PickCoordinate);};
ExMyMinimal.prototype.pickCoordinate = function(event, preview) { this.pos = event.getModelPosition();
if (preview) { this.updatePreview(); } else { this.applyOperation(); }};
ExMyMinimal.prototype.getOperation = function(preview) { if (isNull(this.pos) || isNull(this.radius)) { return undefined; }
var doc = this.getDocument();
var op = new RAddObjectOperation(); var circle = new RCircle(this.pos, this.radius); op.addObject(shapeToEntity(doc, circle)); return op;};
ExMyMinimal.prototype.slotRadiusChanged = function(v) { this.radius = v; this.updatePreview();};
ExMyMinimal.init = function(basePath) { var action = new RGuiAction(qsTr("&Minimal Example"), RMainWindowQt.getMainWindow()); action.setRequiresDocument(true); action.setScriptFile(basePath + "/ExMyMinimal.js"); action.setGroupSortOrder(100000); action.setSortOrder(0); action.setWidgetNames(["ExamplesMenu"]);};Αυτή η νέα συνάρτηση slotRadiusChanged καλείται κάθε φορά που ο χρήστης εισάγει μια νέα ακτίνα. Ορίζει τη μεταβλητή μέλους this.radius, η οποία με τη σειρά της χρησιμοποιείται κατά τη δημιουργία του κύκλου στην getOperation.
Όλα τα σενάρια στο QCAD βασίζονται σε μία από αυτές τις έννοιες που περιγράφονται σε αυτό το σεμινάριο.
Δεδομένου ότι κάθε εργαλείο στο QCAD υλοποιείται ως σενάριο στο ανώτατο επίπεδο, υπάρχουν πολλά διαθέσιμα παραδείγματα σεναρίων. Μπορείτε να τα βρείτε στο αποθετήριο git μας.