Интерактивни скриптови действия
Въведение
Section titled “Въведение”Скриптовите действия са скриптове, които добавят елемент към меню и/или лента с инструменти и които могат да обработват потребителски взаимодействия. Скриптовите действия остават активни, докато не бъдат прекратени от потребителя или докато не се самопрекратят.
Събития
Section titled “Събития”Веднага щом скриптовото действие бъде стартирано, то обработва различни събития, докато не бъде прекратено. Събитие е нещо, което възниква, ако нещо се случва. Например, ако скриптовото действие бъде стартирано, се извиква 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
Section titled “Добавяне на 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).
Ако скрипт не изисква никакво потребителско взаимодействие, такъв скрипт може да се използва за добавяне на меню, което прави нещо и след това се прекратява. Примери за такива действия са Изглед > Авт. мащаб, Избор > Избери всичко, Редактиране > Изтрий и т.н.
Добавяне на взаимодействие
Section titled “Добавяне на взаимодействие”Веднага щом даден скрипт изисква какъвто и да е вид потребителско взаимодействие, трябва да реализираме повече манипулатори на събития и да кажем на скрипта какво трябва да направи потребителят след това (напр. избор на обект или дефиниране на координата). В следващата стъпка влизаме в състояние, в което действието очаква координата от потребителя. След това чертаем окръжност на всяка позиция, върху която потребителят щракне или която въведе.
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 по-горе. Това е така, защото една операция може да се използва за добавяне на множество обекти, промяна на обекти или изтриване на обекти.
Добавяне на джаджи към лентата с опции
Section titled “Добавяне на джаджи към лентата с опции”Окръжността, начертана в нашия пример, винаги има радиус от 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 хранилище.