打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Qt 之 自定义提示信息框
userphoto

2018.12.16

关注

一、简述

Qt 之 自定义提示信息框—迅雷风格 这篇文章中讲述了如何实现迅雷风格的自定义提示框。那么在这一篇中我们就讲述一下如何实现QQ风格的提示框

整体代码与Qt 之 自定义提示信息框—迅雷风格 中的代码类似,主要是界面样式上的不同,下面先看一下效果图。

二、代码之路

看代码之前需要看一下 Qt 之 自定义窗口标题栏 这一篇文章,因为这里用到了这篇文章中写到的自定义标题栏。

这里新建任务窗口类MyMessageBox 继承了BaseWindow类,所以省去了一些代码实现(主要包括顶部标题栏、鼠标按住标题栏进行拖动,窗口背景色等 ),有需要的小伙伴可以去看一下这一篇文章。

如果需要了解如何实现窗口的模态与非模态对话框可以看一下Qt 之 模态与非模态窗口的介绍及 实现QDialog的exec()方法 这一篇文章。

mymessagebox.h

#include <QWidget>#include "ui_mymessagebox.h"#include "basewindow.h"enum ChosseResult{    ID_OK = 0,                      // 确定;    ID_CANCEL                       // 取消;};enum MessageType{    MESSAGE_INFORMATION = 0,        // 提示信息;    MESSAGE_WARNNING,               // 提示警告;    MESSAGE_QUESTION,               // 提示询问;    MESSAGE_INPUT                   // 提示输入框;};enum MessageButtonType{    BUTTON_OK = 0,                  // 只有确定按钮;    BUTTON_OK_AND_CANCEL,           // 确定、取消按钮;    BUTTON_CLOSE                    // 关闭按钮;};class MyMessageBox : public BaseWindow{    Q_OBJECTpublic:    MyMessageBox(QWidget *parent = 0);    ~MyMessageBox();    void setWindowTitle(QString title, int titleFontSize = 10);    void setContentText(QString contentText);    void setMessageType(MessageType messageType);    void setButtonType(MessageButtonType buttonType);    void setMessageContent(QString messageContent);public:    int static showMyMessageBox(QWidget* parent, const QString &title,const QString &contentText , MessageType messageType, MessageButtonType messageButtonType , bool isModelWindow = false);private:    void initWindow();    void initTitleBar();    int exec();    void paintEvent(QPaintEvent *event);    void closeEvent(QCloseEvent *event);private slots:    void onOkClicked();    void onCancelClicked();private:    Ui::MyMessageBox ui;    QEventLoop* m_eventLoop;    ChosseResult m_chooseResult;};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

mymessagebox.cpp

