Interaktive scripthandlinger
Innledning
Section titled “Innledning”Scripthandlinger er scripts som legger til en oppføring i en meny og/eller verktøylinje, og som kan håndtere brukerinteraksjoner. Scripthandlinger forblir aktive til de avsluttes av brukeren eller til de selv avslutter.
Hendelser
Section titled “Hendelser”Så snart scripthandlingen startes, håndterer den ulike hendelser til den avsluttes. En hendelse er noe som oppstår hvis noe skjer. For eksempel, hvis scripthandlingen startes, kalles beginEvent. Hvis brukeren klikker på et objekt, utløses en pickEntity-hendelse, hvis brukeren klikker på en koordinat, oppstår en pickCoordinate-hendelse osv.
Den minimale strukturen til en scripthandling er som følger:
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"]);};Dette eksempelscriptet legger til en meny nederst i menyen Diverse > Eksempler. Menyteksten er “Minimal Example”.
Merk at for at scriptet skal finnes, må filnavnet samsvare med klassenavnet, dvs. “ExMyMinimal.js” i dette tilfellet. Det må også ligge i en mappe med samme navn “ExMyMinimal”, så dette scriptet kan for eksempel plasseres i scripts/Misc/ExMyMinimal/ExMyMinimal.js.
Du kan også legge skriptene dine i en lokal scripts-mappe i hjemmemappen din. For å finne den nøyaktige mappen åpner du Om-dialogen (Hjelp > Om QCAD…) og går til fanen System. Der ser du dataplasseringen under Data directory. Dette er katalogen der du må opprette en undermappe som heter scripts, og i den undermapper, én mappe per skriptverktøy, for eksempel /sti/til/datakatalog/scripts/MyScripts/MyScript1/MyScript1.js
Den nøyaktige plasseringen avhenger av systemet ditt og konfigurasjonen av det.
Legge til beginEvent
Section titled “Legge til beginEvent”Scriptet ovenfor er fullt funksjonelt og kan utløses. Det gjør imidlertid ikke noe når det utløses. Dessuten, når det først er utløst, forblir scriptet aktivt til brukeren avslutter det ved å klikke på høyre museknapp. For å endre dette, la oss implementere beginEvent til å skrive ut noe til kommandolinjehistorikken i QCAD og avslutte handlingen:
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"]);};Hvis verktøyet Diverse > Eksempler > Minimal Example nå startes, skriver det ut “Hello World!” til kommandolinjehistorikken (linje 12) og avslutter deretter (linje 14).
Hvis et script ikke krever noen brukerinteraksjon, kan et slikt script brukes til å legge til en meny som gjør noe og deretter avslutter. Eksempler på slike handlinger er Vis > Autozoom, Velg > Velg alt, Rediger > Slett osv.
Legge til interaksjon
Section titled “Legge til interaksjon”Så snart et script krever noen form for brukerinteraksjon, må vi implementere flere hendelsesbehandlere og fortelle scriptet hva brukeren skal gjøre videre (f.eks. velge et objekt eller definere en koordinat). I neste trinn går vi inn i en tilstand der handlingen forventer en koordinat fra brukeren. Vi tegner deretter en sirkel på hver posisjon brukeren klikker på eller angir.
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"]);};I beginEvent avslutter vi ikke lenger handlingen umiddelbart, men lar den kjøre til brukeren avslutter den (høyreklikk eller Escape). Vi implementerer deretter pickCoordinate for å lagre posisjonen til musepekeren eller den angitte koordinaten og for enten å oppdatere forhåndsvisningen eller anvende operasjonen (dvs. legge til sirkelen). pickCoordinate kalles hver gang brukeren beveger musen for å vise en forhåndsvisning av den planlagte operasjonen. Når brukeren klikker eller angir en koordinat, kalles den med parameteren preview satt til false for å indikere at en endelig koordinat er valgt eller angitt.
updatePreview på linje 22 forhåndsviser operasjonen returnert av getOperation, mens applyOperation på linje 25 faktisk anvender operasjonen på dokumentet vårt.
getOperation må implementeres for å returnere operasjonen som skal forhåndsvises eller anvendes på dokumentet. Dette er litt mer komplekst enn det vi har sett i det enkle API-et ovenfor. Dette er fordi en enkelt operasjon kan brukes til å legge til flere objekter, endre objekter eller slette objekter.
Legge til widgeter i alternativverktøylinjen
Section titled “Legge til widgeter i alternativverktøylinjen”Sirkelen tegnet i eksempelet vårt har alltid en radius på 1 tegneenhet (se linje 33). I et neste trinn vil vi la brukeren angi en radius for sirkelen. QCAD bruker vanligvis alternativverktøylinjen øverst til å vise og endre slike verktøyparametere. For dette må vi definere hvilke widgeter vi vil vise i alternativverktøylinjen og hvilke parametere de styrer. Dette kan gjøres med en UI-fil, en XML-fil som definerer en widget og innholdet i den. UI-filer kan enkelt utformes ved hjelp av en programvare kalt Qt Designer, som følger med som en del av Qt-verktøysettet. For dette eksempelet bruker vi en enkel UI-fil som også kan opprettes i en teksteditor (fil 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-filen definerer to widgeter: en etikett (QLabel) og et linjeredigeringsfelt (RMathLineEdit). Viktig er navnet på linjeredigeringsfeltet (“Radius”). Widgeten kobles automatisk til scriptet vårt gjennom dette navnet. Alt vi må gjøre i scriptet vårt er å definere hvilken UI-fil vi vil bruke (linje 9), og å implementere en ny hendelsesbehandler kalt slotRadiusChanged, det vil si “slot” + [navnet på linjeredigeringsfeltet vårt] + “Changed” (linje 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"]);};Denne nye funksjonen slotRadiusChanged kalles hver gang brukeren angir en ny radius. Den setter medlemsvariabelen this.radius som i sin tur brukes når sirkelen opprettes i getOperation.
Alle scripts i QCAD er basert på ett av disse konseptene som er skissert i denne veiledningen.
Siden hvert verktøy i QCAD er implementert som et script på øverste nivå, finnes det mange eksempelscripts tilgjengelig. Du kan finne dem i git-repositoriet vårt.