Interaktiva scripthandlingar
Introduktion
Section titled “Introduktion”Scripthandlingar är scripts som lägger till en post i en meny och/eller verktygsfält och som kan hantera användarinteraktioner. Scripthandlingar förblir aktiva tills de avslutas av användaren eller tills de själva avslutas.
Händelser
Section titled “Händelser”Så snart scripthandlingen startas hanterar den olika händelser tills den avslutas. En händelse är något som inträffar om något händer. Till exempel, om scripthandlingen startas anropas beginEvent. Om användaren klickar på ett objekt utlöses en pickEntity-händelse, om användaren klickar på en koordinat inträffar en pickCoordinate-händelse osv.
Den minimala strukturen för en scripthandling är följande:
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"]);};Detta exempelscript lägger till en meny längst ner i menyn Diverse > Exempel. Menytexten är “Minimal Example”.
Observera att för att scriptet ska hittas måste filnamnet matcha klassnamnet, dvs. “ExMyMinimal.js” i detta fall. Det måste också ligga i en mapp med samma namn “ExMyMinimal”, så detta script kan till exempel placeras i scripts/Misc/ExMyMinimal/ExMyMinimal.js.
Du kan även lägga dina skript i en lokal scripts-mapp i din användarmapp. För att ta reda på den exakta mappen öppnar du Om-dialogrutan (Hjälp > Om QCAD…) och går till fliken System. Där ser du dataplatsen under Data directory. Detta är katalogen under vilken du måste skapa en undermapp som heter scripts och i den undermappar, en mapp per skriptverktyg, till exempel /sökväg/till/datakatalog/scripts/MyScripts/MyScript1/MyScript1.js
Den exakta platsen beror på ditt system och dess konfiguration.
Lägga till beginEvent
Section titled “Lägga till beginEvent”Scriptet ovan är fullt funktionellt och kan utlösas. Det gör dock inte faktiskt något när det utlöses. Dessutom, när det väl har utlösts, förblir scriptet aktivt tills användaren avslutar det genom att klicka på höger musknapp. För att ändra detta, låt oss implementera beginEvent för att skriva ut något till kommandoradshistoriken i QCAD och avsluta 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"]);};Om verktyget Diverse > Exempel > Minimal Example nu startas skriver det ut “Hello World!” till kommandoradshistoriken (rad 12) och avslutas sedan (rad 14).
Om ett script inte kräver någon användarinteraktion kan ett sådant script användas för att lägga till en meny som gör något och sedan avslutas. Exempel på sådana handlingar är Visa > Autozoom, Markera > Markera allt, Redigera > Ta bort osv.
Lägga till interaktion
Section titled “Lägga till interaktion”Så snart ett script kräver någon form av användarinteraktion måste vi implementera fler händelsehanterare och tala om för scriptet vad användaren behöver göra härnäst (t.ex. välja ett objekt eller definiera en koordinat). I nästa steg går vi in i ett tillstånd där handlingen förväntar sig en koordinat från användaren. Vi ritar sedan en cirkel vid varje position som användaren klickar på eller anger.
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 avslutar vi inte längre handlingen omedelbart, utan låter den köra tills användaren avslutar den (högerklick eller Escape). Vi implementerar sedan pickCoordinate för att lagra positionen för muspekaren eller den angivna koordinaten och för att antingen uppdatera förhandsgranskningen eller tillämpa operationen (dvs. lägga till cirkeln). pickCoordinate anropas varje gång användaren flyttar musen för att visa en förhandsgranskning av den planerade operationen. När användaren klickar eller anger en koordinat anropas den med parametern preview satt till false för att indikera att en definitiv koordinat har valts eller angetts.
updatePreview på rad 22 förhandsgranskar operationen som returneras av getOperation, medan applyOperation på rad 25 faktiskt tillämpar operationen på vårt dokument.
getOperation måste implementeras för att returnera operationen som ska förhandsgranskas eller tillämpas på dokumentet. Detta är något mer komplext än det vi har sett i det enkla API:et ovan. Detta beror på att en enda operation kan användas för att lägga till flera objekt, ändra objekt eller ta bort objekt.
Lägga till widgetar i alternativverktygsfältet
Section titled “Lägga till widgetar i alternativverktygsfältet”Cirkeln som ritas i vårt exempel har alltid en radie på 1 ritenhet (se rad 33). I ett nästa steg vill vi låta användaren ange en radie för cirkeln. QCAD använder vanligtvis alternativverktygsfältet högst upp för att visa och ändra sådana verktygsparametrar. För detta måste vi definiera vilka widgetar vi vill visa i alternativverktygsfältet och vilka parametrar de styr. Detta kan göras med en UI-fil, en XML-fil som definierar en widget och dess innehåll. UI-filer kan bekvämt utformas med hjälp av en programvara som heter Qt Designer, som ingår som en del av Qt-verktygssatsen. För detta exempel använder vi en enkel UI-fil som också kan skapas i en textredigerare (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 definierar två widgetar: en etikett (QLabel) och ett radredigeringsfält (RMathLineEdit). Viktigt är namnet på radredigeringsfältet (“Radius”). Widgeten länkas automatiskt till vårt script genom detta namn. Allt vi behöver göra i vårt script är att definiera vilken UI-fil vi vill använda (rad 9) och att implementera en ny händelsehanterare som heter slotRadiusChanged, det vill säga “slot” + [namnet på vårt radredigeringsfält] + “Changed” (rad 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"]);};Denna nya funktion slotRadiusChanged anropas varje gång användaren anger en ny radie. Den sätter medlemsvariabeln this.radius som i sin tur används när cirkeln skapas i getOperation.
Alla scripts i QCAD är baserade på ett av dessa koncept som beskrivs i denna handledning.
Eftersom varje verktyg i QCAD är implementerat som ett script på toppnivå finns det gott om exempelscripts tillgängliga. Du kan hitta dem i vårt git-repository.