#include "mymessagebox.h"#include <QPainter>#include <QCloseEvent>MyMessageBox::MyMessageBox(QWidget *parent)    : BaseWindow(parent)    , m_eventLoop(NULL)    , m_chooseResult(ID_CANCEL){    ui.setupUi(this);    initWindow();}MyMessageBox::~MyMessageBox(){}void MyMessageBox::initWindow(){    initTitleBar();    loadStyleSheet("MyMessageBox/MyMessageBox");    Qt::WindowFlags flags = this->windowFlags();    this->setWindowFlags(flags | Qt::Window);    ui.inputContent->setVisible(false);    connect(ui.pButtonOk, SIGNAL(clicked()), this, SLOT(onOkClicked()));    connect(ui.pButtonCancel, SIGNAL(clicked()), this, SLOT(onCancelClicked()));}// 初始化标题栏;void MyMessageBox::initTitleBar(){    m_titleBar->move(0, 0);    m_titleBar->setWindowBorderWidth(0);    // 设置标题栏颜色,在迅雷风格中标题栏默认为白色;    m_titleBar->setBackgroundColor(185, 92, 125);    m_titleBar->setButtonType(ONLY_CLOSE_BUTTON);    m_titleBar->setTitleWidth(this->width());    // 设置标题栏图标,在迅雷风格中没有设置图标;    m_titleBar->setTitleIcon(":/Resources/MyMessageBox/WindowIcon.png", QSize(16, 16));}void MyMessageBox::paintEvent(QPaintEvent *event){    QPainter painter(this);    // 绘制窗口白色背景色;    QPainterPath pathBack;    pathBack.setFillRule(Qt::WindingFill);    pathBack.addRoundedRect(QRect(0, 0, this->width(), this->height()) , 3 , 3);    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);    painter.fillPath(pathBack, QBrush(QColor(255, 255, 255)));    // 绘制按钮部分灰色背景;    QPainterPath pathButtonBack;    pathButtonBack.setFillRule(Qt::WindingFill);    pathButtonBack.addRoundedRect(QRect(0, 116, this->width(), 48) , 3 , 3);    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);    painter.fillPath(pathButtonBack, QBrush(QColor(245, 230, 233)));    return QWidget::paintEvent(event);}void MyMessageBox::setWindowTitle(QString title , int titleFontSize){    m_titleBar->setTitleContent(title, titleFontSize);}void MyMessageBox::setContentText(QString contentText){    ui.MessageContent->setText(contentText);}void MyMessageBox::setMessageType(MessageType messageType){    switch (messageType)    {    case MESSAGE_INFORMATION:        ui.MessageIcon->setPixmap(QPixmap(":/Resources/MyMessageBox/information.png"));        break;    case MESSAGE_WARNNING:        ui.MessageIcon->setPixmap(QPixmap(":/Resources/MyMessageBox/warnning.png"));        break;    case MESSAGE_QUESTION:        ui.MessageIcon->setPixmap(QPixmap(":/Resources/MyMessageBox/question.png"));        break;    case MESSAGE_INPUT:        ui.MessageIcon->setVisible(false);        ui.inputContent->setVisible(true);    default:        break;    }}void MyMessageBox::setButtonType(MessageButtonType buttonType){    switch (buttonType)    {    case BUTTON_OK:    {        ui.pButtonOk->setText(QStringLiteral("确定"));        ui.pButtonCancel->setVisible(false);    }        break;    case BUTTON_OK_AND_CANCEL:    {        ui.pButtonOk->setText(QStringLiteral("确定"));        ui.pButtonCancel->setText(QStringLiteral("取消"));    }        break;    default:        break;    }}void MyMessageBox::setMessageContent(QString messageContent){    ui.MessageContent->setText(messageContent);}int MyMessageBox::showMyMessageBox(QWidget* parent, const QString &title, const QString &contentText, MessageType messageType, MessageButtonType messageButtonType, bool isModelWindow){    MyMessageBox * myMessageBox = new MyMessageBox(parent);    myMessageBox->setWindowTitle(title);    myMessageBox->setContentText(contentText);    myMessageBox->setMessageType(messageType);    myMessageBox->setButtonType(messageButtonType);    if (isModelWindow)    {        // 设置为模态窗口时,参数parent必须设置父窗口指针,否则模态设置无效;        // 因为 Qt::WindowModal 参数只对父窗口有效,如果想要模态对全局窗口都有效可以设置 Qt::ApplicationModal        return myMessageBox->exec();    }    else    {        myMessageBox->show();    }    return -1;}int MyMessageBox::exec(){    // 因为QWidget没有exec()方法,所以需要自己定义来完成exec()方法;    // 而exec()方法就是直接设置窗口显示为模态,并且窗口关闭结束后返回用户选择结果(按了确定还是取消按钮);    // 而show()方法只是显示窗口,并不会设置窗口的模态或者非模态,需要自己调用setWindowModality()方法进行设置;    // 而且show()方法并不会返回用户选择结果;    // 这里也可以继承QDialog类,QDialog有自己的exec()方法,根据返回 Accepted, Rejected来决定是否按了确定按钮;    // 设置为窗口级模态,也可设置为应用程序及模态 Qt::ApplicationModal;    this->setWindowModality(Qt::WindowModal);     show();    // 使用事件循环QEventLoop ,不让exec()方法结束,在用户选择确定或者取消后,关闭窗口结束事件循环,并返回最后用户选择的结果;    // 根据返回结果得到用户按下了确定还是取消,采取相应的操作。从而模拟出QDialog类的exec()方法;    m_eventLoop = new QEventLoop(this);    m_eventLoop->exec();    return m_chooseResult;}void MyMessageBox::onOkClicked(){    m_chooseResult = ID_OK;    close();}void MyMessageBox::onCancelClicked(){    m_chooseResult = ID_CANCEL;    close();}void MyMessageBox::closeEvent(QCloseEvent *event){    // 关闭窗口时结束事件循环,在exec()方法中返回选择结果;    if (m_eventLoop != NULL)    {        m_eventLoop->exit();    }    event->accept();}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183

样式

