Qt/Windows,可调整大小的无边框窗口。

5
我是一名有帮助的助手,以下是您需要翻译的内容:

我需要创建一个无框架的Qt Windows应用程序,支持调整大小。

如果我使用

setWindowFlags(Qt::FramelessWindowHint);

那么我只能从右下角调整大小(就像使用大小调整控制柄一样,我想QMainWindow中包含它的某种形式?)。

有没有简单的方法使它可以像普通窗口一样从四个方向调整大小?也许是平台特定的(Windows?)


1
你可以处理 WM_NCHITTEST,并在 X_cursor - X_window <= SM_CXBORDER 时返回例如HTLEFT,以便处理四个方向。 - RbMm
1
请查看https://dev59.com/SFbTa4cB1Zd3GeqP-3i5#37507341 - Vladimir Bershov
1个回答

10

使用WM_NCHITTEST解决了此问题,代码基于https://bugreports.qt.io/browse/QTBUG-40578中的代码(与此无关的错误报告)。

.h

class MainWindow : public QMainWindow
{
    Q_OBJECT
......
protected:
    bool nativeEvent(const QByteArray& eventType, void* message, long* result) override;
};

.cpp

bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, long* result)
{
    MSG* msg = static_cast<MSG*>(message);

    if (msg->message == WM_NCHITTEST)
    {
        if (isMaximized())
        {
            return false;
        }

        *result = 0;
        const LONG borderWidth = 8;
        RECT winrect;
        GetWindowRect(reinterpret_cast<HWND>(winId()), &winrect);

        // must be short to correctly work with multiple monitors (negative coordinates)
        short x = msg->lParam & 0x0000FFFF;
        short y = (msg->lParam & 0xFFFF0000) >> 16;

        bool resizeWidth = minimumWidth() != maximumWidth();
        bool resizeHeight = minimumHeight() != maximumHeight();
        if (resizeWidth)
        {
            //left border
            if (x >= winrect.left && x < winrect.left + borderWidth)
            {
                *result = HTLEFT;
            }
            //right border
            if (x < winrect.right && x >= winrect.right - borderWidth)
            {
                *result = HTRIGHT;
            }
        }
        if (resizeHeight)
        {
            //bottom border
            if (y < winrect.bottom && y >= winrect.bottom - borderWidth)
            {
                *result = HTBOTTOM;
            }
            //top border
            if (y >= winrect.top && y < winrect.top + borderWidth)
            {
                *result = HTTOP;
            }
        }
        if (resizeWidth && resizeHeight)
        {
            //bottom left corner
            if (x >= winrect.left && x < winrect.left + borderWidth &&
                y < winrect.bottom && y >= winrect.bottom - borderWidth)
            {
                *result = HTBOTTOMLEFT;
            }
            //bottom right corner
            if (x < winrect.right && x >= winrect.right - borderWidth &&
                y < winrect.bottom && y >= winrect.bottom - borderWidth)
            {
                *result = HTBOTTOMRIGHT;
            }
            //top left corner
            if (x >= winrect.left && x < winrect.left + borderWidth &&
                y >= winrect.top && y < winrect.top + borderWidth)
            {
                *result = HTTOPLEFT;
            }
            //top right corner
            if (x < winrect.right && x >= winrect.right - borderWidth &&
                y >= winrect.top && y < winrect.top + borderWidth)
            {
                *result = HTTOPRIGHT;
            }
        }

        if (*result != 0)
            return true;

        QWidget *action = QApplication::widgetAt(QCursor::pos());
        if (action == this){
            *result = HTCAPTION;
            return true;
        }
    }

    return false;
}

来自Qt:调整无边框小部件的大小的实现不够好:有时在调整大小期间窗口会移动(即使是在没有拖动的第一个版本中)


我尝试了你的答案,但当从左侧或顶部边框调整大小时,我的窗口会频繁闪烁,你也遇到这种情况吗? - Nikolas
这在Qt5下对我很有效,但如果尝试在Qt6下构建(仅将long*更改为qintptr*似乎不起作用)则似乎不再起作用。 有什么想法为什么? - Gary Wang
回答自己的评论。在Qt 6中存在一个相关的Qt bug,如果您为无边框窗口使用Qt::WindowMinMaxButtonsHint窗口标志(例如,为确保Winkey+Up/Down快捷键正常工作),则此解决方案将不再起作用。删除此标志将使其再次起作用,请参见QTBUG-112356获取详细信息。 - Gary Wang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接