问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Qt框架中MDI多文档界面的开发详解

创作时间:
作者:
@小白创作中心

Qt框架中MDI多文档界面的开发详解

引用
CSDN
1.
https://blog.csdn.net/qq_74047911/article/details/139519140

Qt框架提供了MDI(多文档界面)功能,可以更方便地实现多个窗口的开发。MDI使用QMdiArea作为多个子窗体的容器,这些子窗体可以共享主窗体的工具栏和菜单栏,非常适合需要进行多个文档编辑的场景,比如类似VS的编辑界面。

应用场景

类似于VS的界面功能,工具栏的功能可以对每个文档使用。

界面设计

在MainWindow的构造函数中,将QMdiArea设置为中心组件,并将其最大化显示。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setCentralWidget(ui->mdiArea);
    setWindowState(Qt::WindowMaximized);
}

界面类设计

添加一个纯文本编辑器,并设置窗口边距。

实现功能

1. 新建文档

注意界面类设计的头文件。

2. 打开文件

打开文件的逻辑如下:

  • 如果没有窗口,就先新建一个窗口,再将文件内容写入。
  • 如果有窗口,检查是否已经写入了文件,如果已经写入就需要重新创建一个窗口,否则直接写入。
#include "formdoc.h"
#include <QMdiSubWindow>
#include <QFileDialog>
...

void MainWindow::on_actionOpen_triggered()
{
    bool needForm=false; // 是否需要新建窗口
    FormDoc*form=NULL; // 变化的指向
    if(ui->mdiArea->subWindowList().count()==0) // 如果没有窗口就要新建
    {
        needForm=true;
    }
    else // 有窗口的情况下
    {
        form=(FormDoc*)ui->mdiArea->activeSubWindow()->widget(); // 指向激活的窗口,也就是当前点击的子窗口,需要用到头文件
        if(form->fileWrite()) // 如果文件已经写入就需要重新创建一个窗口
        {
            needForm=true;
        }
    }
    // 获取文件路径名
    QString fileName=QFileDialog::getOpenFileName(this,"打开一个文件",QDir::currentPath(),
                                                  "源文件(*.h *.cpp);;文本文件(*.txt);;所有文件(*.*)");
    if(fileName.isEmpty())
    {
        return;
    }
    if(needForm)
    {
        form=new FormDoc(this); // 创建新的窗口
        ui->mdiArea->addSubWindow(form); // 添加到MDI容器
    }
    form->loadFile(fileName); // 将文件写入窗口
    form->show();
}

面向对象的思想对FormDoc窗口进行操作和读取数据。

#ifndef FORMDOC_H
#define FORMDOC_H
#include <QWidget>
namespace Ui {
class FormDoc;
}
class FormDoc : public QWidget
{
    Q_OBJECT
public:
    explicit FormDoc(QWidget *parent = nullptr);
    ~FormDoc();
    bool fileWrite(); // 文件是否写入
    void loadFile(const QString&fileName); // 写入文件到窗口
private:
    Ui::FormDoc *ui;
    bool m_fileWrite=false;
};
#endif // FORMDOC_H

函数实现:

#include <QTextStream>
#include <QFileInfo>
...
bool FormDoc::fileWrite()
{
    return this->m_fileWrite;
}
void FormDoc::loadFile(const QString&fileName)
{
    QFile file(fileName);
    if(file.open(QIODevice::ReadOnly|QIODevice::Text))
    {
        QTextStream stream(&file);
        ui->plainTextEdit->clear();
        // 读取所有的文件内容写入到窗口中
        ui->plainTextEdit->setPlainText(stream.readAll());
        file.close();
        // 设置窗口的主题
        QFileInfo fileName;
        QString name=fileName.fileName();
        this->setWindowTitle(name);
        // 写了文件,需要重新创建一个窗口
        this->m_fileWrite=true;
    }
}

3. 关闭所有

void MainWindow::on_actionCloseAll_triggered()
{
    ui->mdiArea->closeAllSubWindows();
}

4. 编辑功能

因为纯文本编辑器组件本身就有这些功能,所以我们可以用面向对象的思想在FormDoc窗口来设置接口。

