26
void MainWindow::on_actionAlways_on_Top_triggered(bool checked)
{
    Qt::WindowFlags flags = this->windowFlags();
    if (checked)
    {
        this->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint);
        this->show();
    }
    else
    {
        this->setWindowFlags(flags ^ (Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint));
        this->show();
    }
}

上述解决方案有效,但由于 setWindowFlags 隐藏了窗口,因此需要重新显示它,当然这看起来不太优雅。那么如何在没有“闪烁”副作用的情况下为 QMainWindow 切换“始终在顶部”?

4

4 回答 4

20

诺基亚说不

一旦创建了窗口,就不可能在不引起闪烁的情况下更改窗口标志。闪烁是不可避免的,因为需要重新创建窗口。

但有时,如果你被这样一种丑陋的闪光效果卡住了,你可以故意把它拖出来,让它看起来像是刚刚发生的“很酷”的事情。

也许会弹出一个不在窗口中的小进度条,说“正在调整窗口属性!”...使窗口不存在然后重新进入,然后关闭进度条弹出窗口。

于 2010-05-18T09:41:20.773 回答
20

好吧,对于一个解决方案,我想我会查看 Mono 源,因为我知道 .NET Form 类 (System.Windows.Forms) 具有 TopMost 属性。

我为我的 Qt 程序找到的解决方案是:

void MainWindow::on_actionAlways_on_Top_triggered(bool checked)
{
#ifdef Q_OS_WIN
    // #include <windows.h>
    if (checked)
    {
        SetWindowPos(this->winId(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
    }
    else
    {
        SetWindowPos(this->winId(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
    }
#else
    Qt::WindowFlags flags = this->windowFlags();
    if (checked)
    {
        this->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint);
        this->show();
    }
    else
    {
        this->setWindowFlags(flags ^ (Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint));
        this->show();
    }
#endif
}
于 2010-05-18T20:12:40.787 回答
0

由于我最近遇到了同样的问题:

您可以通过绕过 Qt 来做到这一点。对于 Windows 部分,请参阅@JakePetroules 答案。
我使用的 XCB (X11) 版本:

#ifdef Q_OS_LINUX
#include <QX11Info>
#include <xcb/xcb.h>

// Just a simple atom cache helper
xcb_atom_t xcb_get_atom(const char *name){
    if (!QX11Info::isPlatformX11()){
        return XCB_ATOM_NONE;
    }
    auto key = QString(name);
    if(_xcb_atom_cache.contains(key)){
        return _xcb_atom_cache[key];
    }
    xcb_connection_t *connection = QX11Info::connection();
    xcb_intern_atom_cookie_t request = xcb_intern_atom(connection, 1, strlen(name), name);
    xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, request, NULL);
    if(!reply){
        return XCB_ATOM_NONE;
    }
    xcb_atom_t atom = reply->atom;
    if(atom == XCB_ATOM_NONE){
        DEBUG("Unknown Atom response from XServer: " << name);
    } else {
        _xcb_atom_cache.insert(key, atom);
    }
    free(reply);
    return atom;
}

void xcb_update_prop(bool set, WId window, const char *type, const char *prop, const char *prop2)
{
    auto connection = QX11Info::connection();
    xcb_atom_t type_atom = xcb_get_atom(type);
    xcb_atom_t prop_atom = xcb_get_atom(prop);
    xcb_client_message_event_t event;
    event.response_type = XCB_CLIENT_MESSAGE;
    event.format = 32;
    event.sequence = 0;
    event.window = window;
    event.type = type_atom;
    event.data.data32[0] = set ? 1 : 0;
    event.data.data32[1] = prop_atom;
    event.data.data32[2] = prop2 ? xcb_get_atom(prop2) : 0;
    event.data.data32[3] = 0;
    event.data.data32[4] = 0;

    xcb_send_event(connection, 0, window,
                   XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_PROPERTY_CHANGE,
                   (const char *)&event);
    xcb_flush(connection);
}
#endif

像这样使用: xcb_update_prop(true, window()->winId(), "_NET_WM_STATE", "_NET_WM_STATE_ABOVE", "_NET_WM_STATE_STAYS_ON_TOP");

它有点 hackish,但它在 Mate、KDE、GNOME3、XFCE 和 openbox 上运行良好。

于 2020-08-25T02:44:41.543 回答
-2

经测试

  • Windows XP 上的 Qt 5.2.1
  • OS X 10.9 上的 Qt 5.2
    无效 ConsoleUI::onAllwaysTop(布尔检查)
    {
        Qt::WindowFlags 标志 = windowFlags();
        如果(选中)
        {
            标志 ^= Qt::WindowStaysOnBottomHint;
            标志 |= Qt::WindowStaysOnTopHint;
        }
        别的
        {
            标志 ^= Qt::WindowStaysOnTopHint;
            标志 |= Qt::WindowStaysOnBottomHint;
        }
        设置窗口标志(标志);
        显示();
    }

于 2014-03-24T06:03:51.200 回答