传统的应用程序设计中有多文档界面(Multi-document Interface,MDI)应用程序,Qt 为设计 MDI 应用程序提供了支持。

本节的实例 samp6_4 是一个 MDI 应用程序,程序运行效果如图 1 所示。


图 1 MDI 应用程序实例 samp6_4 的运行时界面

MDI 应用程序就是在主窗口里创建多个同类型的 MDI 子窗口,这些 MDI 子窗口在主窗口里显示,并共享主窗口上的工具栏和菜单等操作功能,主窗口上的操作都针对当前活动的 MDI 子窗口进行。

设计 MDI 应用程序需要在主窗口工作区放置一个 QMdiArea 作为子窗体的容器。实例 samp6_4 主窗口的工作区使用一个 QMdiArea 组件,实例的子窗口类是 QFormDoc,是一个使用 QPlainTextEdit 进行简单文本显示和编辑的窗体。

创建的 QFormDoc 窗体对象作为一个子窗口加入到 mdiArea 组件中。QMdiArea 组件类似于实例 samp6_3 中主窗口上的 tabWidget 组件,只是 QMdiArea 提供更加完备的功能。更改 MDI 的显示模式,可以得到与实例 samp6_3 相似的以多页组件管理的 MDI 界面效果。

文档窗口类QFormDoc的设计

以可视化方式创建一个基于 QWidget 的类 QFormDoc,设计可视化界面时,只放置一个 QPlainTextEdit 组件,并以水平布局填充满整个窗口。这里不再用可视化的方式设计 Action,因为 QFormDoc 窗口不需要创建自己的工具栏,而是使用主窗口上的工具栏按钮对 QFormDoc 窗体上的 QPlainTextEdit 组件进行操作。

为 QFormDoc 添加一些用于文件打开和编辑操作的接口函数,QFormDoc 类的完整定义如下:

class QFormDoc : public QWidget
{Q_OBJECT
private:QString mCurrentFile; //当前文件bool    mFileOpened=false; //文件已打开
public:explicit QFormDoc(QWidget *parent = 0);~QFormDoc();void    loadFromFile(QString& aFileName); //打开文件QString currentFileName();//返回当前文件名bool    isFileOpened();//文件已经打开void    setEditFont();//设置字体void    textCut(); //cutvoid    textCopy(); //copyvoid    textPaste(); //paste
private:Ui::QFormDoc *ui;
};

这些接口函数是为了在主窗口里调用,实现对 MDI 子窗口的操作。实现代码如下:

QFormDoc::QFormDoc(QWidget *parent) :QWidget(parent),ui(new Ui::QFormDoc)
{ui->setupUi(this);this->setWindowTitle("New Doc"); //窗口标题this->setAttribute(Qt::WA_DeleteOnClose); //关闭时自动删除
}
QFormDoc::~QFormDoc()
{//QMessageBox::information(this,"信息","文档窗口被释放");delete ui;
}
void QFormDoc::loadFromFile(QString &aFileName)
{//打开文件QFile aFile(aFileName);  //以文件方式读出if (aFile.open(QIODevice::ReadOnly | QIODevice::Text)) //以只读文本方式打开文件{QTextStream aStream(&aFile); //用文本流读取文件ui->plainTextEdit->clear();//清空ui->plainTextEdit->setPlainText(aStream.readAll()); //读取文本文件aFile.close();//关闭文件mCurrentFile=aFileName;//保存当前文件名QFileInfo fileInfo(aFileName); //文件信息QString str=fileInfo.fileName(); //去除路径后的文件名this->setWindowTitle(str);mFileOpened=true;}
}
QString QFormDoc::currentFileName()
{return  mCurrentFile;
}
bool QFormDoc::isFileOpened()
{ //文件是否已打开return mFileOpened;
}
void QFormDoc::setEditFont()
{QFont   font;font=ui->plainTextEdit->font();bool    ok;font=QFontDialog::getFont(&ok,font);ui->plainTextEdit->setFont(font);
}
void QFormDoc::textCut()
{ui->plainTextEdit->cut();
}
void QFormDoc::textCopy()
{ui->plainTextEdit->copy();
}
void QFormDoc::textPaste()
{ui->plainTextEdit->paste();
}

注意作为 MDI 子窗口,不管其是否设置为关闭时删除,在主窗口里关闭一个 MDI 子窗口时,都会删除子窗口对象。

MDI 主窗口设计与子窗口的使用

主窗口界面设计

要在主窗口实现 MDI 功能,只需在主窗口的工作区放置一个 QMdiArea 组件。图 2 是设计好的主窗口界面。


图 2 设计时的主窗口

在 UI 设计器里创建 Action,并应用 Action 设计主工具栏。在主窗口的工作区放置一个 QMdiArea 组件,然后在主窗口的构造函数里设置 mdiArea 填充满工作区。

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

MDI 子窗口的创建与加入

下面是主窗口上“新建文档”按钮的响应代码:

void QWMainWindow::on_actDoc_New_triggered()
{ //新建文档QFormDoc *formDoc = new QFormDoc(this);ui->mdiArea->addSubWindow (formDoc) ; //文档窗口添力口到 MDI formDoc->show();
}

