QT 写一个属于自己的消息弹窗MessageBox
Posted cpp_learners
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QT 写一个属于自己的消息弹窗MessageBox相关的知识,希望对你有一定的参考价值。
前言
在接触公司的一个桌面应用项目后,发现里面很多窗体都是自己写的而不是使用QT自带的,例如消息弹窗。今天这篇博客就记录下来如何自己写一个消息弹窗。
内容可能有点多,但都是本人自己一步一步操作后,测试可行后才记录下博客这里来的,希望对看到这篇博客的朋友有所帮助!
由于我是在centos7使用QT编写的代码,操作步骤或者界面什么的可能与Window使用QT会有些不一样,但是都是类似的。
下面是一部分运行截图:
我写的整个项目,将上传 csdn 和 百度网盘 后,放在下面 总结 处,需要的朋友自提!
项目所用到的资源文件也一起上传。
目录
一、创建消息窗体
首先得有一个主窗体,自己先手动创建一个QT项目,创建后如下:
然后根据下图指引,在创建一个子窗体,用做消息弹窗:
-
右键选择Add New…
-
选择Qt设计师界面类
-
选择Widget
-
可以适当修改一下名字
-
到此,窗体就创建好了
-
添加资源文件
将资源文件夹msgbox放到项目路径下
1). 右键选择Add New…
2). 选择Qt Resource File
3). 可以设当修改名字
4). 再出现的页面中,下面点击 添加 - 添加前缀
5). 此时前缀这里会出现一些字符串,删掉剩下一个反斜杠即可
6). 点击 添加 - 添加文件
7). 再出现的弹窗中全选文件,点击右上角Open添加进来
8). 添加进来是这样着的,记得 Ctrl + s 保存一下
到了这样,说明资源文件已经添加进来了!
也可以添加自己喜欢的图片、资源进来设置!
二、设置消息弹窗
-
双击MessageBox.ui进入设计师界面,将宽度设置为400,高度设置为150.
-
窗体设置样式
右键对象,选择改变样式表…
将样式设置为:background:rgb(255,255,255); border:1px solid rgba(110, 123, 146, 1);
-
拖动两个Widget
托两个Widget到窗体上:
1). 第一个widget设置宽度400,高度30,x为0,y为0;修改对象名为:widget_1
2). 第二个widget设置宽度400,高度120,x为0,y为30;修改对象名为:widget_2
-
给两个Widget添加标签和按钮
1). widget_1
设置widget_1样式为:
background-image: url(:/msgbox/title_bg.png);
拖一个Label:设置宽度90,高度20,x为10,y为5;修改对象名为:label_title;文本修改为:提示
设置label_title样式为:
border:0;color: rgb(255, 255, 255); background:transparent;
拖一个PushButton:设置宽度18,高度18,x为375,y为6;修改对象名为:btn_close;删掉文本
设置btn_close样式为:
border:0px; background:transparent; background-image: url(:/msgbox/close_normal.png);
2). widget_2
设置widget_2样式为:
background:transparent; background-color: rgb(255, 255, 255);
拖一个Label:设置宽度32,高度32,x为40,y为30;修改对象名为:label_icon;删掉文本
设置label_icon样式为:
border:0; background:transparent; background-image: url(:/msgbox/tips_icon.png);
拖一个Label:设置宽度291,高度41,x为80,y为30;修改对象名为:label_tips;文本可随意设置
设置label_tips样式为:
border:0; background:transparent; color: rgb(51, 51, 51);
拖一个PushButton:设置宽度70,高度30,x为200,y为80;修改对象名为:btn_confirm;文本修改为:是
设置btn_confirm样式为:
border:0; background:transparent; background-image: url(:/msgbox/confirm_normal.png);
拖一个PushButton:设置宽度70,高度30,x为290,y为80;修改对象名为:btn_cancel;文本修改为:否
设置btn_cancel样式为:
border:0; background:transparent; background-image: url(:/msgbox/cancel_normal.png);
根据上面设置完成后,效果如下:
注意自己添加资源文件的路径,路径不对,是无法设置图片的!
具体坐标,大小,可以自己根据具体情况而设置!
三、编写代码
严格按照步骤完成上面的操作后,下面我们可以开始写代码了。
-
首先在MessageBox.h文件中添加两个结构体:
// 设在按钮个数 enum MSG_TYPE SA_OK = 0, // 只有一个“确定”按钮,且两秒钟后自动关闭消息窗口 SA_OKCANCEL = 1, // 一个“是”按钮,一个“否”按钮 SA_OKS = 2 // 只有一个“确定”按钮,不会自动关闭消息窗口 ; // 设在提示的类型 enum MSG_TIP_TYPE SA_SUCCESS = 0, // 完成 SA_FAILED = 1, // 错误 SA_WARNING = 2, // 警告 SA_TIPS = 3, // 提示 SA_QUESTION = 4 // 未知 ;
-
添加头文件 #include < QDialog >
并将MessageBox的基础修改为 class MessageBox : public QDialog ;在构造函数中添加两个参数:
MessageBox(QWidget *parent = nullptr, MSG_TYPE nType = SA_OKCANCEL, MSG_TIP_TYPE nTipType = SA_TIPS);
定义两个私有成员变量,用于接收构造函数传过来的两个参数:
private: int m_nType; int m_nTipType;
实现构造函数:
MessageBox::MessageBox(QWidget *parent, MSG_TYPE nType, MSG_TIP_TYPE nTipType) : QDialog(parent), ui(new Ui::MessageBox) ui->setupUi(this); m_nType = nType; m_nTipType = nTipType; setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); // 设置窗体关闭时自动释放内存 this->setAttribute(Qt::WA_DeleteOnClose); // 设在按钮 if(MSG_TYPE::SA_OK == m_nType) ui->btn_cancel->setVisible(false); // 隐藏“否”按钮 ui->btn_confirm->setText("确定"); else if(MSG_TYPE::SA_OKCANCEL == m_nType) ui->btn_cancel->setVisible(true); // 显示“否”按钮 ui->btn_confirm->setText("是"); else if (MSG_TYPE::SA_OKS == m_nType) ui->btn_cancel->setVisible(false); // 隐藏“否”按钮 ui->btn_confirm->setText("确定"); // 设在两个按钮样式,这样设在效果:当鼠标移动到按钮上方,会切换对应设在的图片,移开后又会设在回来 QString strStyle = "QPushButtonborder:0;background:transparent;background-image: url(:/msgbox/cancel_normal.png);" "QPushButton:hoverborder:0;background:transparent;background-image: url(:/msgbox/cancel_hover.png);"; ui->btn_cancel->setStyleSheet(strStyle); strStyle = "QPushButtonborder:0;background:transparent;background-image: url(:/msgbox/confirm_normal.png);" "QPushButton:hoverborder:0;background:transparent;background-image: url(:/msgbox/confirm_hover.png);"; ui->btn_confirm->setStyleSheet(strStyle); // 根据参数,设在当前消息弹窗需要显示的图片(显示类型) if(SA_SUCCESS == m_nTipType) strStyle = "QLabelborder:0;background:transparent;background-image: url(:/msgbox/success_icon.png);"; else if (SA_FAILED == m_nTipType) strStyle = "QLabelborder:0;background:transparent;background-image: url(:/msgbox/error_icon.png);"; else if (SA_WARNING == m_nTipType) strStyle = "QLabelborder:0;background:transparent;background-image: url(:/msgbox/warning_icon.png);"; else if (SA_TIPS == m_nTipType) strStyle = "QLabelborder:0;background:transparent;background-image: url(:/msgbox/tips_icon.png);"; else if (SA_QUESTION == m_nTipType) strStyle = "QLabelborder:0;background:transparent;background-image: url(:/msgbox/question_icon.png);"; ui->label_icon->setStyleSheet(strStyle);
也就是设置按钮个数和设置现实的图片!
-
实现按钮的槽函数
private slots: void on_btn_close_clicked(); // “叉”按钮槽函数 void on_btn_confirm_clicked(); // “是”按钮槽函数 void on_btn_cancel_clicked(); // “否”按钮槽函数 void MessageBox::on_btn_close_clicked() // .exec()结束后返回0 done(0); this->close(); void MessageBox::on_btn_confirm_clicked() // .exec()结束后返回1 done(1); this->close(); void MessageBox::on_btn_cancel_clicked() // .exec()结束后返回0 done(0); this->close();
当实现到这一步,说明已经自己写的messagebox可以运行了!
-
测试MessageBox
在maindow的构造函数函数中写下代码:MessageBox *messagebox = new MessageBox(this); messagebox->exec();
运行后效果,感觉还可以喔,慢慢的成就感!
但是还不全面,还有很多地方要优化,例如设置成一个按钮时,两秒后自动关闭窗体的功能还没有写;还有这个窗体不能移动;还有提示语还不能设置;下面将开始优化!
四、优化代码
1).窗体移动
在MessageBox.h文件中:
-
添加头文件
添加头文件:#include < QPoint >、#include < QMouseEvent > -
添加私有变量:
private: QPoint m_pMousePoint; bool m_bMousePressed;
-
重写鼠标移动事件方法
protected: void mouseMoveEvent(QMouseEvent *event) override; // 鼠标移动 void mousePressEvent(QMouseEvent *event) override; // 鼠标按下 void mouseReleaseEvent(QMouseEvent *event) override; // 鼠标释放 void MessageBox::mouseMoveEvent(QMouseEvent *event) // 如果鼠标是按下的 if(m_bMousePressed) // 移动窗体 move(event->pos() - m_pMousePoint + pos()); void MessageBox::mousePressEvent(QMouseEvent *event) // 鼠标左键按下 if(event->button() == Qt::LeftButton) // 标志设置true m_bMousePressed = true; // 获取当前窗体位置 m_pMousePoint = event->pos(); void MessageBox::mouseReleaseEvent(QMouseEvent *event) // 鼠标左键释放(松开) if(event->button() == Qt::LeftButton) // 鼠标松开,标志设在false m_bMousePressed = false;
-
不出意外的话,到这一步,窗体已经可以移动了,赶快去试试吧!
2). 设置消息弹窗提示语
在MessageBox.h文件中:
-
添加公共方法:
public: void SetTips(const std::string& strTips);
-
实现它设置提示语
void MessageBox::SetTips(const std::string &strTips) ui->label_tips->setText(strTips.c_str());
-
测试
在maindow的构造函数中添加代码:MessageBox *messagebox = new MessageBox(this); messagebox->SetTips("你好,测试提示语!"); messagebox->exec();
可以发现,已经可以设置提示语了!
3). 两秒后自动关闭窗体
在MessageBox.h文件中:
-
添加头文件
添加头文件:#include < thread >、#include < unistd.h > -
添加私有变量:
private: std::thread *t1; // C++线程
并在构造函数的最上方进行初始化:
t1 = nullptr;
一定要在构造函数里的最上方进行初始化,否则接下来的操作会导致软件崩溃! -
添加两个私有成员方法
一个用来定义线程,一个用来被线程执行private: // 设在sec秒后关闭窗体 void _startTimerClose(int sec = 2); // 线程执行的函数,用于计时关闭窗体 void ticktack(int sec = 2);
实现这两个私有成员方法
void MessageBox::_startTimerClose(int sec) if (t1) delete t1; t1 = nullptr; // 定义线程 t1 = new std::thread(&MessageBox::ticktack, this, sec); t1->detach(); void MessageBox::ticktack(int sec) int secTicktack = 0; while (false == this->isHidden()) // 如果窗体是显示的 // 判断秒数相等,则关闭窗体 if (secTicktack == sec) done(1); this->close(); break; sleep(1); // Sleep(1); secTicktack++; printf("%d - ticktack = %d\\n", sec, secTicktack);
-
重写窗体显示事件方法
protected: // 窗体show前的事件操作 void showEvent(QShowEvent *) override; void MessageBox::showEvent(QShowEvent *) // 判断窗体类型,启动线程计时关闭窗体 if(MSG_TYPE::SA_OK == m_nType) _startTimerClose(2);
-
析构函数
在析构函数中释放线程内存MessageBox::~MessageBox() if (t1) delete t1; delete ui;
好了,到了这里,代码已经写完了,可以去测试了,不出意外的话,只要设置的是MSG_TYPE::SA_OK类型的提示窗体,那么,两秒后就会自动关闭窗体!
测试代码:
MessageBox *messagebox = new MessageBox(this, MSG_TYPE::SA_OK, MSG_TIP_TYPE::SA_SUCCESS);
messagebox->SetTips("你好,测试提示语!");
messagebox->exec();
题外话,可以使用线程池进行操作:(两秒后关闭窗体)
std::shared_ptr<ThreadPoolEx> m_pThreadPools;
m_pThreadPools = std::make_shared<ThreadPoolEx>(1);
m_pThreadPools->enqueue([=]()sleep(2); close(););
在构造函数隐藏按钮的if判断里加上上面两行代码即可
五、封装调用
接下来,调用代码封装成一个函数,方便调用!
在mainwindow中添加方法:
public:
int ShowMsgBox(const std::string strTips, MSG_TYPE nType, const MSG_TIP_TYPE nTipType);
实现该方法:
int MainWindow::ShowMsgBox(const std::string strTips, MSG_TYPE nType, const MSG_TIP_TYPE nTipType)
MessageBox* pMsgBox = new MessageBox(nullptr, nType, nTipType); // 定义指针,不需要手动释放内存,因为我们设置了窗体关闭时自动释放内存
pMsgBox->SetTips(strTips.c_str()); // 设置提示语
pMsgBox->setModal(true); // 设置为模态
int nRes = pMsgBox->exec(); // 运行
return nRes; // 返回值
简单测试:
int res = ShowMsgBox("实现了代码封装,调用起来更加简单了!", MSG_TYPE::SA_OKCANCEL, MSG_TIP_TYPE::SA_FAILED);
已经完美的调用了,看起来还不错喔,哈哈!
六、返回值
这里再说一下返回值。
代码中,我们设置了,只有点击“是”按钮,或者“确定”按钮,或者两秒后自动关闭窗体才会返回1,其他情况都是返回0!
根据这个特性,我们就可以进行具体判断使用了!
例如:
int res = ShowMsgBox("您却要退出程序吗?", MSG_TYPE::SA_OKCANCEL, MSG_TIP_TYPE::SA_QUESTION);
if (res == 1)
printf("退出程序!\\n");
else
printf("返回值:%d\\n", res);
当点击"是":
当点击"否":
七、MessageBox代码
-
MessageBox.h
#ifndef MESSAGEBOX_H #define MESSAGEBOX_H #include <QDialog> #include <QPoint> #include <QMouseEvent> #include <thread> #include <unistd.h> namespace Ui class MessageBox; // 设在按钮个数 enum MSG_TYPE SA_OK = 0, // 只有一个“确定”按钮,且两秒钟后自动关闭消息窗口 SA_OKCANCEL = 1, // 一个“是”按钮,一个“否”按钮 SA_OKS = 2 // 只有一个“确定”按钮,不会自动关闭消息窗口 ; // 设在提示的类型 enum MSG_TIP_TYPE SA_SUCCESS = 0, // 完成 SA_FAILED = 1, // 错误 SA_WARNING = 2, // 警告 SA_TIPS = 3, // 提示 SA_QUESTION = 4 // 未知 ; class MessageBox : public QDialog Q_OBJECT public: explicit MessageBox(QWidget *parent = nullptr,MSG_TYPE nType = SA_OKCANCEL,MSG_TIP_TYPE nTipType = SA_TIPS); ~MessageBox(); // 设置提示语 void SetTips(const std::string& strTips); private: // 设在sec秒后关闭窗体 void _startTimerClose(int sec = 2); // 线程执行的函数,用于计时关闭窗体 void ticktack(int sec = 2); private slots: void on_btn_close_clicked(); // “叉”按钮槽函数 void on_btn_confirm_clicked(); // “是”按钮槽函数 void on_btn_cancel_clicked(); // “否”按钮槽函数 protected: void mouseMoveEvent(QMouseEvent *event) override; // 鼠标移动 void mousePressEvent(QMouseEvent *event) override; // 鼠标按下 void mouseReleaseEvent(QMouseEvent *event) override; // 鼠标释放 // 窗体show前的事件操作 void showEvent(QShowEvent *) override; private: Ui::MessageBox *ui; int m_nType; int m_nTipType; QPoint m_pMousePoint; bool m_bMousePressed; std::thread *t1; ; #endif // MESSAGEBOX_H
-
MessageBox.cpp
以上是关于QT 写一个属于自己的消息弹窗MessageBox的主要内容,如果未能解决你的问题,请参考以下文章