리치 텍스트 문서 구조
텍스트 문서는 ` QTextDocument ` 클래스로 표현되며, 이 클래스는 문서의 내부 표현 및 구조에 대한 정보를 포함하고, 실행 취소/다시 실행 기능을 제공하기 위해 변경 내역을 추적합니다.
텍스트 문서의 구조화된 표현은 내용을 텍스트 블록, 프레임, 표 및 기타 객체의 계층 구조로 나타냅니다. 이러한 요소들은 문서에 논리적 구조를 제공하며, 그 내용이 어떻게 표시될지를 설명합니다. 일반적으로 프레임과 표는 다른 구조들을 그룹화하는 데 사용되는 반면, 텍스트 블록은 실제 텍스트 정보를 담고 있습니다.
새로운 요소는 QTextCursor를 사용하여 프로그래밍 방식으로, 또는 QTextEdit 와 같은 편집기 위젯을 통해 생성되어 문서에 삽입됩니다. 요소는 생성 시 특정 서식을 지정할 수 있으며, 그렇지 않은 경우 해당 요소에 대해 커서의 현재 서식이 적용됩니다.
![]() | 기본 구조 문서의 “최상위 수준”은 그림과 같이 구성될 수 있습니다. 각 문서에는 항상 루트 프레임이 포함되며, 이 프레임은 항상 적어도 하나의 텍스트 블록을 포함합니다. 텍스트 콘텐츠가 포함된 문서의 경우, 루트 프레임은 일반적으로 일련의 블록 및 기타 요소들로 구성됩니다. 문서 내에서 프레임과 표의 연속은, 텍스트 블록에 정보가 포함되어 있지 않더라도 항상 텍스트 블록으로 구분됩니다. 이를 통해 기존 구조 사이에 새로운 요소를 언제든지 삽입할 수 있습니다. |
이 장에서는 리치 텍스트 문서에서 사용되는 각 구조적 요소를 살펴보고, 그 특징과 용도를 개괄하며, 해당 내용을 확인하는 방법을 보여줍니다. 문서 편집에 대해서는 “QTextCursor 인터페이스”에서 설명합니다.
리치 텍스트 문서
QTextDocument 객체에는 리치 텍스트 문서를 구성하는 데 필요한 모든 정보가 포함되어 있습니다. 텍스트 문서는 편집기가 사용하는 선형 버퍼 형태와 레이아웃 엔진에 유용한 객체 계층 구조라는 두 가지 상호 보완적인 방식으로 접근할 수 있습니다. 계층적 문서 모델에서 객체는 일반적으로 프레임, 표, 목록과 같은 시각적 요소에 해당합니다. 더 낮은 수준에서 이러한 요소들은 텍스트 스타일이나 정렬과 같은 속성을 설명합니다. 문서의 선형 표현은 문서 내용을 편집하고 조작하는 데 사용됩니다.
QTextEdit 를 사용하면 리치 텍스트를 쉽게 표시하고 편집할 수 있지만, 문서는 편집기 위젯과 별개로 사용할 수도 있습니다. 예를 들어:
QTextDocument *newDocument = new QTextDocument;또는 기존 편집기에서 추출할 수도 있습니다:
QTextEdit *editor = new QTextEdit;
QTextDocument *editorDocument = editor->document();이러한 유연성 덕분에 애플리케이션은 여러 편집기 위젯으로 인한 부하 없이, 또는 문서를 중간 형식으로 저장할 필요 없이 여러 리치 텍스트 문서를 처리할 수 있습니다.
빈 문서에는 루트 프레임이 포함되어 있으며, 이 프레임 자체는 하나의 빈 텍스트 블록을 포함합니다. 프레임은 문서의 각 부분을 논리적으로 분리해 줄 뿐만 아니라, 렌더링 시 어떻게 표시될지를 결정하는 속성도 가지고 있습니다. 테이블은 행과 열로 배열된 여러 셀로 구성된 특수한 유형의 프레임으로, 각 셀은 추가적인 구조와 텍스트를 포함할 수 있습니다. 표는 셀을 유연하게 구성할 수 있도록 하는 관리 및 레이아웃 기능을 제공합니다.
텍스트 블록은 텍스트 단편을 포함하며, 각 텍스트 단편은 텍스트 및 문자 서식 정보를 지정합니다. 텍스트 속성은 문자 수준과 블록 수준 모두에서 정의됩니다. 문자 수준에서는 글꼴 가족, 텍스트 색상, 글꼴 굵기 등의 속성을 지정할 수 있습니다. 블록 수준 속성은 텍스트 흐름 방향, 정렬, 배경색 등 텍스트의 상위 수준 외관과 동작을 제어합니다.
문서 구조는 직접 조작되지 않습니다. 편집은 커서 기반 인터페이스를 통해 수행됩니다. 텍스트 커서 인터페이스는 루트 프레임에 새로운 문서 요소를 자동으로 삽입하며, 필요한 경우 빈 블록으로 채워지도록 보장합니다.
루트 프레임은 다음과 같은 방식으로 확보합니다:
QTextDocument *editorDocument = editor->document();
QTextFrame *root = editorDocument->rootFrame();문서 구조를 탐색할 때는 루트 프레임에서 시작하는 것이 유용합니다. 루트 프레임을 통해 전체 문서 구조에 접근할 수 있기 때문입니다.
문서 요소
리치 텍스트 문서는 일반적으로 단락, 프레임, 표, 목록과 같은 일반적인 요소들로 구성됩니다. 이러한 요소들은 리치 텍스트 문서( QTextDocument )에서 QTextBlock, QTextFrame, QTextTable, QTextList 클래스로 표현됩니다. 문서의 다른 요소들과 달리, 이미지는 특별히 서식이 지정된 텍스트 조각으로 표현됩니다. 이를 통해 이미지는 주변 텍스트와 서식이 일치하도록 인라인으로 배치될 수 있습니다.
문서의 기본 구조 구성 요소는 QTextBlock 및 QTextFrame 입니다. 블록 자체는 서식이 지정된 텍스트 조각(QTextFragment)을 포함하지만, 이러한 조각들은 문서의 상위 수준 구조에 직접적인 영향을 미치지는 않습니다.
다른 문서 요소를 그룹화할 수 있는 요소는 일반적으로 ` QTextObject`의 하위 클래스이며, 두 가지 범주로 나뉩니다. 텍스트 블록을 그룹화하는 요소는 ` QTextBlockGroup`의 하위 클래스이고, 프레임 및 기타 요소를 그룹화하는 요소는 ` QTextFrame`의 하위 클래스입니다.
텍스트 블록
텍스트 블록은 QTextBlock 클래스에 의해 제공됩니다.
텍스트 블록은 서로 다른 문자 서식을 가진 텍스트 조각들을 묶어주며, 문서 내의 단락을 표현하는 데 사용됩니다. 각 블록은 일반적으로 서로 다른 스타일을 가진 여러 텍스트 조각을 포함합니다. 조각은 텍스트가 문서에 삽입될 때 생성되며, 문서가 편집될 때 더 많은 조각이 추가됩니다. 문서는 블록 내의 서로 다른 텍스트 스타일을 효율적으로 표현하기 위해 조각을 분할, 병합 및 제거합니다.
QTextBlock::iterator 를 사용하여 블록의 내부 구조를 탐색함으로써, 특정 블록 내의 조각들을 확인할 수 있습니다:
QTextBlock::iterator it;
for (it = currentBlock.begin(); !(it.atEnd()); ++it) {
QTextFragment currentFragment = it.fragment();
if (currentFragment.isValid())
processFragment(currentFragment);
}블록은 목록 항목을 표현하는 데에도 사용됩니다. 따라서 블록은 목록 항목에 사용되는 글머리 기호의 유형과 같은 블록 수준의 서식 정보를 포함하는 고유한 문자 서식을 정의할 수 있습니다. 블록 자체의 서식은 ` QTextBlockFormat ` 클래스에 의해 정의되며, 텍스트 정렬, 들여쓰기, 배경색과 같은 속성을 설명합니다.
특정 문서에 복잡한 구조가 포함되어 있을 수 있지만, 일단 문서 내 유효한 블록에 대한 참조를 확보하면 작성된 순서대로 각 텍스트 블록 사이를 이동할 수 있습니다:
QTextBlock currentBlock = textDocument->begin();
while (currentBlock.isValid()) {
processBlock(currentBlock);
currentBlock = currentBlock.next();
}이 방법은 프레임, 표 및 기타 유형의 구조를 무시하므로 문서에서 서식 있는 텍스트만 추출하고자 할 때 유용합니다.
QTextBlock 블록을 더 쉽게 조작할 수 있도록 하는 비교 연산자를 제공합니다. ` operator==()` 및 ` operator!=()`는 두 블록이 동일한지 확인하는 데 사용되며, ` operator<()`는 문서에서 어느 블록이 먼저 나타나는지 판단하는 데 사용됩니다.
프레임
프레임은 QTextFrame 클래스에서 제공됩니다.
텍스트 프레임은 텍스트 블록과 자식 프레임을 그룹화하여 단락보다 큰 문서 구조를 만듭니다. 프레임의 형식은 페이지에서 프레임의 렌더링 방식과 배치 위치를 지정합니다. 프레임은 텍스트 흐름에 삽입되거나 페이지의 왼쪽 또는 오른쪽에 플로팅됩니다. 각 문서에는 다른 모든 문서 요소를 포함하는 루트 프레임이 있습니다. 따라서 루트 프레임을 제외한 모든 프레임에는 부모 프레임이 있습니다.
텍스트 블록은 다른 문서 요소를 구분하는 데 사용되므로, 각 프레임은 항상 적어도 하나의 텍스트 블록과 0개 이상의 자식 프레임을 포함합니다. ` QTextFrame::iterator `를 사용하여 프레임의 자식 요소를 순회함으로써 프레임의 내용을 확인할 수 있습니다:
QTextFrame::iterator it;
for (it = frame->begin(); !(it.atEnd()); ++it) {
QTextFrame *childFrame = it.currentFrame();
QTextBlock childBlock = it.currentBlock();
if (childFrame)
processFrame(childFrame);
else if (childBlock.isValid())
processBlock(childBlock);
}이터레이터는 프레임과 블록을 모두 선택하므로, 어떤 요소를 가리키고 있는지 확인해야 합니다. 이를 통해 문서 구조를 프레임 단위로 탐색하면서도 필요할 경우 텍스트 블록에 접근할 수 있습니다. QTextBlock::iterator 와 QTextFrame::iterator 클래스를 상호 보완적으로 사용하여 문서에서 필요한 구조를 추출할 수 있습니다.
표
표는 QTextTable 클래스를 통해 제공됩니다.
표는 행과 열로 배열된 셀들의 모음입니다. 각 표 셀은 고유한 문자 서식을 가진 문서 요소이지만, 프레임이나 텍스트 블록과 같은 다른 요소를 포함할 수도 있습니다. 표 셀은 표가 생성될 때나 추가 행이나 열이 추가될 때 자동으로 생성됩니다. 또한 표 간에 이동할 수도 있습니다.
QTextTable 는 QTextFrame 의 하위 클래스이므로, 테이블은 문서 구조 내에서 프레임과 동일하게 취급됩니다. 문서에서 발견되는 각 프레임에 대해, 해당 프레임이 테이블을 나타내는지 확인하고 그에 따라 다르게 처리할 수 있습니다:
QTextFrame::iterator it;
for (it = frame->begin(); !(it.atEnd()); ++it) {
QTextFrame *childFrame = it.currentFrame();
QTextBlock childBlock = it.currentBlock();
if (childFrame) {
QTextTable *childTable = qobject_cast<QTextTable*>(childFrame);
if (childTable)
processTable(childTable);
else
processFrame(childFrame);
} else if (childBlock.isValid()) {
processBlock(childBlock);
}
}기존 테이블 내의 셀은 행과 열을 순회하여 확인할 수 있습니다.
for (int row = 0; row < table->rows(); ++row) {
for (int column = 0; column < table->columns(); ++column) {
QTextTableCell tableCell = table->cellAt(row, column);
processTableCell(tableCell);
}
}목록
목록은 ` QTextList ` 클래스에서 제공됩니다.
목록은 일반적인 방식으로 서식이 지정된 텍스트 블록의 시퀀스이지만, 글머리 기호나 번호 매기기 항목과 같은 표준 목록 장식 기능도 제공합니다. 목록은 중첩될 수 있으며, 목록 서식에서 0이 아닌 들여쓰기를 지정하면 들여쓰기가 적용됩니다.
각 목록 항목은 목록 내의 인덱스를 통해 참조할 수 있습니다:
for (int index = 0; index < list->count(); ++index) {
QTextBlock listItem = list->item(index);
processListItem(listItem);
}QTextList 는 QTextBlockGroup 의 하위 클래스이므로, 목록 항목을 자식 요소로 묶지 않고 대신 이를 관리하기 위한 다양한 함수를 제공합니다. 즉, 문서를 탐색할 때 발견되는 모든 텍스트 블록은 실제로 목록 항목일 수 있습니다. 다음 코드를 사용하면 목록 항목이 올바르게 식별되도록 할 수 있습니다:
QTextFrame::iterator it;
for (it = frame->begin(); !(it.atEnd()); ++it) {
QTextBlock block = it.currentBlock();
if (block.isValid()) {
QTextList *list = block.textList();
if (list) {
int index = list->itemNumber(block);
processListItem(list, index);
}
}
}이미지
QTextDocument 의 이미지는 리소스 메커니즘을 통해 외부 이미지를 참조하는 텍스트 단편으로 표현됩니다. 이미지는 커서 인터페이스를 사용하여 생성되며, 나중에 이미지의 텍스트 단편의 문자 형식을 변경하여 수정할 수 있습니다:
if (fragment.isValid()) {
QTextImageFormat newImageFormat = fragment.charFormat().toImageFormat();
if (newImageFormat.isValid()) {
newImageFormat.setName(":/images/newimage.png");
QTextCursor helper = cursor;
helper.setPosition(fragment.position());
helper.setPosition(fragment.position() + fragment.length(),
QTextCursor::KeepAnchor);
helper.setCharFormat(newImageFormat);
}
}이미지를 나타내는 단편은 이미지를 포함하는 텍스트 블록 내의 단편들을 순회하여 찾을 수 있습니다.
© 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.
