Qt 项目实战 | 多界面编辑器

Qt 项目实战 | 多界面编辑器

  • Qt 项目实战 | 多界面编辑器
    • 界面设计
    • 创建子窗口类

官方博客:https://www.yafeilinux.com/

Qt开源社区:https://www.qter.org/

参考书:《Qt 及 Qt Quick 开发实战精解》

Qt 项目实战 | 多界面编辑器

开发环境:Qt Creator 4.6.2 Based on Qt 5.9.6

在这里插入图片描述

界面设计

这里主要是对主窗口和工具栏的设计。

新建 Qt Gui 应用,项目名称 myMdi,类名默认 MainWindow,基类默认为 QMainWindow都不做改动。

添加资源文件 myImage.qrc:

在这里插入图片描述

双击 mainwindow.ui 进入设计模式,添加菜单:

在这里插入图片描述

菜单栏和工具栏:

在这里插入图片描述

文件子菜单,注意有2个分隔符:

在这里插入图片描述

编辑子菜单,注意有1个分隔符:

在这里插入图片描述

窗口子菜单,注意有2个分隔符:

在这里插入图片描述

帮助子菜单:

在这里插入图片描述

设计完菜单栏和工具栏后,向主窗口中心区域拖入一个 MDI Area 部件,并单击主窗口界面,按下 Ctrl + G,使其处于栅格布局。

在这里插入图片描述

确保 MDI Area 部件的 objectName 是 mdiArea,而文件菜单、编辑菜单、窗口菜单、帮助菜单的 objectName 分别是 menuF、menuE、menuW、menuH。

在这里插入图片描述

创建子窗口类

为了实现多文档操作,需要向 QMdiArea 中添加子窗口,我们需要子类化子窗口的中心部件。

新建C++类文件,类名为 MdiChild,基类为 QTextEdit,类型信息选择“继承自 QWidget”:

在这里插入图片描述

在 mdichild.h 添加代码:

#ifndef MDICHILD_H
#define MDICHILD_H#include <QTextEdit>
#include <QWidget>class MdiChild : public QTextEdit
{Q_OBJECT
private:QString curFile;  //当前文件路径bool isUntitled;  //作为当前文件是否被保存到硬盘的标志bool maybeSave();                              //是否需要保存void setCurrentFile(const Qstring& fileName);  //设置当前文件
protected:void closeEvent(QCloseEvent* event);  //关闭事件
public:explicit MdiChild(QWidget* parent = 0);void newFile();                            //新建文件bool loadFile(const Qstring& fileName);    //加载文件bool save();                               //保存操作bool saveAs();                             //另存为操作bool saveFile(const QString& fileName);    //保存文件QString userFriendlyCurrentFile();         //提取文件名QString currentFile() { return curFile; }  //返回当前文件路径
private slots:void documentWasModified();  //文档被更改时,窗口显示更改状态标志
};#endif  // MDICHILD_H

在 mdichild.cpp 添加代码:

#include "mdichild.h"#include <QApplication>
#include <QCloseEvent>
#include <QFile>
#include <QFileDialog>
#include <QFileInfo>
#include <QMessageBox>
#include <QPushButton>
#include <QTextStream>// 是否需要保存
bool MdiChild::maybeSave()
{// 如果文档被更改过if (document()->isModified()){QMessageBox box;box.setWindowTitle(tr("多文档编辑器"));box.setText(tr("是否保存对“%1”的更改?").arg(userFriendlyCurrentFile()));box.setIcon(QMessageBox::Warning);// 添加按钮,QMessageBox::YesRole可以表明这个按钮的行为QPushButton* yesBtn = box.addButton(tr("是(&Y)"), QMessageBox::YesRole);box.addButton(tr("否(&N)"), QMessageBox::NoRole);QPushButton* cancelBtn = box.addButton(tr("取消"), QMessageBox::RejectRole);// 弹出对话框,让用户选择是否保存修改,或者取消关闭操作box.exec();if (box.clickedButton() == yesBtn){// 如果用户选择是,则返回保存操作的结果return save();}else if (box.clickedButton() == cancelBtn){// 如果选择取消,则返回falsereturn false;}}return true;  // 如果文档没有更改过,则直接返回true
}// 设置当前文件
void MdiChild::setCurrentFile(const QString& fileName)
{// canonicalFilePath()可以除去路径中的符号链接,“.”和“..”等符号curFile = QFileInfo(fileName).canonicalFilePath();// 文件已经被保存过了isUntitled = false;// 文档没有被更改过document()->setModified(false);// 窗口不显示被更改标志setWindowModified(false);// 设置窗口标题,userFriendlyCurrentFile() 函数返回文件名setWindowTitle(userFriendlyCurrentFile() + "[*]");
}// 关闭操作,在关闭事件中执行
void MdiChild::closeEvent(QCloseEvent* event)
{if (maybeSave()){// 如果 maybeSave() 函数返回 true,则关闭窗口event->accept();}else{// 否则忽略该事件event->ignore();}
}MdiChild::MdiChild(QWidget* parent) : QTextEdit(parent)
{// 设置在子窗口关闭时销毁这个类的对象setAttribute(Qt::WA_DeleteOnClose);// 初始 isUntitled 为 trueisUntitled = true;
}// 新建文件操作
void MdiChild::newFile()
{// 设置窗口编号,因为编号一直被保存,所以需要使用静态变量static int sequenceNumber = 1;// 新建的文档没有被保存过isUntitled = true;// 将当前文件命名为未命名文档加编号,编号先使用再加 1curFile = tr("未命名文档%1.txt").arg(sequenceNumber++);// 设置窗口标题,使用[*]可以在文档被更改后在文件名称后显示“*”号setWindowTitle(curFile + "[*]" + tr(" - 多文档编辑器"));// 当文档被更改时发射 contentsChanged() 信号,执行 documentWasModified() 槽函数connect(document(), SIGNAL(contentsChanged()), this, SLOT(documentWasModified()));
}// 加载文件
bool MdiChild::loadFile(const QString& fileName)
{// 新建 QFile 对象QFile file(fileName);// 只读方式打开文件,出错则提示,并返回 falseif (!file.open(QFile::ReadOnly | QFile::Text)){QMessageBox::warning(this, tr("多文档编辑器"),tr("无法读取文件 %1:\n%2.").arg(fileName).arg(file.errorString()));return false;}// 新建文本流对象QTextStream in(&file);// 设置鼠标状态为等待状态QApplication::setOverrideCursor(Qt::WaitCursor);// 读取文件的全部文本内容,并添加到编辑器中setPlainText(in.readAll());// 恢复鼠标状态QApplication::restoreOverrideCursor();// 设置当前文件setCurrentFile(fileName);connect(document(), SIGNAL(contentsChanged()), this, SLOT(documentWasModified()));return true;
}// 保存操作
bool MdiChild::save()
{if (isUntitled){// 如果文件未被保存过,则执行另存为操作return saveAs();}else{// 否则直接保存文件return saveFile(curFile);}
}// 另存为操作
bool MdiChild::saveAs()
{// 使用文件对话框获取文件路径QString fileName = QFileDialog::getSaveFileName(this, tr("另存为"), curFile);if (fileName.isEmpty()){// 如果文件路径为空,则返回 falsereturn false;}// 否则保存文件return saveFile(fileName);
}// 保存文件
bool MdiChild::saveFile(const QString& fileName)
{QFile file(fileName);if (!file.open(QFile::WriteOnly | QFile::Text)){QMessageBox::warning(this, tr("多文档编辑器"),tr("无法写入文件 %1:\n%2.").arg(fileName).arg(file.errorString()));return false;}QTextStream out(&file);// 设置应用程序强制光标为等待旋转光标(设置鼠标状态为等待状态)QApplication::setOverrideCursor(Qt::WaitCursor);// 以纯文本文件写入out << toPlainText();// 恢复光标(恢复鼠标状态)QApplication::restoreOverrideCursor();setCurrentFile(fileName);return true;
}// 提取文件名
QString MdiChild::userFriendlyCurrentFile()
{// 从文件路径中提取文件名return QFileInfo(curFile).fileName();
}// 文档被更改时,窗口显示更改状态标志
void MdiChild::documentWasModified()
{// 根据文档的isModified()函数的返回值,判断编辑器内容是否被更改了// 如果被更改了,就要在设置了[*]号的地方显示“*”号,这里会在窗口标题中显示setWindowModified(document->isModified());
}

下面对这个类进行简单的测试。

在 mainwindow.cpp 中添加以下代码:

#include "mdichild.h"

因为程序中使用了中文,要在 main.cpp 文件中添加头文件和代码:

#include <QTextCodec>
// 解决 Qt 中文乱码问题
QTextCodec::setCodecForLocale(QTextCodec::codecForLocale());
// QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8"));

转到设计模式,在 Action Editor 中“新建文件”动作上右击,转到它的触发信号 triggered() 的槽,并更改如下:

void MainWindow::on_actionNew_triggered()
{//创建 MdiChildMdiChild* child = new MdiChild;//多文档区域添加子窗口ui->mdiArea->addSubWindow(child);//新建文件child->newFile();//显示子窗口child->show();
}

测试结果:

在这里插入图片描述

打开多个界面也没有问题。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/168615.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最新Jn建站系统2.0 已集成各类源码 【附视频安装教程】

附视频安装教程|已集成各类源码 目前已集成的网站&#xff1a; 1.发卡网(最新) 2.代刷网(无需授权) 3. 博客网(自带模板) 4.易支付(稳定版) 5.个人导航网(简洁) 6.代理查询网 7.留言网 8.匿名网 9.表白墙(最新) 10.抽奖网 11.源码站 12.z-blog博客程序 13.织梦CM…

在Word中,图片显示不全

在今天交作业的时候&#xff0c;发现了一个非常SB的事情&#xff0c;把图片复制过去显示不完全&#xff1a; 使用文心一言查看搜索了一下&#xff0c;发现可能是以下几种原因&#xff1a; 图片所在行的行高设置不正确。可以重新设置行高&#xff0c;具体步骤包括打开图片显示…

自然语言处理---RNN经典案例之构建人名分类器

1 案例介绍 关于人名分类问题&#xff1a;以一个人名为输入, 使用模型帮助判断它最有可能是来自哪一个国家的人名&#xff0c;这在某些国际化公司的业务中具有重要意义&#xff0c;在用户注册过程中&#xff0c;会根据用户填写的名字直接给他分配可能的国家或地区选项&#xff…

【C语言进阶】指针进阶(三)

指针进阶&#xff08;三&#xff09; 9.指针和数组笔试题解析10.指针笔试题 9.指针和数组笔试题解析 数组名的理解 数组名是数组首元素的地址 但是有2个例外&#xff1a; sizeof(数组名)&#xff0c;这里的数组名表示整个数组&#xff0c;sizeof(数组名)计算的是整个数组的大…

SpringMVC(三)获取请求参数

1.1通过ServletAPI获取 SpringMVC封装的就是原生的servlet 我们进行测试如下所示&#xff1a; package com.rgf.controller.service;import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.…

纺织工厂数字孪生3D可视化管理平台,推动纺织产业数字化转型

近年来&#xff0c;我国加快数字化发展战略部署&#xff0c;全面推进制造业数字化转型&#xff0c;促进数字经济与实体经济深度融合。以数字孪生、物联网、云计算、人工智能为代表的数字技术发挥重要作用。聚焦数字孪生智能工厂可视化平台&#xff0c;推动纺织制造业数字化转型…

OpenCV17-图像形态学操作

OpenCV17-图像形态学操作 1.形态学操作1.1腐蚀1.2膨胀 2.形态学应用2.1开运算2.2闭运算2.3形态学梯度2.4顶帽运算2.5黑帽运算2.6击中击不中变换2.7形态学应用示例 1.形态学操作 1.1腐蚀 图像腐蚀&#xff08;Image erosion&#xff09;可用于减小图像中物体的大小、填充孔洞或…

css之Flex弹性布局(子项常见属性)

文章目录 &#x1f380;前言&#xff1a;本篇博客介绍弹性布局flex容器中子项的常见用法&#x1fa80;flex:子项目占得份数 &#xff08;划分不同子项的比例&#xff09;&#x1f387;align-self 控制单独一个子项在侧轴的排列方式&#x1f9f8;order属性定义子项的排列顺序 &a…

酷开科技 | 酷开系统,为居家生活打开更精彩的窗口

电视在我们的日常生活中扮演着重要的角色。虽然&#xff0c;作为客厅C位的扛把子——电视的娱乐作用深入人心&#xff0c;但是&#xff0c;它的涵义和影响力却因我们每个人的具体生活环境而存在着种种差异&#xff0c;而我们的生活环境又受到我们所处的社会及文化环境的影响。 …

一文了解AIGC与ChatGPT

一、AIGC简介 1.AIGC基础 (1)AIGC是什么 AIGC是人工智能图形计算的缩写&#xff0c;是一种基于图形处理器&#xff08;GPU&#xff09;的计算技术&#xff0c;可以加速各种计算任务&#xff0c;包括机器学习、深度学习、计算机视觉等。 AIGC是一种基于GPU的计算技术&#x…

Git(一)Windows下安装及使用Git Bash

目录 一、简介1.1 什么是Git&#xff1f;1.2 Git 的主要特点1.3 什么是 Git Bash&#xff1f; 二、下载三、安装3.1 同意协议3.2 选择安装位置3.3 其他配置&#xff08;【Next】 即可&#xff09;3.4 安装完毕3.5 打开 Git Bash 官网地址&#xff1a; https://www.git-scm.com/…

包管理工具

代码共享方案 放到npm仓库&#xff0c;下载到本地放到node_modules npm配置文件 必须填写的属性&#xff1a;name、version name是项目的名称&#xff1b; version是当前项目的版本号&#xff1b; description是描述信息&#xff0c;很多时候是作为项目的基本描述&#xff1b…

力扣每日一题61:旋转链表

题目描述&#xff1a; 给你一个链表的头节点 head &#xff0c;旋转链表&#xff0c;将链表每个节点向右移动 k 个位置。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], k 2 输出&#xff1a;[4,5,1,2,3]示例 2&#xff1a; 输入&#xff1a;head [0,1,2], k 4 输…

CSS必学:你需要知道的盒子模型的秘密

作者:WangMin 格言:努力做好自己喜欢的每一件事 CSDN原创文章 博客地址 &#x1f449; WangMin 作为前端开发来说&#xff0c;要掌握的CSS基础一定很多&#xff0c;那么CSS中盒子模型肯定是必考必问必掌握的前端知识点&#xff0c;因为它是CSS基础中非常重要的内容&#xff0c;…

异步编程详解(.NET)

在之前写的一篇关于async和await的前世今生的文章之后&#xff0c;大家似乎在async和await提高网站处理能力方面还有一些疑问&#xff0c;很多网站本身也做了不少的尝试。今天我们再来回答一下这个问题&#xff0c;同时我会做一个async和await在WinForm中的尝试&#xff0c;并且…

Java SOAP 调用 C# 的WebService

Java SOAP 调用 C# 的WebService&#xff0c;C# 的WebService方法的创建可以参考上一篇文章。IntelliJ IDEA Community Edition 2021.2.3的idea64.exe新建项目&#xff0c;导入需要的jar&#xff0c;代码如下&#xff1a; import org.apache.axis.client.Service; import org.…

循环神经网络(Recurrent Neural Network)

1. 为什么需要循环神经网络 RNN 上图是一幅全连接神经网络图&#xff0c;我们可以看到输入层-隐藏层-输出层&#xff0c;他们每一层之间是相互独立地&#xff0c;(框框里面代表同一层)&#xff0c;每一次输入生成一个节点&#xff0c;同一层中每个节点之间又相互独立的话&#…

PKU 概率论+数理统计+建模 期中考复习总结

目录 计算条件概率计算概率&#xff08;放回与不放回&#xff09;生成随机数算法Linear Congruential Method判断是否是full period Uniformity (test of frequency)1.Chi-Square testmethodreminderexample 2.Kolmogorov-Sminov testmethodexample Independence (test of auto…

互联网Java工程师面试题·Spring篇·第一弹

目录 1、一般问题 1.1、不同版本的 Spring Framework 有哪些主要功能&#xff1f; 1.2、什么是 Spring Framework&#xff1f; 1.3、列举 Spring Framework 的优点。 1.4、Spring Framework 有哪些不同的功能&#xff1f; 1.5、Spring Framework 中有多少个模块&#xff…

JSX 模板精简原则

学习目标&#xff1a; 使模板中的逻辑跟简洁 实现&#xff1a; 复杂的多分枝的逻辑收敛为一个函数&#xff0c;通过一个专门的函数来写分支逻辑&#xff0c;模板中只负责调用 实例&#xff1a; // 有一个状态type有1&#xff0c;2&#xff0c;3三种 // 1 展示 h1 // 2 展示 h2…