JavaScript를 통한 동적 QML 객체 생성
QML은 JavaScript 내에서 객체를 동적으로 생성하는 기능을 지원합니다. 이는 객체의 인스턴스화를 필요한 시점까지 지연시켜 애플리케이션 시작 시간을 단축하는 데 유용합니다. 또한 사용자 입력이나 기타 이벤트에 반응하여 시각적 객체를 동적으로 생성하고 씬에 추가할 수 있게 해줍니다.
경고: 신뢰할 수 없는 출처에서객체를 동적으로 생성해서는 안 됩니다. 정적 QML 소스에 적용되는 제한 사항은 동적 객체 생성에도 동일하게 적용됩니다.
객체 동적 생성
JavaScript에서 객체를 동적으로 생성하는 방법에는 두 가지가 있습니다. ` Qt.createComponent()`를 호출하여 ` Component ` 객체를 동적으로 생성하거나, ` Qt.createQmlObject()`를 사용하여 QML 문자열로부터 객체를 생성할 수 있습니다. QML 문서에 정의된 기존 컴포넌트가 있고 해당 컴포넌트의 인스턴스를 동적으로 생성하려는 경우에는 컴포넌트를 생성하는 방법이 더 적합합니다. 반면, QML 문자열로부터 객체를 생성하는 방법은 객체의 QML 자체가 런타임에 생성되는 경우에 유용합니다.
컴포넌트 동적 생성
QML 파일에 정의된 컴포넌트를 동적으로 로드하려면, ` Qt object`의 ` Qt.createComponent()` 함수를 호출하십시오. 이 함수는 QML 파일의 URL을 유일한 인수로 받아 이 URL로부터 ` Component ` 객체를 생성합니다.
Component 객체를 얻으면, createObject() 메서드를 호출하여 컴포넌트의 인스턴스를 생성할 수 있습니다. 이 함수는 하나 또는 두 개의 인수를 받을 수 있습니다:
- 첫 번째 인수는 새 객체의 부모입니다. 부모는 그래픽 객체(즉, Item 유형)이거나 비그래픽 객체(즉, QtObject 또는 C++ QObject 유형)일 수 있습니다. 그래픽 부모 객체를 가진 그래픽 객체만 Qt Quick 시각적 캔버스에 렌더링됩니다. 나중에 부모 객체를 설정하고자 한다면, 이 함수에
null를 안전하게 전달할 수 있습니다. - 두 번째 인수는 선택 사항이며, 객체의 초기 속성 값을 정의하는 속성-값 쌍의 맵입니다. 이 인수로 지정된 속성 값은 객체 생성이 완료되기 전에 적용되므로, 다른 속성 바인딩을 활성화하기 위해 특정 속성을 초기화해야 할 때 발생할 수 있는 바인딩 오류를 방지할 수 있습니다. 또한, 객체가 생성된 후에 속성 값과 바인딩을 정의하는 것에 비해 약간의 성능 이점이 있습니다.
다음은 예시입니다. 먼저 간단한 QML 컴포넌트를 정의하는 ` Sprite.qml` 파일이 있습니다:
import QtQuick
Rectangle { width: 80; height: 50; color: "red" }메인 애플리케이션 파일인 ` main.qml`은 ` Sprite ` 객체를 생성할 ` componentCreation.js ` JavaScript 파일을 임포트합니다:
import QtQuick
import "componentCreation.js" as MyScript
Rectangle {
id: appWindow
width: 300; height: 300
Component.onCompleted: MyScript.createSpriteObjects();
}다음은 componentCreation.js 파일입니다. QML 파일이 네트워크를 통해 로드되어 즉시 준비되지 않을 경우를 대비하여, createObject()을 호출하기 전에 status 컴포넌트가 Component.Ready 상태인지 확인하는 점에 유의하십시오.
var component;
var sprite;
function createSpriteObjects() {
component = Qt.createComponent("Sprite.qml");
if (component.status == Component.Ready)
finishCreation();
else
component.statusChanged.connect(finishCreation);
}
function finishCreation() {
if (component.status == Component.Ready) {
sprite = component.createObject(appWindow, {x: 100, y: 100});
if (sprite == null) {
// Error Handling
console.log("Error creating object");
}
} else if (component.status == Component.Error) {
// Error Handling
console.log("Error loading component:", component.errorString());
}
}로드할 QML 파일이 로컬 파일임이 확실하다면, finishCreation() 함수를 생략하고 바로 createObject()을 호출할 수 있습니다:
function createSpriteObjects() {
component = Qt.createComponent("Sprite.qml");
sprite = component.createObject(appWindow, {x: 100, y: 100});
if (sprite == null) {
// Error Handling
console.log("Error creating object");
}
}두 경우 모두, 동적으로 생성된 객체가 시각적(Qt Quick) 객체이므로 createObject()을 호출할 때 appWindow 를 부모 인자로 전달해야 한다는 점에 유의하십시오. 생성된 객체는 main.qml 에서 appWindow 객체의 자식 객체가 되며, 씬에 표시됩니다.
상대 경로를 사용하는 파일의 경우, 경로는 Qt.createComponent()이 실행되는 파일을 기준으로 해야 합니다.
동적으로 생성된 객체에 신호를 연결하거나(또는 신호를 수신하려면) signal. connect() 메서드를 사용하십시오. 자세한 내용은 ‘메서드 및 신호에 신호 연결’을 참조하십시오.
incubateObject() 함수를 사용하여 차단 없이 컴포넌트를 인스턴스화할 수도 있습니다.
QML 문자열을 사용하여 객체 생성
경고: QML 문자열로 객체를생성하는 것은 매번 전달된 QML 문자열을 엔진이 컴파일해야 하기 때문에 매우 느립니다. 또한, 프로그래밍 방식으로 QML 코드를 생성할 때 유효하지 않은 QML이 생성될 가능성이 매우 높습니다. 문자열 조작을 통해 새로운 컴포넌트를 생성하기보다는, QML 컴포넌트를 별도의 파일로 분리하여 속성과 메서드를 추가해 동작을 사용자 정의하는 것이 훨씬 더 좋습니다.
QML이 런타임까지 정의되지 않은 경우, 다음 예제와 같이 ` Qt.createQmlObject()` 함수를 사용하여 QML 문자열로부터 QML 객체를 생성할 수 있습니다.
const newObject = Qt.createQmlObject(`
import QtQuick
Rectangle {
color: "red"
width: 20
height: 20
}
`,
parentItem,
"myDynamicSnippet"
);첫 번째 인수는 생성할 QML 문자열입니다. 새 파일에서와 마찬가지로, 사용하려는 모든 타입을 임포트해야 합니다. 두 번째 인자는 새 객체의 부모 객체이며, 컴포넌트에 적용되는 부모 인자의 의미론은 createQmlObject() 에도 마찬가지로 적용됩니다. 세 번째 인자는 새 객체와 연관시킬 파일 경로로, 오류 보고에 사용됩니다.
QML 문자열에서 상대 경로를 사용하여 파일을 가져오는 경우, 해당 경로는 부모 객체(메서드의 두 번째 인자)가 정의된 파일을 기준으로 해야 합니다.
중요: 정적 QML 애플리케이션을 빌드할때 , QML 파일을 스캔하여 임포트 종속성을 감지합니다. 이를 통해 필요한 모든 플러그인과 리소스가 컴파일 시점에 해결됩니다. 그러나 명시적인 임포트 문(QML 파일 상단에 있는 것)만 고려되며, 문자열 리터럴 내에 포함된 임포트 문은 고려되지 않습니다. 따라서 정적 빌드를 지원하려면 ` Qt.createQmlObject()`를 사용하는 QML 파일에서, 문자열 리터럴 내부는 물론 파일 상단에도 필요한 모든 임포트를 명시적으로 포함해야 합니다.
동적으로 생성된 객체 관리
동적으로 생성된 객체를 관리할 때는 생성 컨텍스트가 생성된 객체보다 오래 지속되도록 해야 합니다. 그렇지 않으면 생성 컨텍스트가 먼저 소멸될 경우, 동적 객체 내의 바인딩과 시그널 핸들러가 더 이상 작동하지 않게 됩니다.
실제 생성 컨텍스트는 객체가 생성되는 방식에 따라 달라집니다:
- Qt.createComponent()을 사용하는 경우, 생성 컨텍스트는 이 메서드가 호출된 QQmlContext 입니다.
- Qt.createQmlObject()가 호출되는 경우, 생성 컨텍스트는 이 메서드가 호출된 입니다.
Component{}객체가 정의되어 있고, 해당 객체에 대해 createObject() 또는 incubateObject()가 호출된 경우, 생성 컨텍스트는Component가 정의된 컨텍스트입니다.
또한, 동적으로 생성된 객체는 다른 객체와 동일하게 사용할 수 있지만, QML에서는 ID를 가지지 않는다는 점에 유의하십시오.
객체를 동적으로 삭제하기
많은 사용자 인터페이스에서 시각적 객체를 삭제하는 대신, 그 불투명도를 0으로 설정하거나 화면 밖으로 이동시키는 것만으로도 충분합니다. 하지만 동적으로 생성된 객체가 많다면, 사용되지 않는 객체를 삭제함으로써 상당한 성능 향상을 얻을 수 있습니다.
편의성을 위해 제공되는 QML 객체 팩토리(예: Loader 및 Repeater)에 의해 동적으로 생성된 객체는 절대로 수동으로 삭제해서는 안 됩니다. 또한, 직접 동적으로 생성하지 않은 객체를 삭제하는 것도 피해야 합니다.
항목은 destroy() 메서드를 사용하여 삭제할 수 있습니다. 이 메서드에는 객체가 소멸되기 전까지의 대략적인 지연 시간(밀리초 단위)을 지정하는 선택적 인자(기본값은 0)가 있습니다.
다음은 예시입니다. ` application.qml `는 ` SelfDestroyingRect.qml ` 컴포넌트의 인스턴스 5개를 생성합니다. 각 인스턴스는 ` NumberAnimation`를 실행하고, 애니메이션이 완료되면 루트 객체에 대해 ` destroy() `를 호출하여 스스로를 소멸시킵니다:
application.qml | |
SelfDestroyingRect.qml | |
또는 ` application.qml `가 ` object.destroy()`를 호출하여 생성된 객체를 직접 소멸시킬 수도 있습니다.
해당 객체 내에서 destroy()를 호출하는 것은 안전합니다. 객체는 destroy()가 호출되는 즉시 소멸되지 않고, 해당 스크립트 블록이 끝난 후 다음 프레임 사이에 정리됩니다(지연 시간을 0이 아닌 값으로 지정하지 않은 경우).
또한 SelfDestroyingRect 인스턴스가 다음과 같이 정적으로 생성된 경우:
Item {
SelfDestroyingRect {
// ...
}
}이 경우 오류가 발생합니다. 객체는 동적으로 생성된 경우에만 동적으로 소멸될 수 있기 때문입니다.
Qt.createQmlObject()로 생성된 객체도 마찬가지로 destroy() 를 사용하여 소멸시킬 수 있습니다:
const newObject = Qt.createQmlObject(`
import QtQuick
Rectangle {
color: "red"
width: 20
height: 20
}
`,
parentItem,
"myDynamicSnippet"
);
newObject.destroy(1000);© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.