void MainWindow::on_actionCut_triggered()
{
    FormDoc*form=(FormDoc*)ui->mdiArea->activeSubWindow()->widget(); // 选中的窗体
    form->cut();
}
void MainWindow::on_actionCopy_triggered()
{
    FormDoc*form=(FormDoc*)ui->mdiArea->activeSubWindow()->widget(); // 选中的窗体
    form->copy();
}
void MainWindow::on_actionPaste_triggered()
{
    FormDoc*form=(FormDoc*)ui->mdiArea->activeSubWindow()->widget(); // 选中的窗体
    form->paste();
}
void MainWindow::on_actionFont_triggered()
{
    FormDoc*form=(FormDoc*)ui->mdiArea->activeSubWindow()->widget(); // 选中的窗体
    form->setFont();
}

FormDoc.h

#ifndef FORMDOC_H
#define FORMDOC_H
#include <QWidget>
namespace Ui {
class FormDoc;
}
class FormDoc : public QWidget
{
    Q_OBJECT
public:
    explicit FormDoc(QWidget *parent = nullptr);
    ~FormDoc();
    bool fileWrite(); // 文件是否写入
    void loadFile(const QString&fileName); // 写入文件到窗口
    
    void cut();
    void copy();
    void paste();
    void setFont();
private:
    Ui::FormDoc *ui;
    bool m_fileWrite=false;
};
#endif // FORMDOC_H

FormDoc.cpp

#include "formdoc.h"
#include "ui_formdoc.h"
#include <QTextStream>
#include <QFileInfo>
#include <QFontDialog>
FormDoc::FormDoc(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::FormDoc)
{
    ui->setupUi(this);
    this->setAttribute(Qt::WA_DeleteOnClose); // 关闭窗口时同时销毁
}
FormDoc::~FormDoc()
{
    delete ui;
}
bool FormDoc::fileWrite()
{
    return this->m_fileWrite;
}
void FormDoc::loadFile(const QString&fileName)
{
    QFile file(fileName);
    if(file.open(QIODevice::ReadOnly|QIODevice::Text))
    {
        QTextStream stream(&file);
        ui->plainTextEdit->clear();
        // 读取所有的文件内容写入到窗口中
        ui->plainTextEdit->setPlainText(stream.readAll());
        file.close();
        // 设置窗口的主题
        QFileInfo fileName;
        QString name=fileName.fileName();
        this->setWindowTitle(name);
        // 写了文件,需要重新创建一个窗口
        this->m_fileWrite=true;
    }
}
void FormDoc::cut()
{
    ui->plainTextEdit->cut();
}
void FormDoc::copy()
{
    ui->plainTextEdit->copy();
}
void FormDoc::paste()
{
    ui->plainTextEdit->paste();
}
void FormDoc::setFont()
{
    bool ok;
    QFont font=ui->plainTextEdit->font();
    font=QFontDialog::getFont(&ok,font);
    ui->plainTextEdit->setFont(font);
}

5. MDI页模式

void MainWindow::on_actionMDI_triggered(bool checked)
{
    if(checked)
    {
        ui->mdiArea->setViewMode(QMdiArea::TabbedView); // 设置为页面模式
        // 页面模式不能使用展开和平铺
        ui->actionShow->setEnabled(false);
        ui->actionTile->setEnabled(false);
        ui->mdiArea->setTabsClosable(true); // 页有关闭按钮
    }
    else
    {
        ui->mdiArea->setViewMode(QMdiArea::SubWindowView); // 设置为页面模式        
        ui->actionShow->setEnabled(true);
        ui->actionTile->setEnabled(true);
        ui->mdiArea->setTabsClosable(false); // 页有关闭按钮
    }
}

6. 瀑布展开模式

void MainWindow::on_actionShow_triggered()
{
    ui->mdiArea->cascadeSubWindows();
}

7. 平铺模式

void MainWindow::on_actionTile_triggered()
{
    ui->mdiArea->tileSubWindows();
}

总结

Qt提供的MDI(多文档界面)功能可以更方便地实现多个窗口的开发。MDI使用QMdiArea作为多个子窗体的容器,这些子窗体可以共享主窗体的工具栏和菜单栏,非常适合需要进行多个文档编辑的场景,比如类似VS的编辑界面。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号