史上最全用Qt做一个无边框界面方法

本文分享了在Qt中创建无边框界面的详细步骤,包括去除边框、添加阴影、实现鼠标拖拽及停靠功能,以及自定义右上角按钮的方法。

最近在用Qt做一个无边框界面,查找诸多资料之后,终于找到了一个很好的办法解决Qt无边框出现的诸多问题。

问题1:Qt去掉边框之后就没有停靠功能,也没有右上角的缩放关闭等功能,而且边框也没有,主界面是纯白色,这就需要添加上这些基本功能。

            1.界面还需要添加“顶端”,这个顶端可以提供一些工具栏的按钮,还提供拖动的功能。

            2.界面边框添加阴影或者线,

 

Qt如果做成无边框界面的话就没有边框停靠的功能,也没有鼠标拖拽功能,这些功能就需要自己写,现在计算一下,没有边框需要添加哪些功能,一是停靠功能,二是鼠标拖拽功能,三是右上角缩放关闭等按钮功能,四是加上边框线,以上功能将通过代码全部写出来。

1.去掉边框,添加阴影

#include <windowsx.h>

#include <windows.h>

#pragma comment (lib,"Dwmapi.lib") //添加阴影

#pragma comment (lib,"user32.lib")

main

{

this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint);

HWND hwnd = (HWND)this->winId();

DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);

::SetWindowLong(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION);

const MARGINS shadow = { 1, 1, 1, 1 };//留出一个边框添加阴影

DwmExtendFrameIntoClientArea(HWND(winId()), &shadow);

}

2.添加主窗口线

上面代码实现去掉边框的功能,在主窗口上添加边框阴影效果,这时可以实现paintEvent函数画主边框线,具体代码如下:

void MainWindow::paintEvent(QPaintEvent *e)

{

       Q_UNUSED(e);

       QPainter painter(this);

       //画笔添加边框

       painter.setBrush(QColor(130,135,144));

       painter.setPen(QColor(130, 135, 144));

       painter.drawRect(0, 0, 1, this->height());

       painter.drawRect(this->width()-1, 0, 1, this->height());

       painter.drawRect(0, this->height()-2, this->width(), 2);

       painter.drawRect(0,0,this->width(),1);

       

}

3.添加拖拽,停靠功能

在case WM_NCHITTEST:去掉一些边框面积,那些面积就不能被鼠标拖拽,其余地方就可以被拖拽。在case WM_GETMINMAXINFO:例子中实现窗口停靠功能,

bool MainWindow::nativeEvent(const QByteArray & eventType, void * message, long * result)

