Các hành động tập lệnh tương tác
Giới thiệu
Section titled “Giới thiệu”Các hành động tập lệnh là các tập lệnh thêm một mục vào menu và/hoặc thanh công cụ và có thể xử lý các tương tác của người dùng. Các hành động tập lệnh vẫn hoạt động cho đến khi bị người dùng chấm dứt hoặc cho đến khi chúng tự chấm dứt.
Sự kiện
Section titled “Sự kiện”Ngay khi hành động tập lệnh được khởi động, nó xử lý các sự kiện khác nhau cho đến khi bị chấm dứt. Sự kiện là điều gì đó xảy ra nếu có điều gì đó đang diễn ra. Ví dụ, nếu hành động tập lệnh được khởi động, beginEvent được gọi. Nếu người dùng nhấp vào một đối tượng, một sự kiện pickEntity được kích hoạt, nếu người dùng nhấp vào một tọa độ, một sự kiện pickCoordinate xảy ra, v.v.
Cấu trúc tối thiểu của một hành động tập lệnh như sau:
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"]);};Tập lệnh ví dụ này thêm một menu vào cuối menu Khác > Ví dụ. Văn bản menu là “Minimal Example”.
Lưu ý rằng để tìm thấy tập lệnh, tên tệp cần khớp với tên lớp, tức là “ExMyMinimal.js” trong trường hợp này. Nó cũng cần nằm trong một thư mục có cùng tên “ExMyMinimal”, vì vậy tập lệnh này ví dụ có thể được đặt vào scripts/Misc/ExMyMinimal/ExMyMinimal.js.
Bạn cũng có thể đặt các kịch bản của mình vào thư mục scripts cục bộ trong thư mục người dùng của bạn. Để biết thư mục chính xác, hãy mở hộp thoại giới thiệu (Trợ giúp > Giới thiệu QCAD…) và chuyển đến thẻ Hệ thống. Ở đó bạn có thể thấy vị trí dữ liệu tại Data directory. Đây là thư mục mà bên dưới nó bạn phải tạo một thư mục con tên là scripts và các thư mục con bên trong, mỗi công cụ kịch bản một thư mục, ví dụ /đường dẫn/đến/thư mục dữ liệu/scripts/MyScripts/MyScript1/MyScript1.js
Vị trí chính xác phụ thuộc vào hệ thống và cấu hình của bạn.
Thêm beginEvent
Section titled “Thêm beginEvent”Tập lệnh trên hoàn toàn hoạt động và có thể được kích hoạt. Tuy nhiên, nó thực sự không làm gì khi được kích hoạt. Hơn nữa, một khi được kích hoạt, tập lệnh vẫn hoạt động cho đến khi người dùng chấm dứt nó bằng cách nhấp chuột phải. Để thay đổi điều này, hãy triển khai beginEvent để in một cái gì đó vào lịch sử dòng lệnh của QCAD và chấm dứt hành động:
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"]);};Nếu công cụ Khác > Ví dụ > Minimal Example bây giờ được khởi động, nó in “Hello World!” vào lịch sử dòng lệnh (dòng 12) rồi chấm dứt (dòng 14).
Nếu một tập lệnh không yêu cầu bất kỳ tương tác nào của người dùng, một tập lệnh như vậy có thể được sử dụng để thêm một menu làm điều gì đó rồi chấm dứt. Ví dụ về các hành động như vậy là Xem > Thu phóng tự động, Chọn > Chọn tất cả, Chỉnh sửa > Xóa, v.v.
Thêm tương tác
Section titled “Thêm tương tác”Ngay khi một tập lệnh yêu cầu bất kỳ loại tương tác nào của người dùng, chúng ta cần triển khai thêm các trình xử lý sự kiện và cho tập lệnh biết người dùng cần làm gì tiếp theo (ví dụ: chọn một đối tượng hoặc xác định một tọa độ). Trong bước tiếp theo, chúng ta vào một trạng thái mà hành động mong đợi một tọa độ từ người dùng. Sau đó chúng ta vẽ một đường tròn tại mỗi vị trí mà người dùng nhấp hoặc nhập.
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"]);};Trong beginEvent, chúng ta không còn chấm dứt hành động ngay lập tức nữa, mà để nó chạy cho đến khi người dùng chấm dứt (nhấp chuột phải hoặc Escape). Sau đó chúng ta triển khai pickCoordinate để lưu trữ vị trí của con trỏ chuột hoặc tọa độ đã nhập và hoặc cập nhật bản xem trước hoặc áp dụng thao tác (tức là thêm đường tròn). pickCoordinate được gọi bất cứ khi nào người dùng di chuyển chuột để hiển thị bản xem trước của thao tác đã lên kế hoạch. Khi người dùng nhấp hoặc nhập một tọa độ, nó được gọi với tham số preview đặt thành false để cho biết rằng một tọa độ dứt khoát đã được chọn hoặc nhập.
updatePreview ở dòng 22 xem trước thao tác được getOperation trả về, trong khi applyOperation ở dòng 25 thực sự áp dụng thao tác vào tài liệu của chúng ta.
getOperation phải được triển khai để trả về thao tác cần xem trước hoặc áp dụng vào tài liệu. Điều này phức tạp hơn một chút so với những gì chúng ta đã thấy trong API đơn giản ở trên. Đó là vì một thao tác duy nhất có thể được sử dụng để thêm nhiều đối tượng, sửa đổi đối tượng hoặc xóa đối tượng.
Thêm widget vào thanh công cụ tùy chọn
Section titled “Thêm widget vào thanh công cụ tùy chọn”Đường tròn được vẽ trong ví dụ của chúng ta luôn có bán kính 1 đơn vị bản vẽ (xem dòng 33). Ở một bước tiếp theo, chúng ta muốn cho phép người dùng nhập bán kính cho đường tròn. QCAD thường sử dụng thanh công cụ tùy chọn ở trên cùng để hiển thị và thay đổi các tham số công cụ như vậy. Đối với điều này, chúng ta cần xác định những widget nào chúng ta muốn hiển thị trong thanh công cụ tùy chọn và chúng điều khiển những tham số nào. Điều này có thể được thực hiện bằng một tệp UI, một tệp XML xác định một widget và nội dung của nó. Các tệp UI có thể được thiết kế thuận tiện bằng một phần mềm gọi là Qt Designer đi kèm như một phần của bộ công cụ Qt. Đối với ví dụ này, chúng ta sử dụng một tệp UI đơn giản cũng có thể được tạo trong trình soạn thảo văn bản (tệp 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>Tệp UI xác định hai widget: một nhãn (QLabel) và một ô chỉnh sửa dòng (RMathLineEdit). Quan trọng là tên của ô chỉnh sửa dòng (“Radius”). Widget được tự động liên kết với tập lệnh của chúng ta thông qua tên này. Tất cả những gì chúng ta phải làm trong tập lệnh của mình là xác định tệp UI nào chúng ta muốn sử dụng (dòng 9) và triển khai một trình xử lý sự kiện mới gọi là slotRadiusChanged, tức là “slot” + [tên của ô chỉnh sửa dòng của chúng ta] + “Changed” (dòng 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"]);};Hàm mới slotRadiusChanged này được gọi bất cứ khi nào người dùng nhập một bán kính mới. Nó đặt biến thành viên this.radius, biến này lần lượt được sử dụng khi tạo đường tròn trong getOperation.
Tất cả các tập lệnh trong QCAD đều dựa trên một trong những khái niệm được trình bày trong hướng dẫn này.
Vì mọi công cụ trong QCAD được triển khai dưới dạng tập lệnh ở cấp cao nhất, có rất nhiều tập lệnh ví dụ có sẵn. Bạn có thể tìm thấy chúng trong kho lưu trữ git của chúng tôi.