You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何检测Linux下Qt窗口是否被用户设置为始终置顶?

检测Qt窗口是否被用户手动设置为始终置顶

嘿,这个问题我之前踩过坑!你说的没错,直接查windowFlags()里的Qt.WindowStaysOnTopHint确实没用——因为这个标志是咱们代码里主动设置的标识,而用户通过系统自带的窗口操作(比如Windows右键窗口标题栏选“始终置顶”、macOS在窗口菜单里设“置于顶层”)改的状态,属于系统层面的操作,Qt根本不会把这个变化同步到它自己维护的windowFlags里。

要检测用户手动设置的置顶状态,得借助对应平台的原生API来获取窗口的实际系统状态,下面分平台给你具体实现:

Windows平台实现

调用Win32 API检查窗口的WS_EX_TOPMOST扩展样式:

#include <windows.h>

bool isWindowAlwaysOnTop(QWidget *widget) {
    HWND hwnd = reinterpret_cast<HWND>(widget->winId());
    return (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
}

macOS平台实现

通过Cocoa API获取窗口的层级,判断是否处于置顶层级:

#include <Cocoa/Cocoa.h>

bool isWindowAlwaysOnTop(QWidget *widget) {
    NSWindow *nsWindow = reinterpret_cast<NSWindow*>(widget->winId());
    // 置顶窗口通常处于NSStatusWindowLevel或更高层级
    return nsWindow.level >= NSStatusWindowLevel;
}

Linux(X11)平台实现

通过Xlib读取窗口的_NET_WM_STATE属性,检查是否包含_NET_WM_STATE_ABOVE

#include <X11/Xlib.h>
#include <X11/Xatom.h>

bool isWindowAlwaysOnTop(QWidget *widget) {
    Display *display = XOpenDisplay(nullptr);
    if (!display) return false;

    Window winId = static_cast<Window>(widget->winId());
    Atom netWmState = XInternAtom(display, "_NET_WM_STATE", False);
    Atom netWmStateAbove = XInternAtom(display, "_NET_WM_STATE_ABOVE", False);

    Atom *prop = nullptr;
    int format;
    unsigned long numItems, bytesAfter;
    int status = XGetWindowProperty(display, winId, netWmState, 0L, 1024L, False,
                                    XA_ATOM, &prop, &format, &numItems, &bytesAfter);

    bool isOnTop = false;
    if (status == Success && prop != nullptr) {
        for (unsigned long i = 0; i < numItems; ++i) {
            if (prop[i] == netWmStateAbove) {
                isOnTop = true;
                break;
            }
        }
        XFree(prop);
    }

    XCloseDisplay(display);
    return isOnTop;
}

在closeEvent中保存状态

有了检测函数,就可以在窗口关闭时获取状态并保存(这里用QSettings存配置):

void YourWidget::closeEvent(QCloseEvent *event) {
    bool isOnTop = isWindowAlwaysOnTop(this);
    // 保存到配置文件
    QSettings settings("YourCompanyName", "YourAppName");
    settings.setValue("Window/AlwaysOnTop", isOnTop);
    
    QWidget::closeEvent(event);
}

下次启动时恢复状态

在窗口初始化或者showEvent里读取配置并恢复:

void YourWidget::showEvent(QShowEvent *event) {
    QSettings settings("YourCompanyName", "YourAppName");
    bool shouldStayOnTop = settings.value("Window/AlwaysOnTop", false).toBool();
    
    if (shouldStayOnTop) {
        // 设置置顶标志并重新显示窗口(修改窗口标志后需要重新show)
        this->setWindowFlags(this->windowFlags() | Qt::WindowStaysOnTopHint);
        this->show();
    }
    
    QWidget::showEvent(event);
}

内容的提问来源于stack exchange,提问作者Elad Weiss

火山引擎 最新活动