How do I toggle 'always on top' for a QMainWindow in Qt without causing a flicker or a flash?

前端 未结 4 1092
猫巷女王i
猫巷女王i 2020-12-28 15:07
void MainWindow::on_actionAlways_on_Top_triggered(bool checked)
{
    Qt::WindowFlags flags = this->windowFlags();
    if (checked)
    {
        this->setWind         


        
相关标签:
4条回答
  • 2020-12-28 15:26

    Well, for a solution I figured I'd look in the Mono sources, since I know the .NET Form class (System.Windows.Forms) has a TopMost property.

    The solution I found for my Qt program was:

    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
    }
    
    0 讨论(0)
  • 2020-12-28 15:31

    Since i recently ran into the same issue:

    You can do it by bypassing Qt. For the windows part see @JakePetroules answer.
    XCB (X11) version i use:

    #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
    

    Use like: xcb_update_prop(true, window()->winId(), "_NET_WM_STATE", "_NET_WM_STATE_ABOVE", "_NET_WM_STATE_STAYS_ON_TOP");

    Its a bit hackish, but it worked fine on Mate, KDE, GNOME3, XFCE and openbox.

    0 讨论(0)
  • 2020-12-28 15:32

    Nokia says no:

    It is not possible to make changes to the window flags once the window has been created without causing flicker. Flicker is unavoidable since the window needs to be recreated.

    But sometimes if you're stuck with a flashing effect that's kind of ugly like this, you can intentionally drag it out to make it seem like something "cool" just happened.

    Maybe pop up a little progress bar that's not in the window, say "Adjusting Window Properties!"...fade the window out of existence and then back in, and close the progress bar popup.

    0 讨论(0)
  • 2020-12-28 15:49

    Tested with

    • Qt 5.2.1 on windows XP
    • Qt 5.2 on OS X 10.9
    
        void ConsoleUI::onAllwaysTop(bool checked)
        {
            Qt::WindowFlags flags = windowFlags();
            if (checked)
            {
                flags ^= Qt::WindowStaysOnBottomHint;
                flags |= Qt::WindowStaysOnTopHint;
            }
            else
            {
                flags ^= Qt::WindowStaysOnTopHint;
                flags |= Qt::WindowStaysOnBottomHint;
            }
            setWindowFlags(flags);
            show();
        }
    
    
    0 讨论(0)
提交回复
热议问题