콘텐츠로 이동

대화형 스크립트 액션

스크립트 액션은 메뉴 및/또는 도구 모음에 항목을 추가하고 사용자 상호작용을 처리할 수 있는 스크립트입니다. 스크립트 액션은 사용자가 종료하거나 스스로 종료할 때까지 활성 상태로 유지됩니다.

스크립트 액션이 시작되는 즉시 종료될 때까지 다양한 이벤트를 처리합니다. 이벤트는 무언가가 발생할 때 일어나는 것입니다. 예를 들어 스크립트 액션이 시작되면 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를 구현하여 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번째 줄).

스크립트가 사용자 상호작용을 요구하지 않는 경우, 이러한 스크립트를 사용하여 무언가를 수행한 다음 종료하는 메뉴를 추가할 수 있습니다. 이러한 액션의 예로는 보기 > 자동 확대/축소, 선택 > 모두 선택, 편집 > 삭제 등이 있습니다.

스크립트가 어떤 종류의 사용자 상호작용을 요구하는 즉시, 더 많은 이벤트 핸들러를 구현하고 사용자가 다음에 무엇을 해야 하는지(예: 엔티티 선택 또는 좌표 정의) 스크립트에 알려야 합니다. 다음 단계에서는 액션이 사용자로부터 좌표를 기대하는 상태로 들어갑니다. 그런 다음 사용자가 클릭하거나 입력하는 모든 위치에 원을 그립니다.

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로 설정하여 호출됩니다.

22번째 줄의 updatePreview는 getOperation이 반환한 작업을 미리 봅니다. 반면 25번째 줄의 applyOperation은 실제로 작업을 문서에 적용합니다.

getOperation은 문서에서 미리 보거나 적용할 작업을 반환하도록 구현해야 합니다. 이는 위의 간단한 API에서 본 것보다 약간 더 복잡합니다. 이는 단일 작업이 여러 객체를 추가하거나 객체를 수정하거나 객체를 삭제하는 데 사용될 수 있기 때문입니다.

옵션 도구 모음에 위젯 추가하기

섹션 제목: “옵션 도구 모음에 위젯 추가하기”

예제에서 그린 원은 항상 1 도면 단위의 반지름을 갖습니다(33번째 줄 참조). 다음 단계에서는 사용자가 원의 반지름을 입력할 수 있게 하고자 합니다. QCAD는 일반적으로 이러한 도구 매개변수를 표시하고 변경하기 위해 상단의 옵션 도구 모음을 사용합니다. 이를 위해 옵션 도구 모음에 표시할 위젯과 이들이 제어하는 매개변수를 정의해야 합니다. 이는 위젯과 그 내용을 정의하는 XML 파일인 UI 파일로 수행할 수 있습니다. UI 파일은 Qt 도구 키트의 일부로 제공되는 Qt Designer라는 소프트웨어를 사용하여 편리하게 디자인할 수 있습니다. 이 예제에서는 텍스트 편집기에서도 만들 수 있는 간단한 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>&amp;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 저장소에서 찾을 수 있습니다.