代码功能是新建一个 QFormDoc 类的窗口 formDoc,构造函数中传入了主窗口指针,所以主窗口是 formDoc 的父窗口,然后使用 QMdiArea 的 addSubWindow() 函数将 formDoc 加入到 mdiArea。

下面是主窗口上“打开文档”按钮的响应代码:

void QWMainWindow::on_actDoc_Open_triggered()
{//打开文件
//必须先获取当前MDI子窗口,再使用打开文件对话框,否则无法获得活动的子窗口bool needNew=false;// 是否需要新建子窗口QFormDoc    *formDoc;if (ui->mdiArea->subWindowList().count()>0) //如果有打开的主窗口,获取活动窗口{formDoc=(QFormDoc*)ui->mdiArea->activeSubWindow()->widget();needNew=formDoc->isFileOpened();//文件已经打开,需要新建窗口}elseneedNew=true;QString curPath=QDir::currentPath();QString aFileName=QFileDialog::getOpenFileName(this,tr("打开一个文件"),curPath,"C程序文件(*.h *cpp);;文本文件(*.txt);;所有文件(*.*)");if (aFileName.isEmpty())return; //如果未选择文件,退出if (needNew) //需要新建子窗口{formDoc = new QFormDoc(this);//指定父窗口,必须在父窗口为Widget窗口提供一个显示区域ui->mdiArea->addSubWindow(formDoc);}formDoc->loadFromFile(aFileName); //打开文件formDoc->show();ui->actCut->setEnabled(true);ui->actCopy->setEnabled(true);ui->actPaste->setEnabled(true);ui->actFont->setEnabled(true);
}

通过 QMdiArea::subWindowList() 可以获得子窗口对象列表,从而可以判断子窗口的个数。如果没有一个MDI子窗口,就创建一个新的窗口并打开文件。

如果有 MDI 子窗口,则总有一个活动窗口,通过 QMdiArea::activeSubWindow() 可以获得此活动的子窗口,通过子窗口的 isFileOpened() 函数判断是否打开了文件,如果没有打开过文件,就在这个活动窗口里打开文件,否则新建窗口打开文件。

注意一定要先获取 MDI 子窗口,再使用 QFileDialog 选择需要打开的文件。如果顺序更换了,则无法获得正确的 MDI 活动子窗口。

QMdiArea常用功能函数

QMdiArea 提供了一些成员函数,可以进行一些操作,工具栏上的“关闭全部”、“MDI模式”、“级联展开”、“平铺展开”等按钮都是调用 QMdiArea 类的成员函数实现的。

下面是这几个按钮功能的实现代码:

void QWMainWindow::on_actCascade_triggered()
{ //窗口级联展开ui->mdiArea->cascadeSubWindows();
}
void QWMainWindow::on_actTile_triggered()
{//平铺展开ui->mdiArea->tileSubWindows();
}
void QWMainWindow::on_actCloseALL_triggered()
{//关闭全部子窗口ui->mdiArea->closeAllSubWindows();
}
void QWMainWindow::on_actViewMode_triggered(bool checked)
{//MDI 显示模式if (checked) //Tab多页显示模式{ui->mdiArea->setViewMode(QMdiArea::TabbedView); //Tab多页显示模式ui->mdiArea->setTabsClosable(true); //页面可关闭ui->actCascade->setEnabled(false);ui->actTile->setEnabled(false);}else 子窗口模式{ui->mdiArea->setViewMode(QMdiArea::SubWindowView); //子窗口模式ui->actCascade->setEnabled(true); //ui->actTile->setEnabled(true); //}
}

其中,设置 MDI 视图模式用 setViewMode() 函数,有两种模式可以选择:

  1. QMdiArea::Sub Window View 是传统的子窗口模式,显不效果如图 1 所示。
  2. QMdiArea::TabbedView 是多页的显示模式,显示效果如图 3 所示。


图 3 多页模式下 MDI 界面

MDI的信号

QMdiArea 有一个信号 subWindowActivated(QMdiSubWindow *argl),在当前活动窗口切换时发射,利用此信号可以在活动窗口切换时进行一些处理,例如,在状态栏里显示活动 MDI 子窗口的文件名,在没有 MDI 子窗口时,将工具栏上的编辑功能按钮设置为禁用。

下面是该信号的槽函数代码:

void QWMainWindow::on_mdiArea_subWindowActivated(QMdiSubWindow *arg1)
{//当前活动子窗口切换时if (ui->mdiArea->subWindowList().count()==0){ //若子窗口个数为零ui->actCut->setEnabled(false);ui->actCopy->setEnabled(false);ui->actPaste->setEnabled(false);ui->actFont->setEnabled(false);ui->statusBar->clearMessage();}else{QFormDoc *formDoc=static_cast<QFormDoc*>(ui->mdiArea->activeSubWindow()->widget());ui->statusBar->showMessage(formDoc->currentFileName()); //显示主窗口的文件名}
}

主窗口工具栏上的“剪切”、“复制”、“粘贴”、“字体设置”等按钮都是调用当前子窗口的相应函数,关键是获取当前 MDI 子窗体对象。