*{font-family:Microsoft YaHei;}QLabel#MessageContent{    font-size:14px;}QPushButton#pButtonOk{    border-radius:3px;    background-color:rgb(244 , 244 , 244);    border: 1px solid rgb(160 , 150 , 152);}QPushButton#pButtonOk:hover{    background-color:rgb(190 , 231 , 253);    border: 1px solid rgb(79 , 173 , 216);}QPushButton#pButtonOk:pressed{    background-color:rgb(235 , 236 , 237);    border: 1px solid rgb(79 , 173 , 216);    padding-left:2px;    padding-top:2px;}QPushButton#pButtonCancel{    border-radius:3px;    background-color:rgb(244 , 244 , 244);    border: 1px solid rgb(160 , 150 , 152);}QPushButton#pButtonCancel:hover{    background-color:rgb(190 , 231 , 253);    border: 1px solid rgb(79 , 173 , 216);}QPushButton#pButtonCancel:pressed{    background-color:rgb(235 , 236 , 237);    border: 1px solid rgb(79 , 173 , 216);    padding-left:2px;    padding-top:2px;}QLineEdit#inputContent{    border: 1px solid rgb(195 , 195 , 195);}QLineEdit#inputContent:hover{    border: 1px solid rgb(1 , 186 , 255 );}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

测试代码

设置为模态窗口

设置父窗口指针

void onButtonClicked(){    // showMyMessageBox()方法的最后一个参数为是否设置提示框为模态窗口;    // 设置提示框为模态窗口,那么必须将父窗口指针传进showMyMessageBox()方法中,否则模态无效;    // 因为MyMessageBox模态时设置的为Qt::WindowModal,只会影响父窗口,如需要阻塞整个应用程序,可设置为Qt::ApplicationModal;    int result = MyMessageBox::showMyMessageBox(this, QStringLiteral("删除好友"), QStringLiteral("您确定要删除XXX好友吗?"), MESSAGE_WARNNING, BUTTON_OK_AND_CANCEL, true);    if (result == ID_OK)    {        ui.label->setText(QStringLiteral("结果:确定"));    }    else if (result == ID_CANCEL)    {        ui.label->setText(QStringLiteral("结果:取消"));    }    else    {        ui.label->setText(QStringLiteral("非模态窗口"));    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

效果图一

我们看到设置为模态窗口,弹出提示框后,父窗口被阻塞,无法响应我们的操作。并且在我们点击确定/取消 按钮后,调用showMyMessageBox()方法之后的代码得以执行。
测试代码中根据showMyMessageBox()的返回值来设置父窗口界面上显示用户操作结果(点击确定还是取消),而这些操作都是在提示框关闭之后执行的。以此说明,父窗口的操作都会被阻塞直到关闭提示框。


不设置父窗口指针

我们将showMyMessageBox()方法中的父指针修改为NULL。来看看效果

int result = MyMessageBox::showMyMessageBox(NULL, QStringLiteral("删除好友"), QStringLiteral("您确定要删除XXX好友吗?"), MESSAGE_WARNNING, BUTTON_OK_AND_CANCEL, true);
  • 1

效果图二

我们看到打开提示框后,父窗口仍可接受用户响应(可以移动,并且点击打开窗口按钮,可以再次弹出一个提示框)。但是父窗口中显示的结果(确定/取消)还是在提示框关闭之后进行更新,说明设置为模态窗口后,尽管不设置父窗口指针,showMyMessageBox()方法之后的代码要等待窗口关闭之后才能执行。


设置为非模态窗口

设置父窗口指针

我们将showMyMessageBox()方法最后一个参数修改为false,设置为非模态窗口。

int result = MyMessageBox::showMyMessageBox(this, QStringLiteral("删除好友"), QStringLiteral("您确定要删除XXX好友吗?"), MESSAGE_WARNNING, BUTTON_OK_AND_CANCEL, false);
  • 1

效果图三

我们看到设置为非模态窗口,打开提示框,并不会阻塞父窗口的响应。同时,我们将父窗口指针传入showMyMessageBox()方法中,我们看到提示框会一直显示在父窗口之上。在Qt中子窗口会一直显示在父窗口之上

同时,设置为非模态,showMyMessageBox()方法会立即返回,不会阻塞后面代码的执行。我们也看到在打开提示框时,父窗口结果立即更新为非模态窗口,而不是在提示框关闭之后。


不设置父窗口指针

int result = MyMessageBox::showMyMessageBox(NULL, QStringLiteral("删除好友"), QStringLiteral("您确定要删除XXX好友吗?"), MESSAGE_WARNNING, BUTTON_OK_AND_CANCEL, false);
  • 1

效果图四

将父窗口指针修改为NULL后,我们发现提示框不会一直显示在父窗口之上了。


这里我们在 Qt 之 自定义提示信息框—迅雷风格 代码的基础上修改了样式,得到了QQ风格的自定义提示框效果。代码很简单,关键在于尝试。

有兴趣的小伙伴可以自行修改样式,来实现另一番效果。欢迎一起交流哈 O(∩_∩)O!

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
关于模态窗口刷新父页面
QScatterSeries相关内容
夜光表
文章标题多层文本阴影源代码
如何避免真空 干燥箱产生爆炸
《彻底搞定C指针》第7篇 函数名与函数指针
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服