本文实现了自定义标题栏的最小化,最大化(自适应任务栏),关闭,拉伸,拖曳。因为不想引入其他资源,所以按钮,背景都是系统提供的。
效果图:
直接上代码----
#include "widget.h"
#include <QApplication>
#include "CustomFrame.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget *w = new Widget();
CustomFrame frame(w, "CustomFrame");
frame.show();
return a.exec();
}
#pragma once
#include <QFrame>
class QToolButton;
class CustomFrame : public QFrame
{
Q_OBJECT
public:
explicit CustomFrame(QWidget *contentWidget, const QString &title);
public slots:
void slotShowSmall();
void slotShowMaxRestore();
protected:
void mousePressEvent(QMouseEvent *);
void mouseMoveEvent(QMouseEvent *);
void mouseReleaseEvent(QMouseEvent *);
bool nativeEvent(const QByteArray & eventType, void * message, long * result);
void paintEvent(QPaintEvent *);
private:
bool isMax_;
bool isPress_;
QPoint startPos_;
QPoint clickPos_;
QWidget *contentWidget_;
QPixmap maxPixmap_;
QPixmap restorePixmap_;
QToolButton *maxButton_;
};
#include "CustomFrame.h"
#include <QtWidgets>
static const int TITLE_HEIGHT = 30;
static const int FRAME_BORDER = 2;
CustomFrame::CustomFrame(QWidget *contentWidget, const QString &title)
: contentWidget_(contentWidget)
{
this->setWindowFlags(Qt::FramelessWindowHint);
this->setAttribute(Qt::WA_TranslucentBackground);
this->setMouseTracking(true);
isMax_ = false;
isPress_ = false;
QLabel *logoLabel = new QLabel();
QPixmap logoPixmap = this->style()->standardPixmap(QStyle::SP_TitleBarMenuButton);
logoLabel->setPixmap(logoPixmap);
logoLabel->setFixedSize(16, 16);
logoLabel->setScaledContents(true);
QLabel *titleLabel = new QLabel();
titleLabel->setText(title);
QFont titleFont = titleLabel->font();
titleFont.setBold(true);
titleLabel->setFont(titleFont);
titleLabel->setObjectName("whiteLabel");
QToolButton *minButton = new QToolButton();
QPixmap minPixmap = this->style()->standardPixmap(QStyle::SP_TitleBarMinButton);
minButton->setIcon(minPixmap);
connect(minButton, SIGNAL(clicked()), this, SLOT(slotShowSmall()));
maxButton_ = new QToolButton();
maxPixmap_ = this->style()->standardPixmap(QStyle::SP_TitleBarMaxButton);
restorePixmap_ = this->style()->standardPixmap(QStyle::SP_TitleBarNormalButton);
maxButton_->setIcon(maxPixmap_);
connect(maxButton_, SIGNAL(clicked()), this, SLOT(slotShowMaxRestore()));
QToolButton *closeButton = new QToolButton();
QPixmap closePixmap = this->style()->standardPixmap(QStyle::SP_TitleBarCloseButton);
closeButton->setIcon(closePixmap);
connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
QHBoxLayout *titleLayout = new QHBoxLayout();
titleLayout->addWidget(logoLabel);
titleLayout->addWidget(titleLabel);
titleLabel->setContentsMargins(5, 0, 0, 0);
titleLayout->addStretch();
titleLayout->addWidget(minButton, 0, Qt::AlignTop);
titleLayout->addWidget(maxButton_, 0, Qt::AlignTop);
titleLayout->addWidget(closeButton, 0, Qt::AlignTop);
titleLayout->setSpacing(0);
titleLayout->setContentsMargins(5, 0, 0, 0);
QWidget *titleWidget = new QWidget();
titleWidget->setLayout(titleLayout);
titleWidget->installEventFilter(0);
QVBoxLayout *mainLayout = new QVBoxLayout();
mainLayout->addWidget(titleWidget);
mainLayout->addWidget(contentWidget_);
mainLayout->setSpacing(0);
mainLayout->setMargin(5);
this->setLayout(mainLayout);
}
void CustomFrame::slotShowSmall()
{
this->showMinimized();
}
void CustomFrame::slotShowMaxRestore()
{
if (isMax_) {
this->showNormal();
maxButton_->setIcon(maxPixmap_);
} else {
this->showMaximized();
maxButton_->setIcon(restorePixmap_);
}
isMax_ = !isMax_;
}
void CustomFrame::mousePressEvent(QMouseEvent *e)
{
startPos_ = e->globalPos();
clickPos_ = e->pos();
if (e->button() == Qt::LeftButton) {
if (e->type() == QEvent::MouseButtonPress) {
isPress_ = true;
} else if (e->type() == QEvent::MouseButtonDblClick && e->pos().y() <= TITLE_HEIGHT) {
this->slotShowMaxRestore();
}
}
}
void CustomFrame::mouseMoveEvent(QMouseEvent *e)
{
if (isMax_ || !isPress_) {
return;
}
this->move(e->globalPos() - clickPos_);
}
void CustomFrame::mouseReleaseEvent(QMouseEvent *)
{
isPress_ = false;
}
bool CustomFrame::nativeEvent(const QByteArray & eventType, void * message, long * result)
{
Q_UNUSED(eventType);
const int HIT_BORDER = 5;
const MSG *msg=static_cast<MSG*>(message);
if(msg->message == WM_NCHITTEST) {
int xPos = ((int)(short)LOWORD(msg->lParam)) - this->frameGeometry().x();
int yPos = ((int)(short)HIWORD(msg->lParam)) - this->frameGeometry().y();
if(this->childAt(xPos,yPos) == 0) {
*result = HTCAPTION;
} else {
return false;
}
if(xPos > 0 && xPos < HIT_BORDER) {
*result = HTLEFT;
}
if(xPos > (this->width() - HIT_BORDER) && xPos < (this->width() - 0)) {
*result = HTRIGHT;
}
if(yPos > 0 && yPos < HIT_BORDER) {
*result = HTTOP;
}
if(yPos > (this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {
*result = HTBOTTOM;
}
if(xPos > 0 && xPos < HIT_BORDER && yPos > 0 && yPos < HIT_BORDER) {
*result = HTTOPLEFT;
}
if(xPos > (this->width() - HIT_BORDER) && xPos < (this->width() - 0) && yPos > 0 && yPos < HIT_BORDER) {
*result = HTTOPRIGHT;
}
if(xPos > 0 && xPos < HIT_BORDER && yPos > (this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {
*result = HTBOTTOMLEFT;
}
if(xPos > (this->width() - HIT_BORDER) && xPos < (this->width() - 0) && yPos > (this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {
*result = HTBOTTOMRIGHT;
}
return true;
}
return false;
}
void CustomFrame::paintEvent(QPaintEvent *e)
{
int border = FRAME_BORDER;
if (this->isMaximized()) {
border = 0;
}
QPainter painter(this);
QPainterPath painterPath;
painterPath.setFillRule(Qt::WindingFill);
painterPath.addRect(border, border, this->width()-2*border, this->height()-2*border);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.fillPath(painterPath, QBrush(Qt::white));
QColor color(200, 200, 200);
for (int i=0; i<border; i++) {
color.setAlpha((i+1)*30);
painter.setPen(color);
painter.drawRect(border-i, border-i, this->width()-(border-i)*2, this->height()-(border-i)*2);
}
painter.setPen(Qt::NoPen);
painter.setBrush(Qt::white);
// 这里可以在资源中指定一张标题背景图片
//painter.drawPixmap(QRect(border, border, this->width()-2*border, this->height()-2*border), QPixmap(DEFAULT_SKIN));
painter.drawRect(QRect(border, TITLE_HEIGHT, this->width()-2*border, this->height()-TITLE_HEIGHT-border));
QFrame::paintEvent(e);
}