例如,“剪切”和“字体设置”按钮的代码如下:

void QWMainWindow::on_actCut_triggered()
{ //cutQFormDoc* formDoc=(QFormDoc*)ui->mdiArea->activeSubWindow()->widget();formDoc->textCut();
}
void QWMainWindow::on_actFont_triggered()
{//设置字体QFormDoc* formDoc=(QFormDoc*)ui->mdiArea->activeSubWindow()->widget();formDoc->setEditFont();
}

Qt MDI及其使用方法相关推荐

  1. python界面设计资源库_python GUI库图形界面开发之PyQt5 Qt Designer工具(Qt设计师)详细使用方法及Designer ui文件转py文件方法...

    PyQt5 Qt Designer (Qt设计师) PyQt5是对Qt所有类进行封装, Qt能开发的东西, PyQt都能开发. Qt是强大的GUI库之一, 用C++开发, 并且跨平台. PyQt双许可 ...

  2. Qt Creator用户互动方法

    Qt Creator用户互动方法 用户互动方法 基本互动方法 鼠标区域 重点范围 可轻弹 常规控制属性 按钮控制 按钮 延迟按钮 复选框 单选按钮 转变 圆形按钮 显示文字和图标 检查按钮 按钮信号 ...

  3. Qt程序打包发布方法(使用官方提供的windeployqt工具)

    Qt程序打包发布方法(使用官方提供的windeployqt工具) 转自:http://tieba.baidu.com/p/3730103947?qq-pf-to=pcqq.group Qt 官方开发环 ...

  4. MDI窗体简单方法(调用,闪屏)

    MDI窗体简单方法(调用,闪屏) 调用方式: RibbonForm mdishow = new RibbonForm(); //实例化midshow.MdiParent = this; //设置在主窗 ...

  5. Qt | QTableView的使用方法

    Qt | QTableView的使用方法 QTableView的数据是基于model显示的,需要先建一个model,然后tableView通过setModel进行模型绑定,后续操作model就可以实现 ...

  6. Qt程序打包发布方法(使用官方提供的windeployqt工具) 转自:http://tieba.baidu.com/p/3730103947?qq-pf-to=pcqq.group Qt 官方

    Qt程序打包发布方法(使用官方提供的windeployqt工具) 转自:http://tieba.baidu.com/p/3730103947?qq-pf-to=pcqq.group Qt 官方开发环 ...

  7. WPF实现MDI窗体的方法

    WPF实现MDI窗体的方法 原文:WPF实现MDI窗体的方法 第一:新建一个类(Class) Win32Native.cs 代码如下: using System;  using System.Coll ...

  8. Qt控件使用方法技巧合集

    Qt控件使用方法技巧合集 ~~~~~~~~        本篇博客代码示例包含C++版本和Python版本,不管是哪个版本,Qt的API都是一样的,使用方式大同小异. 文章目录 Qt控件使用方法技巧合 ...

  9. QT 圆形头像绘制方法

    QT 圆形头像绘制方法 目标效果: 方法一: 将目标图像转换成圆形.根据图像得到圆形的Pixmap,再将pixmap绘制到label上. 这种方法的优点是不必在意绘制的label的形状是什么.相当于目 ...

  10. Qt实用技巧:VS2017编写纯C库以及使用Qt调用C库方法

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

最新文章

  1. 【JQuery】可直接编辑的表格
  2. ICML2021 | 自提升策略规划真实且可执行的分子逆合成路线
  3. matlab、python使用小方法收集
  4. 毕业5年,我是怎么成为年薪30W的运维工程师
  5. 注意我写的OTA短信同步设置的代码有很多问题
  6. Android 7.0 Nougat介绍
  7. 快捷键关机电脑_技巧 | 如何知道电脑多久没关机?一个命令就行嘞!
  8. sparksql 操作hive_Spark SQL 物化视图原理与实践
  9. R工程化—Rest API 之plumber包
  10. JSTL—fn使用方法总结
  11. C程序设计--结构体(结构体和函数之间的参数使用)
  12. android 看视频播放器下载,想看视频播放器
  13. Flash动画短片制作流程注意点
  14. Deepfacelab 新手教程(转载)
  15. 如何快速进行十进制二进制转换
  16. 从“网易邮箱被黑”看网页游戏账号安全
  17. 仿掌阅实现书籍打开动画
  18. 使用hotspot/cpuperf进行CPU占用分析
  19. 移动互联网四个特点:移动性、私密性、局限性、强关联性
  20. 微信小程序 web-view 在ios显示空白页面

热门文章

  1. xgene:之ROC曲线、ctDNA、small-RNA seq、甲基化seq、单细胞DNA, mRNA
  2. HDU - 6070 线段树 + 分数规划
  3. 鲁棒性的含义以及如何提高模型的鲁棒性
  4. 独角兽公司超级创始人早期的30个特质
  5. 顺序表的类型定义与基本操作
  6. Qt连接MySql驱动加载失败问题解决方法
  7. 电子邮件营销的十大技巧
  8. 多个图片合成PDF文件
  9. 【基础入门题048】骰子游戏(一)
  10. 实现LAYERED窗口