1. 程式人生 > >Qt之使用setWindowFlags方法遇到的問題

Qt之使用setWindowFlags方法遇到的問題

一、簡述

前段時間在使用setWindowFlags方法時遇到了一個坑,具體情況是想通過視窗介面上一個checkBox來控制視窗當前狀態是否置頂,而Qt提供了Qt::WindowStaysOnTopHint標誌,能夠讓視窗始終保持在其他視窗前端,也就是將視窗置頂。

理論上,我們在勾選上checkBox之後將Qt::WindowStaysOnTopHint標誌設定上,就會將視窗置頂,結果卻將視窗隱藏了。那麼為什麼第二次呼叫setWindowFlags設定視窗標誌位時視窗會隱藏了呢(實際上呼叫了hide()方法),下面就看一下具體是什麼原因導致的。

這裡寫圖片描述

Qt::WindowStaysOnTopHint

Informs the window system that the window should stay on top of all other windows. Note that on some window managers on X11 you also have to pass Qt::X11BypassWindowManagerHint for this flag to work correctly.

二、分析視窗隱藏原因

首先我們看一下程式碼,在建構函式中我們繫結checkBox,然後設定視窗屬性。

this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint)
; connect(ui.checkBox, SIGNAL(stateChanged(int)), this, SLOT(onStateChanged(int)));

checkBox狀態變化槽函式

void onStateChanged(int state)
{
    if (state == Qt::Unchecked)
    {
        // 未勾選時不置頂;
        this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint);
    }
    else if (state ==
Qt::Checked) { // 勾選時置頂; this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint | Qt::WindowStaysOnTopHint); } }

想要查詢原因,那就得直接看Qt原始碼呀,所以就直接跟進了qwidget.cpp中的setWindowFlags方法。

這裡寫圖片描述

除錯之後,發現進入了setParent方法,我們仔細看一下,在setParent方法中確實會呼叫hide方法,那什麼時候會呼叫呢,首先是判斷視窗是否被建立,然後是視窗是否被隱藏,也就是如果視窗被建立並且沒有被隱藏時會呼叫hide方法。下面是在建構函式中呼叫setWindowFlags時,wasCreated為false,也不會呼叫hide,而且當時視窗並未建立,所以在視窗未建立時無論呼叫多少次setWindowFlags方法,都會以最後一次呼叫時傳入的引數為準。

這裡寫圖片描述

下面是在視窗中勾選了checkBox,然後再次呼叫了setWindowFlags方法,此時滿足視窗被建立並且沒有被隱藏條件,所以這裡呼叫了hide方法將視窗隱藏了,終於找到了原因。

這裡寫圖片描述

那麼也不是沒有辦法解決視窗置頂問題,windows提供了SetWindowPos方法解決了視窗置頂的問題。如果我們想一直保持視窗置頂狀態也可以在視窗初始化時呼叫setWindowFlags方法傳入Qt::WindowStaysOnTopHint標誌即可使視窗置頂。

如果兩個視窗都是置頂狀態,如果層疊在一起也會相互覆蓋。

解決辦法一:

void onStateChanged(int state)
{
    if (state == Qt::Unchecked)
    {
        ::SetWindowPos((HWND)this->winId(), HWND_NOTOPMOST, this->pos().x(), this->pos().y(), width(), height(), SWP_SHOWWINDOW);
    }
    else if (state == Qt::Checked)
    {
        ::SetWindowPos((HWND)this->winId(), HWND_TOPMOST, this->pos().x(), this->pos().y(), width(), height(), SWP_SHOWWINDOW);
    }
}

解決辦法二:

void onStateChanged(int state)
{
    if (state == Qt::Unchecked)
    {
        // 未勾選時不置頂;
        this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint);
        // 如果當前視窗不可見,則顯示出來;
        if (!this->isVisible())
        {
            setVisible(true);
        }
    }
    else if (state == Qt::Checked)
    {
        // 勾選時置頂;
        this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint | Qt::WindowStaysOnTopHint);
        // 如果當前視窗不可見,則顯示出來;
        if (!this->isVisible())
        {
            setVisible(true);
        }
    }
}

更新於2017_7_12。