문서 뷰어

JSON, 텍스트 및 PDF 파일을 표시하고 인쇄하는 위젯 애플리케이션입니다.

문서 뷰어는 정적 및 동적 도구 모음, 메뉴, 동작이 있는 QMainWindow 을 사용하는 방법을 보여줍니다. 또한 위젯 기반 애플리케이션에서 다음 기능을 시연합니다:

  • QSettings 을 사용하여 사용자 환경설정을 조회 및 저장하고 이전에 열어본 파일 기록을 관리합니다.
  • 위젯 위로 마우스를 가져갔을 때 커서 동작 제어하기.
  • 동적으로 로드되는 플러그인 만들기.

애플리케이션 및 메인 창 만들기

애플리케이션과 메인 창은 main.cpp 에서 구성됩니다. main() 함수는 QCommandLineParser 를 사용하여 도움말, 버전 및 선택적 위치 인수인 파일과 같은 명령줄 인수를 처리합니다. 사용자가 애플리케이션을 시작할 때 파일 경로를 제공한 경우 메인 창에서 해당 파일이 열립니다:

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QCoreApplication::setOrganizationName("QtProject"_L1);
    QCoreApplication::setApplicationName("DocumentViewer"_L1);
    QCoreApplication::setApplicationVersion("1.0"_L1);

    QCommandLineParser parser;
    parser.setApplicationDescription(QApplication::translate("main",
                                                     "A viewer for JSON, PDF and text files"));
    parser.addHelpOption();
    parser.addVersionOption();
    parser.addPositionalArgument("File"_L1, QApplication::translate("main",
                                                                    "JSON, PDF or text file to open"));
    parser.process(app);

    const QStringList &positionalArguments = parser.positionalArguments();
    const QString &fileName = (positionalArguments.count() > 0) ? positionalArguments.at(0)
                                                                : QString();

    MainWindow w;

    // Start application only if plugins are available
    if (!w.hasPlugins()) {
        QMessageBox::critical(nullptr,
                              "No viewer plugins found"_L1,
                              "Unable to load viewer plugins. Exiting application."_L1);
        return 1;
    }

    w.show();
    if (!fileName.isEmpty())
        w.openFile(fileName);

    return app.exec();
}

MainWindow 클래스

MainWindow 클래스는 메뉴, 작업 및 툴바가 있는 애플리케이션 화면을 제공합니다. 파일을 열 수 있으며 콘텐츠 유형을 자동으로 감지합니다. 또한 QSettings 을 사용하여 이전에 열었던 파일 목록을 유지 관리하고 실행 시 설정을 저장하고 다시 로드합니다. 메인창은 콘텐츠 유형에 따라 열린 파일에 적합한 뷰어를 생성하고 문서 인쇄를 지원합니다.

MainWindow의 생성자는 Qt Designer 에서 생성된 사용자 인터페이스를 초기화합니다. mainwindow.ui 파일은 왼쪽에 QTabWidget 을 제공하여 북마크와 썸네일을 표시합니다. 오른쪽에는 파일 콘텐츠를 볼 수 있는 QScrollArea 이 있습니다.

ViewerFactory 클래스

ViewerFactory 클래스는 알려진 파일 형식에 대한 뷰어를 관리합니다. 이러한 뷰어는 플러그인으로 구현됩니다. ViewerFactory의 인스턴스가 생성되면 보기 영역과 기본 창에 대한 포인터가 생성자에게 전달됩니다:

m_factory.reset(new ViewerFactory(ui->viewArea, this));

뷰어팩토리는 생성 시 사용 가능한 모든 플러그인을 로드합니다. 로드된 플러그인, 이름, 지원되는 MIME 유형을 쿼리할 수 있는 공용 API를 제공합니다:

    using ViewerList = QList<AbstractViewer *>;
    QStringList viewerNames(bool showDefault = false) const;
    ViewerList viewers() const;
    AbstractViewer *findViewer(const QString &viewerName) const;
    AbstractViewer *defaultViewer() const;
    QStringList supportedMimeTypes() const;

viewer() 함수는 인자로 전달된 QFile 을 열기에 적합한 플러그인에 대한 포인터를 반환합니다:

m_viewer = m_factory->viewer(file);

애플리케이션 설정에 뷰어용 섹션이 포함되어 있으면 뷰어의 가상 restoreState() 함수에 전달됩니다:

