最近一直在研究迅雷9的界面,花了点时间做了几个通用的提示信息框,整体风格与迅雷9界面相同。支持模态和非模态两种模式窗口。提示框效果见下图。
我们可以根据设置不同的参数来设置提示框标题、显示内容、显示图标、下方按钮个数,可以设置为输入框,也可以设置为模态/非模态对话框,实现了自定义的QMessageBox。目前实现了提示框基本功能,后续将继续拓展更多功能。小伙伴们可以根据需要自定义其他功能,下面直接上代码。
后续更改了一下样式,修改为QQ风格的提示窗口,详情见 Qt 之 自定义提示信息框—QQ风格 。
看代码之前需要看一下Qt 之 自定义窗口标题栏这一篇文章,因为这里用到了这篇文章中写到的自定义标题栏。
如果需要了解如何实现窗口的模态与非模态对话框可以看一下 Qt 之 模态与非模态窗口的介绍及 实现QDialog的exec()方法 这一篇文章。
这里新建任务窗口类MyMessageBox 继承了BaseWindow类,所以省去了一些代码实现(主要包括顶部标题栏、鼠标按住标题栏进行拖动,窗口背景色等 ),有需要的小伙伴可以去看一下这一篇文章。
#include
#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_OBJECT
public:
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;
};
#include "mymessagebox.h"
#include
#include
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(1, 2);
m_titleBar->setWindowBorderWidth(2);
m_titleBar->setBackgroundColor(255, 255, 255);
m_titleBar->setButtonType(ONLY_CLOSE_BUTTON);
m_titleBar->setTitleWidth(this->width());
}
void MyMessageBox::paintEvent(QPaintEvent *event)
{
// 绘制窗口白色背景色;
QPainter painter(this);
QPainterPath pathBack;
pathBack.setFillRule(Qt::WindingFill);
pathBack.addRect(QRect(0, 0, this->width(), this->height()));
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
painter.fillPath(pathBack, QBrush(QColor(255, 255, 255)));
// 绘制按钮部分灰色背景;
QPainterPath pathButtonBack;
pathButtonBack.setFillRule(Qt::WindingFill);
pathButtonBack.addRect(QRect(0, 110, this->width(), 48));
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
painter.fillPath(pathButtonBack, QBrush(QColor(247, 247, 247)));
// 绘制窗口灰色边框;
QPen pen(QColor(204, 204, 204));
painter.setPen(pen);
painter.drawRect(0, 0, this->width() - 1, this->height() - 1);
// 绘制窗口上方蓝条;
QPainterPath pathHead;
pathHead.setFillRule(Qt::WindingFill);
pathHead.addRect(QRect(0, 0, this->width(), 2));
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
painter.fillPath(pathHead, QBrush(QColor(15, 151, 255)));
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);
}
// 显示提示框
// isModelWindow 参数设置提示框是否是模态
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 0;
}
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();
}
*{font-family:Microsoft YaHei;}
QLabel#MessageContent
{
font-size:14px;
}
QPushButton#pButtonOk
{
color:white;
background-color:rgb(14 , 150 , 254);
border: 1px solid rgb(11 , 137 , 234);
}
QPushButton#pButtonOk:hover
{
color:white;
background-color:rgb(44 , 137 , 255);
border: 1px solid rgb(11 , 137 , 234);
}
QPushButton#pButtonOk:pressed
{
color:white;
background-color:rgb(14 , 135 , 228);
border: 1px solid rgb(12 , 138 , 235);
padding-left:3px;
padding-top:3px;
}
QPushButton#pButtonCancel
{
color:black;
background-color:rgb(238 , 238 , 238);
border: 1px solid rgb(183 , 183 , 183);
}
QPushButton#pButtonCancel:hover
{
color:black;
background-color:rgb(228 , 240 , 250);
border: 1px solid rgb(15 , 150 , 255);
}
QPushButton#pButtonCancel:pressed
{
color:black;
background-color:rgb(204 , 228 , 247);
border: 1px solid rgb(1 , 84 , 153);
padding-left:3px;
padding-top:3px;
}
QLineEdit#inputContent
{
border: 1px solid rgb(195 , 195 , 195);
}
QLineEdit#inputContent:hover
{
border: 1px solid rgb(1 , 186 , 255 );
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyMessageBox::showMyMessageBox(NULL, QStringLiteral("删除"), QStringLiteral("您确定要删除此任务吗?"), MESSAGE_WARNNING, BUTTON_OK_AND_CANCEL);
MyMessageBox::showMyMessageBox(NULL, QStringLiteral("退出"), QStringLiteral("任务为下载完,确定退出吗?"), MESSAGE_QUESTION, BUTTON_OK_AND_CANCEL);
MyMessageBox::showMyMessageBox(NULL, QStringLiteral("提示"), QStringLiteral("您输入的用户名不正确"), MESSAGE_INFORMATION, BUTTON_OK_AND_CANCEL);
MyMessageBox::showMyMessageBox(NULL, QStringLiteral("重命名"), QStringLiteral("文件名: "), MESSAGE_INPUT, BUTTON_OK_AND_CANCEL);
return a.exec();
}
代码其实很简单,这里只是实现了基本功能(根据参数设置不同样式的提示框),更多可以参考Qt的QMessageBox,在后续会增加更多功能实现,敬请期待哈 O(∩_∩)O !
Qt 之 自定义提示信息框—QQ风格
Qt 之 模态与非模态窗口的介绍及 实现QDialog的exec()方法
Qt 之 自定义窗口标题栏
Qt 之 自定义提示信息框—QQ、迅雷风格 (包含了QQ和迅雷两种风格的提示框)