การกระทำสคริปต์แบบโต้ตอบ
การกระทำสคริปต์ (script action) คือสคริปต์ที่เพิ่มรายการลงในเมนูและ/หรือแถบเครื่องมือ และสามารถจัดการการโต้ตอบกับผู้ใช้ได้ การกระทำสคริปต์จะยังคงทำงานอยู่จนกว่าผู้ใช้จะยุติหรือจนกว่ามันจะยุติตัวเอง
เหตุการณ์
Section titled “เหตุการณ์”ทันทีที่การกระทำสคริปต์เริ่มทำงาน มันจะจัดการเหตุการณ์ต่าง ๆ จนกว่าจะถูกยุติ เหตุการณ์ (event) คือสิ่งที่เกิดขึ้นเมื่อมีอะไรบางอย่างเกิดขึ้น ตัวอย่างเช่น หากการกระทำสคริปต์เริ่มทำงาน 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)
หากสคริปต์ไม่ต้องการการโต้ตอบใด ๆ จากผู้ใช้ สคริปต์ดังกล่าวสามารถใช้เพิ่มเมนูที่ทำบางอย่างแล้วยุติได้ ตัวอย่างของการกระทำเช่นนี้ ได้แก่ มุมมอง > Auto Zoom, เลือก > เลือกทั้งหมด, แก้ไข > ลบ เป็นต้น
การเพิ่มการโต้ตอบ
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 ต้องถูกทำเพื่อส่งคืนการดำเนินการที่จะแสดงตัวอย่างหรือใช้กับเอกสาร ซึ่งซับซ้อนกว่าที่เราเห็นใน Simple 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 ของเรา