void MainWindow::restoreViewerSettings()
{
    if (!m_viewer)
        return;

    QSettings settings;
    settings.beginGroup(settingsViewers);
    QByteArray viewerSettings = settings.value(m_viewer->viewerName(), QByteArray()).toByteArray();
    settings.endGroup();
    if (!viewerSettings.isEmpty())
        m_viewer->restoreState(viewerSettings);
}

그런 다음 표준 UI 에셋이 뷰어에 전달되고 메인 스크롤 영역이 뷰어의 디스플레이 위젯을 표시하도록 설정됩니다:

    m_viewer->initViewer(ui->actionBack, ui->actionForward, ui->menuHelp->menuAction(), ui->tabWidget);
    restoreViewerSettings();
    ui->scrollArea->setWidget(m_viewer->widget());
    return true;
}

AbstractViewer 클래스

AbstractViewer 는 문서를 보고, 저장하고, 인쇄할 수 있는 일반화된 API를 제공합니다. 문서와 뷰어 모두의 속성을 쿼리할 수 있습니다:

  • 문서에 콘텐츠가 있는가?
  • 문서가 수정되었는가?
  • 개요(썸네일 또는 북마크)가 지원되는가?

AbstractViewer는 파생 클래스가 기본 창에 작업과 메뉴를 만들 수 있도록 보호된 메서드를 제공합니다. 이러한 자산을 기본 창에 표시하기 위해 해당 자산은 기본 창에 부모가 됩니다. AbstractViewer는 생성한 UI 에셋을 제거하고 파기할 책임이 있습니다. QObject 에서 상속하여 신호와 슬롯을 구현합니다.

신호

void uiInitialized();

이 신호는 뷰어가 메인 창에서 UI 에셋에 대한 모든 필요한 정보를 수신한 후에 발생합니다.

void printingEnabledChanged(bool enabled);

이 신호는 문서 인쇄가 활성화 또는 비활성화될 때 발생합니다. 예를 들어 새 문서가 성공적으로 로드되었거나 모든 콘텐츠가 제거된 후에 발생합니다.

void printStatusChanged(AbstractViewer::PrintStatus status);

인쇄 프로세스를 시작한 후 이 신호는 진행 상황의 변경 사항을 알려줍니다.

void documentLoaded(const QString &fileName);

이 신호는 문서가 성공적으로 로드되었음을 애플리케이션에 알립니다.

TxtViewer 클래스

TxtViewer 는 간단한 텍스트 뷰어로, AbstractViewer를 상속합니다. 텍스트 파일 편집, 복사/잘라내기 및 붙여넣기, 인쇄 및 변경 사항 저장을 지원합니다.

JsonViewer 클래스

JsonViewerQTreeView 에 JSON 파일을 표시합니다. 내부적으로는 파일의 내용을 QJsonDocument 에 로드하고 이를 사용하여 JsonItemModel 로 사용자 정의 트리 모델을 채웁니다.

JSON 뷰어 플러그인은 QAbstractItemModel 에서 상속된 사용자 정의 항목 모델을 구현하는 방법을 보여줍니다. JsonTreeItem 클래스는 JSON 데이터를 조작하고 기본 QJsonDocument 로 다시 전파하기 위한 기본 API를 제공합니다.

JsonViewer는 문서의 최상위 객체를 탐색을 위한 북마크로 사용합니다. 다른 노드(키 및 값)를 추가 북마크로 추가하거나 북마크 목록에서 제거할 수 있습니다. QLineEdit 은 JSON 트리를 탐색하기 위한 검색 필드로 사용됩니다.

PdfViewer 클래스

PdfViewer 클래스(및 플러그인)는 PDF 뷰어 위젯 예제의 포크입니다. QScroller 을 사용하여 문서를 원활하게 넘기는 방법을 보여줍니다.

기타 관련 클래스

HoverWatcher 클래스

HoverWatcher 클래스는 위젯 위에 마우스를 올려놓으면 오버라이드 커서를 설정하고, 마우스를 떼면 복원합니다. 동일한 위젯에 대해 여러 개의 HoverWatcher 인스턴스가 생성되는 것을 방지하기 위해 위젯당 싱글톤으로 구현됩니다.

HoverWatcher는 QObject 에서 상속하고 감시하는 QWidget 을 인스턴스의 부모로 삼습니다. 이벤트 필터를 설치하여 호버 이벤트를 소비하지 않고 가로챕니다:

HoverWatcher::HoverWatcher(QWidget *watched)
    : QObject(watched), m_watched(watched)
{
    Q_ASSERT(watched);
    m_cursorShapes[Entered].emplace(Qt::OpenHandCursor);
    m_cursorShapes[MousePress].emplace(Qt::ClosedHandCursor);
    m_cursorShapes[MouseRelease].emplace(Qt::OpenHandCursor);
    // no default for Left => restore override cursor
    m_watched->installEventFilter(this);
}

HoverAction 열거형은 HoverWatcher가 반응하는 동작을 나열합니다:

    enum HoverAction {
        Entered,
        MousePress,
        MouseRelease,
        Left,
        Ignore
    };

정적 함수는 감시자를 생성하고, 특정 QWidget 에 대해 감시자의 존재를 확인하거나, 감시자를 해제합니다:

    static HoverWatcher *watcher(QWidget *watched);
    static const HoverWatcher *watcher(const QWidget *watched);
    static bool hasWatcher(QWidget *widget);
    static void dismiss(QWidget *watched);

커서 모양은 각 HoverAction에 대해 설정하거나 설정 해제할 수 있습니다. 연결된 커서 모양이 없는 경우 동작이 트리거될 때 애플리케이션의 재정의 커서가 복원됩니다.

public slots:
    void setCursorShape(HoverAction type, Qt::CursorShape shape);
    void unSetCursorShape(HoverAction type);

mouseButtons 속성은 MousePress 동작에 대해 고려할 마우스 버튼을 보유합니다:

    void setMouseButtons(Qt::MouseButtons buttons);
    void setMouseButton(Qt::MouseButton button, bool enable);

동작을 처리한 후 동작별 신호가 방출됩니다:

signals:
    void entered();
    void mousePressed();
    void mouseReleased();
    void left();

처리된 액션을 인수로 전달하는 일반 신호가 방출됩니다:

void hoverAction(HoverAction action);
최근 파일 클래스

RecentFiles 는 최근에 연 파일 목록을 관리하는 데 특화된 QStringList 입니다.

RecentFiles에는 단일 파일 또는 여러 파일을 한 번에 추가할 수 있는 슬롯이 있습니다. 경로가 존재하고 열 수 있는 파일을 가리키면 최근 파일 목록에 항목이 추가됩니다. 파일이 이미 목록에 있는 경우에는 원래 위치에서 제거되고 맨 위에 추가됩니다.

public slots:
    void addFile(const QString &fileName) { addFile(fileName, EmitPolicy::EmitWhenChanged); }
    void addFiles(const QStringList &fileNames);

파일은 이름 또는 색인을 기준으로 목록에서 제거됩니다:

    void removeFile(const QString &fileName) { removeFile(m_files.indexOf(fileName)); }
    void removeFile(qsizetype index) {removeFile(index, RemoveReason::Other); }

QSettings 에서 저장 및 복원을 구현하는 슬롯:

    void saveSettings(QSettings &settings, const QString &key) const;
    bool restoreFromSettings(QSettings &settings, const QString &key);

설정을 복원할 때 존재하지 않는 파일은 무시됩니다. maxFiles 속성은 저장할 최근 파일의 최대 용량을 보유합니다(기본값은 10개).

qsizetype maxFiles();
void setMaxFiles(qsizetype maxFiles);

RecentFiles 파일을 수락하기 전에 파일을 읽을 수 있는지 확인합니다.

최근 파일 메뉴 클래스

RecentFileMenuQMenu, 최근 파일 객체를 하위 메뉴로 표시하는 데 특화되어 있습니다.

이 클래스의 생성자는 부모 QObject 에 대한 포인터와 시각화할 콘텐츠인 RecentFiles 객체에 대한 포인터를 받습니다. 사용자가 목록에서 최근 파일을 선택하면 트리거되는 fileOpened() 신호는 파일의 절대 경로를 인수로 전달합니다.

참고: RecentFileMenu 는 부모 위젯 또는 생성자에 전달된 RecentFiles 객체에 의해 소멸됩니다.

class RecentFileMenu : public QMenu
{
    Q_OBJECT

public:
    explicit RecentFileMenu(QWidget *parent, RecentFiles *recent);

signals:
    void fileOpened(const QString &fileName);
    ...
};

예제 프로젝트 @ code.qt.io

© 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.