转载:Qt之界面(自定义标题栏、无边框、可移动、缩放)_我不是萧海哇~~~~的博客-CSDN博客
参考了两篇文章处理,还有半屏没处理,就是左右边框的时候半屏。
重点:
1.拖动需要重载标题栏的 mousePressEvent方法。
2.边框拉伸的是采用的window的消息通信nativeEvent。需要注意的是这里面windows鼠标点获取的点和qt中获取的鼠标点位置不同,这里涉及到分辨下等问题,需要做转换处理,上面的文章没处理。
3.还有设置了自定义标题栏,需要对边框四周留缝隙,特别是顶部位置,就是在设置布局的时候,要给顶部留空隙,这时候边框拖动才能捕捉到。
效果:
代码:
widget.h
#ifndef WIDGET_H #define WIDGET_H #include#include #include #include #include QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result); private: Ui::Widget *ui; int m_nBorderWidth; //m_nBorder表示鼠标位于边框缩放范围的宽度 }; class TitleBar : public QWidget { Q_OBJECT public: explicit TitleBar(QWidget *parent = 0); protected: // 双击标题栏进行界面的最大化/还原 virtual void mouseDoubleClickEvent(QMouseEvent *event); protected: virtual void mousePressEvent(QMouseEvent *event); signals: public slots: //the slots function of minmaxclose bt void onChangeClicked(); private: QLabel *m_luLabel; //left-upper label QLabel *m_midLabel; //mid title label QPushButton *m_minBt; //min bt QPushButton *m_maxBt; //max bt QPushButton *m_closeBt; //close bt }; #endif // WIDGET_H
widget.cpp
#include "widget.h" #include "ui_widget.h" #include "titlebar.h" #include#include #include //调用WIN API需要用到的头文件与库 [实现缩放] #ifdef Q_OS_WIN #include #include #endif Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); setMouseTracking(true); //Qt::FramelessWindowHint设置窗口标志为无边框,而Qt::WindowStaysOnTopHint使窗口位于所有界面之上 this->setWindowFlags(Qt::FramelessWindowHint); //定义自定义标题栏对象 TitleBar *pTitleBar = new TitleBar(); pTitleBar->setParent(this); installEventFilter(pTitleBar); //使用调色板设置窗口的背景色 QPalette pal(palette()); pal.setColor(QPalette::Window, QColor(0, 255, 255)); setAutoFillBackground(true); setPalette(pal); //窗口布局中加入标题栏 QVBoxLayout *pLayout = new QVBoxLayout(); pLayout->addWidget(pTitleBar); pLayout->addStretch(); pLayout->setSpacing(0); //自定义标题的时候需要留一些边框空隙给拉伸的时候使用 pLayout->setContentsMargins(5, 5, 5, 5); setLayout(pLayout); //m_nBorder表示鼠标位于边框缩放范围的宽度,可以设置为5 m_nBorderWidth=5; } Widget::~Widget() { delete ui; } //nativeEvent主要用于进程间通信-消息传递,使用这种方式后来实现窗体的缩放 [加上了这函数,窗口也能移动了] bool Widget::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) { Q_UNUSED(eventType) MSG *param = static_cast (message); switch (param->message) { case WM_NCHITTEST: { //由于windows的分辨率不一样,需要我们做转化 int xPt = GET_X_LPARAM(param->lParam); int yPt = GET_Y_LPARAM(param->lParam); QPoint gpos(xPt,yPt); QWindow * handle = this->window()->windowHandle(); if(handle && handle->screen()) { QScreen * screen = handle->screen(); QPoint offset = screen->geometry().topLeft(); gpos = (gpos - offset) / screen->devicePixelRatio() + offset; } int nX = gpos.x() - this->geometry().x(); int nY = gpos.y()- this->geometry().y(); //如果是子控件 if (childAt(nX, nY) != nullptr) return QWidget::nativeEvent(eventType, message, result); *result = HTCAPTION;//在标题栏 2 int width=this->width(); int height=this->height(); // 鼠标区域位于窗体边框,进行缩放 if ((nX > 0) && (nX < m_nBorderWidth)) *result = HTLEFT;//在窗口的左边框 10 if ((nX > (width - m_nBorderWidth)) && (nX < width)) *result = HTRIGHT;//在窗口的右边框 11 if ((nY > 0) && (nY < m_nBorderWidth)) *result = HTTOP;//在窗口框的上面的水平线上 12 if ((nY > (height - m_nBorderWidth)) && (nY < height)) *result = HTBOTTOM;//窗口框的下面的水平线上 15 if ((nX > 0) && (nX < m_nBorderWidth) && (nY > 0) && (nY < m_nBorderWidth)) *result = HTTOPLEFT;//在窗口框的左上角 13 if ((nX > (width - m_nBorderWidth)) && (nX < width) && (nY > 0) && (nY < m_nBorderWidth)) *result = HTTOPRIGHT;//在窗口框的右上角 14 if ((nX > 0) && (nX < m_nBorderWidth) && (nY > (height - m_nBorderWidth)) && (nY < height)) *result = HTBOTTOMLEFT;//在窗口框的左下角 16 if ((nX > (width - m_nBorderWidth)) && (nX < width) && (nY > (height - m_nBorderWidth)) && (nY < height)) *result = HTBOTTOMRIGHT;//在窗口框的右下角 17 return true; } } return QWidget::nativeEvent(eventType, message, result); } TitleBar::TitleBar(QWidget *parent) : QWidget{parent} { m_luLabel = new QLabel; m_midLabel = new QLabel; m_minBt = new QPushButton; m_maxBt = new QPushButton; m_closeBt = new QPushButton; //set size m_luLabel->setFixedSize(20, 20); m_luLabel->setScaledContents(true); //save window default layout m_midLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); m_midLabel->setFixedHeight(32); m_minBt->setFixedSize(20, 20); m_maxBt->setFixedSize(20, 20); m_closeBt->setFixedSize(20, 20); //detele button frame m_minBt->setFlat(true); m_maxBt->setFlat(true); m_closeBt->setFlat(true); //set icon":/new/prefix1/rc/minimize.png" m_minBt->setIcon(QIcon(":/new/prefix1/rc/minimize.png")); m_minBt->setIconSize(m_minBt->size()); m_maxBt->setIcon(QIcon(":/new/prefix1/rc/maximize.png")); m_maxBt->setIconSize(m_maxBt->size()); m_closeBt->setIcon(QIcon(":/new/prefix1/rc/close-small.png")); m_closeBt->setIconSize(m_closeBt->size()); QPixmap icon(":/new/prefix1/rc/avatar.png"); m_luLabel->setPixmap(icon); //set name m_midLabel->setObjectName("titleLabel"); m_minBt->setObjectName("minimizeButton"); m_maxBt->setObjectName("maximizeButton"); m_closeBt->setObjectName("closeButton"); //set label text m_midLabel->setText("这里是项目名称字段"); //prompt name when Mouse over the button m_minBt->setToolTip("最小化"); m_maxBt->setToolTip("放大/缩小"); m_closeBt->setToolTip("关闭"); QHBoxLayout *pLayout = new QHBoxLayout(this); pLayout->addWidget(m_luLabel); pLayout->addWidget(m_midLabel,0,Qt::AlignCenter); pLayout->addWidget(m_minBt); pLayout->addWidget(m_maxBt); pLayout->addWidget(m_closeBt); pLayout->setSpacing(10);//set distance between controls pLayout->setContentsMargins(0, 0, 0, 0);//set Surrounding margin this->setLayout(pLayout); connect(m_minBt,SIGNAL(clicked()),this,SLOT(onChangeClicked())); connect(m_maxBt,SIGNAL(clicked()),this,SLOT(onChangeClicked())); connect(m_closeBt,SIGNAL(clicked()),this,SLOT(onChangeClicked())); } void TitleBar::onChangeClicked() { //if called by slot,return pointer,else nullptr QPushButton *pBtn = qobject_cast (sender()); QWidget *pWindow = this->window(); if (!pBtn||!pWindow->isWindow()) { return; } if (pBtn == m_minBt) { pWindow->showMinimized();//min window。 } else if (pBtn == m_maxBt) { pWindow->isMaximized() ? pWindow->showNormal() : pWindow->showMaximized();//scaled window } else if (pBtn == m_closeBt) { pWindow->close();//close window } } void TitleBar::mouseDoubleClickEvent(QMouseEvent *event) { Q_UNUSED(event); emit m_maxBt->clicked(); } void TitleBar::mousePressEvent(QMouseEvent *event) { if (ReleaseCapture()) { QWidget *pWindow = this->window(); //if mouse press is top window if (pWindow->isTopLevel()) { SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0); } } event->ignore(); }
main.cpp
#include "widget.h" #includeint main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); }



