不同于Qt::CustomizeWindowHint,本例去除了Qt::CustomizeWindowHint状态下顶部的那一小部分边框,并且保留了功能

效果:

实现:
 .h文件

#ifndef FRAMELESSWIDGET_H
#define FRAMELESSWIDGET_H

#include <QWidget>
#include <dwmapi.h>//添加阴影需要用到的系统库

class FramelessWidget : public QWidget
{
    Q_OBJECT
public:
    explicit FramelessWidget(QWidget *parent = 0);

protected:

    bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result);

private:
    //边距
    int padding;

    HWND hwnd;

    //标题栏控件
    QWidget *titleBar;

    Qt::WindowFlags flags;

public Q_SLOTS:
    //设置标题栏控件
    void setTitleBar(QWidget *titleBar);
};

#endif // FRAMELESSWIDGET_H

记得在pro文件引入dwmapi的库(不知道为什么ide会自动补全但是编译就显示不认识里面函数,估计是没有链接dll文件)

右击项目->添加库->外部库加进去就行

.cpp

#include "framelesswidget.h"
#include "qdatetime.h"
#include "qevent.h"
#include "qdebug.h"
#include "windows.h"
#include "windowsx.h"
#pragma comment (lib,"user32.lib")

FramelessWidget::FramelessWidget(QWidget *parent) : QWidget(parent)
{
    padding = 8;
    flags = this->windowFlags();
    titleBar = 0;

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


    hwnd = (HWND)this->winId();
    DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);

    //设置窗口样式
    SetWindowLong(hwnd, GWL_STYLE, style|WS_MAXIMIZEBOX | WS_THICKFRAME|WS_CAPTION);

    //添加阴影
    MARGINS margins = {-1,-1,-1,-1};
    DwmExtendFrameIntoClientArea(hwnd, &margins);
}


bool FramelessWidget::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
{
    if (eventType == "windows_generic_MSG")
    {

        MSG *msg = static_cast<MSG *>(message);

        //不同的消息类型和参数进行不同的处理
        if (msg->message == WM_NCCALCSIZE)
        {
            *result = 0;
            return true;
        }
        else if (msg->message == WM_SYSKEYDOWN)
        {
            //屏蔽alt键按下
        }
        else if (msg->message == WM_SYSKEYUP)
        {
            //屏蔽alt键松开
        }
        else if (msg->message == WM_NCHITTEST)
        {
            long x = GET_X_LPARAM(msg->lParam);
            long y = GET_Y_LPARAM(msg->lParam);
            QPoint cursorpos(x,y);

            //注意屏幕缩放的问题
            qreal scales=QGuiApplication::primaryScreen()->devicePixelRatio();
            cursorpos/=scales;

            QPoint pos=mapFromGlobal(cursorpos);

            //判断当前鼠标位置在哪个区域
            bool left = pos.x() < padding;
            bool right = pos.x() > width() - padding;
            bool top = pos.y() < padding;
            bool bottom = pos.y() > height() - padding;

            //鼠标移动到四个角,这个消息是当鼠标移动或者有鼠标键按下时候发出的
            *result = 0;

            if (left && top) {
                *result = HTTOPLEFT;
            } else if (left && bottom) {
                *result = HTBOTTOMLEFT;
            } else if (right && top) {
                *result = HTTOPRIGHT;
            } else if (right && bottom) {
                *result = HTBOTTOMRIGHT;
            } else if (left) {
                *result = HTLEFT;
            } else if (right) {
                *result = HTRIGHT;
            } else if (top) {
                *result = HTTOP;
            } else if (bottom) {
                *result = HTBOTTOM;
            }

            //先处理掉拉伸
            if (0 != *result) {
                return true;
            }

            //识别标题栏拖动产生半屏全屏效果
            if (titleBar && titleBar->rect().contains(pos)) {
                QWidget *child = titleBar->childAt(pos);
                if (!child)
                {
                    *result = HTCAPTION;
                    return true;
                }
            }
        }
        else if (msg->wParam == PBT_APMSUSPEND && msg->message == WM_POWERBROADCAST)
        {
            //系统休眠的时候自动最小化可以规避程序可能出现的问题
            this->showMinimized();
        }
        else if (msg->wParam == PBT_APMRESUMEAUTOMATIC)
        {
            //休眠唤醒后自动打开
            this->showNormal();
        }
    }
    return false;
}

//用于拖拽程序的区域
void FramelessWidget::setTitleBar(QWidget *titleBar)
{
    this->titleBar = titleBar;
    this->titleBar->installEventFilter(this);
}

SKcakor
6 声望0 粉丝