Qt Widgets - 텍스트 뷰어 플러그인 예시
메뉴, 도구 모음, 상태 표시줄이 있는 위젯 예제입니다.
텍스트 뷰어 예제는 범용 문서 뷰어용 플러그인 형태로 QPlainTextEdit 을 기반으로 구축된 텍스트 편집기입니다.
텍스트 뷰어 예제의 모든 코드는 AbstractViewer
을 상속하는 TxtViewer
클래스에 있습니다. AbstractViewer
은 뷰어와 기본 창 간의 상호 작용을 위한 프레임워크를 제공합니다. 이 애플리케이션은 메뉴 표시줄에 File, Edit, Help 항목을 제공합니다.
메인 창 하단의 상태 표시줄에는 애플리케이션이 사용자에게 제공하는 메시지가 표시됩니다.
최근에 연 파일은 File 메뉴에 표시됩니다. 이 예제에서는 한 번에 하나의 파일만 로드할 수 있습니다.
클래스 정의
class TxtViewer : public ViewerInterface { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.DocumentViewer.ViewerInterface" FILE "txtviewer.json") Q_INTERFACES(ViewerInterface)
클래스 정의는 신호와 슬롯을 처리하는 Q_OBJECT
매크로로 시작합니다. 그 다음에는 플러그인을 등록하는 데 필요한 Q_PLUGIN_METADATA
및 Q_INTERFACES
매크로가 이어집니다.
이 클래스는 ViewerInterface
에서 상속되며, AbstractViewer
에서 상속됩니다. ViewerInterface
클래스는 메인 창 애플리케이션과 플러그인 간의 인터페이스를 제공하는 데 사용됩니다.
QPluginLoader
또한 플러그인의 키가 포함되어야 하는 txtviewer.json 파일이 필요합니다:
{ "Keys": [ "txtviewer" ] } public: TxtViewer(); ~TxtViewer() override; void init(QFile *file, QWidget *parent, QMainWindow *mainWindow) override; QString viewerName() const override { return QLatin1StringView(staticMetaObject.className()); }; QStringList supportedMimeTypes() const override; bool saveDocument() override { return saveFile(m_file.get()); }; bool saveDocumentAs() override; bool hasContent() const override; QByteArray saveState() const override { return {}; } bool restoreState(QByteArray &) override { return true; } bool supportsOverview() const override { return false; } #ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT protected: void printDocument(QPrinter *printer) const override; #endif // QT_DOCUMENTVIEWER_PRINTSUPPORT private slots: void setupTxtUi(); private: void openFile(); bool saveFile (QFile *file); QPlainTextEdit *m_textEdit; };
이 클래스는 생성자를 정의하지 않으므로 인수가 없는 표준 생성자만 사용할 수 있습니다. 소멸자를 포함한 다른 모든 함수는 ViewerInterface
의 가상 함수를 다시 구현합니다. 이 함수는 데이터, 정보 및 지침을 기본 애플리케이션과 교환하는 데 사용됩니다.
설정을 저장하고 복원하는 기능은 구현되어 있지 않습니다. supportsOverview
함수는 항상 false
을 반환하며, 이는 썸네일 탐색 창을 표시할 필요가 없음을 기본 애플리케이션에 알려줍니다.
TxtViewer 클래스 구현
#include "txtviewer.h" #include <QFileDialog> #include <QMainWindow> #include <QMenu> #include <QMenuBar> #include <QPlainTextEdit> #include <QScrollBar> #include <QToolBar> #include <QGuiApplication> #include <QPainter> #include <QTextDocument> #include <QDir> #ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT #include <QPrinter> #include <QPrintDialog> #endif using namespace Qt::StringLiterals; TxtViewer::TxtViewer() { connect(this, &AbstractViewer::uiInitialized, this, &TxtViewer::setupTxtUi); } TxtViewer::~TxtViewer() = default; void TxtViewer::init(QFile *file, QWidget *parent, QMainWindow *mainWindow) { AbstractViewer::init(file, new QPlainTextEdit(parent), mainWindow); m_textEdit = qobject_cast<QPlainTextEdit *>(widget()); } QStringList TxtViewer::supportedMimeTypes() const { return {"text/plain"_L1}; } void TxtViewer::setupTxtUi() { QMenu *editMenu = addMenu(tr("&Edit")); QToolBar *editToolBar = addToolBar(tr("Edit")); #if QT_CONFIG(clipboard) const QIcon cutIcon = QIcon::fromTheme(QIcon::ThemeIcon::EditCut, QIcon(":/demos/documentviewer/images/cut.png"_L1)); QAction *cutAct = new QAction(cutIcon, tr("Cu&t"), this); cutAct->setShortcuts(QKeySequence::Cut); cutAct->setStatusTip(tr("Cut the current selection's contents to the " "clipboard")); connect(cutAct, &QAction::triggered, m_textEdit, &QPlainTextEdit::cut); editMenu->addAction(cutAct); editToolBar->addAction(cutAct); const QIcon copyIcon = QIcon::fromTheme(QIcon::ThemeIcon::EditCopy, QIcon(":/demos/documentviewer/images/copy.png"_L1)); QAction *copyAct = new QAction(copyIcon, tr("&Copy"), this); copyAct->setShortcuts(QKeySequence::Copy); copyAct->setStatusTip(tr("Copy the current selection's contents to the " "clipboard")); connect(copyAct, &QAction::triggered, m_textEdit, &QPlainTextEdit::copy); editMenu->addAction(copyAct); editToolBar->addAction(copyAct); const QIcon pasteIcon = QIcon::fromTheme(QIcon::ThemeIcon::EditPaste, QIcon(":/demos/documentviewer/images/paste.png"_L1)); QAction *pasteAct = new QAction(pasteIcon, tr("&Paste"), this); pasteAct->setShortcuts(QKeySequence::Paste); pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current " "selection")); connect(pasteAct, &QAction::triggered, m_textEdit, &QPlainTextEdit::paste); editMenu->addAction(pasteAct); editToolBar->addAction(pasteAct); menuBar()->addSeparator(); cutAct->setEnabled(false); copyAct->setEnabled(false); connect(m_textEdit, &QPlainTextEdit::copyAvailable, cutAct, &QAction::setEnabled); connect(m_textEdit, &QPlainTextEdit::copyAvailable, copyAct, &QAction::setEnabled); #endif // QT_CONFIG(clipboard) openFile(); connect(m_textEdit, &QPlainTextEdit::textChanged, this, [&](){ maybeSetPrintingEnabled(hasContent()); }); connect(m_uiAssets.back, &QAction::triggered, m_textEdit, [&](){ auto *bar = m_textEdit->verticalScrollBar(); if (bar->value() > bar->minimum()) bar->setValue(bar->value() - 1); }); connect(m_uiAssets.forward, &QAction::triggered, m_textEdit, [&](){ auto *bar = m_textEdit->verticalScrollBar(); if (bar->value() < bar->maximum()) bar->setValue(bar->value() + 1); }); }
TxtViewer
에서 사용하는 모든 클래스에 액세스하는 데 필요한 헤더 파일을 포함하는 것으로 시작합니다. 또한 txtviewer.h
.
QPrinter
와 QPrintDialog
는 컴파일 시스템에서 인쇄 지원이 활성화된 경우에만 포함됩니다.
왜 mainwindow.h
에 이러한 헤더를 포함하지 않고 끝내는지 궁금할 수 있습니다. 그 이유는 다른 헤더 파일에서 여러 개의 큰 헤더를 포함하면 성능이 급격히 저하될 수 있기 때문입니다. 여기에서는 아무런 문제가 없지만 일반적으로 다른 헤더 파일에서 꼭 필요한 헤더 파일만 포함하는 것이 좋습니다.
구현은 빈 소멸자로 시작합니다. 완전히 생략할 수도 있습니다. 코드 리더에게 소멸자에서 아무것도 할 필요가 없음을 알리기 위해 비워두는 것이 좋습니다.
소멸자 뒤에는 세 개의 인수를 받는 초기화 함수가 이어집니다:
file
, 열어 표시할 파일에 대한 포인터.parent
는 편집기가 배치될QWidget
을 가리킵니다.mainWindow
는 메뉴와 메뉴 표시줄이 처리되는 애플리케이션의 메인 창을 가리킵니다.
이 함수는 AbstractViwer
의 기본 init 함수를 호출합니다. 새로운 QPlainTextEdit 위젯이 생성되어 파일의 내용을 표시합니다. 그런 다음 TxtViewer
의 설정 함수가 기본 클래스의 uiInitialized 신호에 연결됩니다.
다음 함수는 텍스트 뷰어가 지원하는 마임 유형 목록을 반환합니다. 일반 텍스트만 지원됩니다.
마지막 초기화 함수는 메뉴, 아이콘, 버튼, 툴팁과 같은 뷰어별 UI 컴포넌트를 추가합니다. 이 기능은 AbstractViewer
에서 제공하는 기능을 사용하여 다른 뷰어 플러그인으로 다른 파일이 표시되면 이러한 구성 요소가 애플리케이션의 기본 창에서 제거되도록 합니다.
void TxtViewer::openFile() { const QString type = tr("open"); if (!m_file->open(QFile::ReadOnly | QFile::Text)) { statusMessage(tr("Cannot read file %1:\n%2.") .arg(QDir::toNativeSeparators(m_file->fileName()), m_file->errorString()), type); return; } QTextStream in(m_file.get()); #ifndef QT_NO_CURSOR QGuiApplication::setOverrideCursor(Qt::WaitCursor); #endif if (!m_textEdit->toPlainText().isEmpty()) { m_textEdit->clear(); disablePrinting(); } m_textEdit->setPlainText(in.readAll()); #ifndef QT_NO_CURSOR QGuiApplication::restoreOverrideCursor(); #endif statusMessage(tr("File %1 loaded.") .arg(QDir::toNativeSeparators(m_file->fileName())), type); maybeEnablePrinting(); }
openFile
파일을 열고, 그 내용을 QPlainTextEdit 로 전송하고, 열기 성공 여부에 따라 사용자에게 상태 메시지를 인쇄합니다.
bool TxtViewer::hasContent() const { return (!m_textEdit->toPlainText().isEmpty()); } #ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT void TxtViewer::printDocument(QPrinter *printer) const { if (!hasContent()) return; m_textEdit->print(printer); } #endif // QT_DOCUMENTVIEWER_PRINTSUPPORT bool TxtViewer::saveFile(QFile *file) { QString errorMessage; QGuiApplication::setOverrideCursor(Qt::WaitCursor); if (file->open(QFile::WriteOnly | QFile::Text)) { QTextStream out(file); out << m_textEdit->toPlainText(); } else { errorMessage = tr("Cannot open file %1 for writing:\n%2.") .arg(QDir::toNativeSeparators(file->fileName())), file->errorString(); } QGuiApplication::restoreOverrideCursor(); if (!errorMessage.isEmpty()) { statusMessage(errorMessage); return false; } statusMessage(tr("File %1 saved") .arg(QDir::toNativeSeparators(file->fileName()))); return true; } bool TxtViewer::saveDocumentAs() { QFileDialog dialog(mainWindow()); dialog.setWindowModality(Qt::WindowModal); dialog.setAcceptMode(QFileDialog::AcceptSave); if (dialog.exec() != QDialog::Accepted) return false; const QStringList &files = dialog.selectedFiles(); if (files.isEmpty()) return false; //newFile(); m_file->setFileName(files.first()); return saveDocument(); }
다음으로 다시 구현된 함수는 뷰어 플러그인이 실제로 콘텐츠를 표시하고 있는지 여부를 기본 애플리케이션에 알려줍니다.
컴파일 시스템에서 인쇄가 지원되는 경우 다음 섹션에서 이를 구현합니다.
마지막 두 개의 재구현은 현재 파일을 저장하거나 새 이름으로 저장하는 기능을 제공합니다.
© 2025 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.