{

       if (projectWidget)

       {

              projectWidget->setWID(effectiveWinId());

              projectWidget->handleBim5DEvent(eventType, message, result);

       }

       MSG* msg = (MSG*)message;

       switch (msg->message)

       {

              case WM_NCHITTEST:

              {

                     int xPos = GET_X_LPARAM(msg->lParam) - this->frameGeometry().x();

                     int yPos = GET_Y_LPARAM(msg->lParam) - this->frameGeometry().y();

                     const int HIT_BORDER = 5;//边框大小

                     //主窗体

                     auto comBoxRect = QRect(ui.widget_2->pos() + ui.comboBox->pos(), ui.comboBox->size());

                     auto userRect = QRect(ui.widget_2->pos()+ui.userBtn->pos(),ui.userBtn->size());

                     auto setRect = QRect(ui.widget_2->pos() + ui.appInfoSetting->pos(),ui.appInfoSetting->size());

                     auto minRect = QRect(ui.widget_2->pos() + ui.hideBtn->pos(), ui.hideBtn->size());

                     auto maxRect = QRect(ui.widget_2->pos() + ui.minMaxBtn->pos(),ui.minMaxBtn->size());

                     auto closeRect = QRect(ui.widget_2->pos() + ui.closeBtn->pos(),ui.closeBtn->size());

                     //导航按钮

                     QRect exitProjectRect, saveProjectRect, updateRect, commitRect, lockRect;

                     if (navigationWidget)

                     {

                           //获取控件的大小在测试时候只有一半,所以乘以sizeRate,还没找到原因

                           float sizeRate = 1.0;

                           exitProjectRect = QRect(ui.navigationWidgetContainer->pos() + navigationWidget->getExitProjectPos(),navigationWidget->getExitProjectSize()*sizeRate);

                           saveProjectRect = QRect(ui.navigationWidgetContainer->pos() + navigationWidget->getSaveProjectPos(),navigationWidget->getSaveProjectSize()*sizeRate);

                           updateRect = QRect(ui.navigationWidgetContainer->pos() + navigationWidget->getUpdatePos(),navigationWidget->getUpdateSize()*sizeRate);

                           commitRect = QRect(ui.navigationWidgetContainer->pos() + navigationWidget->getCommitPos(),navigationWidget->getCommitSize()*sizeRate);

                           lockRect = QRect(ui.navigationWidgetContainer->pos() + navigationWidget->getLockPos(), navigationWidget->getLockSize()*sizeRate);

                     }

                     //排除按钮部分

                     if ((xPos > HIT_BORDER && xPos < (ui.stackedWidget->width() - HIT_BORDER) && yPos >(ui.widget_2->height() + HIT_BORDER) && yPos < (this->height() - HIT_BORDER))//工程界面

                           || ui.logoLabel->geometry().contains(xPos,yPos)

                           || (!navigationWidget && comBoxRect.contains(xPos, yPos))

                           || userRect.contains(xPos, yPos)//用户按钮

                            || setRect.contains(xPos, yPos)

                           || minRect.contains(xPos, yPos)

                           || maxRect.contains(xPos, yPos)

                           || closeRect.contains(xPos, yPos)

                           || (navigationWidget &&

                           (exitProjectRect.contains(xPos, yPos)

                           || saveProjectRect.contains(xPos,yPos)

                           || updateRect.contains(xPos,yPos)

                           || commitRect.contains(xPos,yPos)

                           || lockRect.contains(xPos,yPos))))

                     {

                           return false;

                     }

                     if (ui.horizontalLayout_2->geometry().contains(xPos, yPos) && xPos > HIT_BORDER && yPos > HIT_BORDER)

                     {

                           *result = HTCAPTION;

                           return true;

                     }

                     //边框缩放

                     if (xPos > 0 && xPos < HIT_BORDER)

                     {

                           *result = HTLEFT;

                     }

                     else if (xPos > (this->width() - HIT_BORDER) && xPos < (this->width() - 0)) {

                           *result = HTRIGHT;

                     }

                     else if (yPos > 0 && yPos < HIT_BORDER) {

                           *result = HTTOP;

                     }

                     else 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;

                     }

                     else if (xPos > (this->width() - HIT_BORDER) && xPos < (this->width() - 0) && yPos > 0 && yPos < HIT_BORDER) {

                           *result = HTTOPRIGHT;

                     }

                     else if (xPos > 0 && xPos < HIT_BORDER && yPos >(this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {

                           *result = HTBOTTOMLEFT;

                     }

                     else if (xPos > (this->width() - HIT_BORDER) && xPos < (this->width() - 0) && yPos >(this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {

                           *result = HTBOTTOMRIGHT;

                     }

                     return true;

              }

              break;

              case WM_NCCALCSIZE:

                     return true;

              case WM_GETMINMAXINFO:

              {

                     if (::IsZoomed(msg->hwnd))

                     {

                           // 最大化时会超出屏幕,所以填充边框间距

                           RECT frame = { 0, 0, 0, 0};

                           AdjustWindowRectEx(&frame, WS_OVERLAPPEDWINDOW, FALSE, 0);

                           frame.left = abs(frame.left);

                           frame.top = abs(frame.bottom);

                           this->setContentsMargins(frame.left-1, frame.top-1, frame.right-1, frame.bottom-1);

                           ui.minMaxBtn->setIcon(QIcon(":/MainWindow/resource/MainWindow/maxWindow.png"));//图标变换

                     }

                     else

                     {

                           this->setContentsMargins(0, 0, 0, 0);

                           ui.minMaxBtn->setIcon(QIcon(":/MainWindow/resource/MainWindow/normalWindow.png"));//图标变换

                     }

                     *result = ::DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);

                     return true;

              }

              break;

       }

       return QMainWindow::nativeEvent(eventType, message, result);

}

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值