2012-02-07 61 views
5

我正在創建一個使用Qt的應用程序,它由一個用作應用程序背景的小部件和一個浮動在上面的用戶控件接口組成。如何在Qt中分層獨立的小部件?

一個類似的例子是谷歌地圖,其中地圖在背景上,控件位於背景之上。

但事實是,背景小部件可以被改變爲不同的小部件(有這個顯示地圖,顯示視頻輸入另一個部件,一個部件...)

,同樣的事情發生在用戶控制界面中的按鈕,它們與當前背景沒有直接關係,並且可以進行改變。

我試過使用QStackedLayout,使用兩層,後臺部件和用戶控制界面。但是您無法與背景圖層進行互動,因爲所有點擊均被前面的小部件阻止。

有什麼建議嗎?

回答

1

你的問題太籠統了,不能給你一個特定的答案,但最明顯的解決方案是實現從QWidget繼承的類爲你的系統的每個可能的組件。在你的例子中,我可以看到兩個不同的組件:背景和控件。背景將存儲所有圖像數據,如地圖和視頻,而控件將具有與系統交互的按鈕。你甚至可以將背景分成不同的類來管理圖像或視頻。我建議使用從QObject繼承的中央GUIController類來管理所有接口交互,如連接信號/插槽或實現任何動畫,這樣您可以添加/管理多個小部件,而無需通過不同的.cpp文件。

編輯:隨着您的評論,似乎你的主要問題是,你的鼠標事件沒有傳播到你的小部件,如你所料。可能的原因是你沒有設置組件之間的父/子關係。請確保您所呼叫的默認構造函數QWidget的在您的自定義小部件類像上面:

CustoWidget(QWidget *parent = 0, Qt::WFlags flags = 0) : QWidget(parent, flags) 
{ 
//your code here 
} 

當創建一個Controller類,集中的組件之間的正確關係。在您的系統的情況下,作用似乎對我來說,所有組件都將被添加爲背景的孩子,所以它看起來象下面這樣:

class Controller : public QObject 
{ 
public: 
    Controller(QObject *parent = 0, Qt::WFlags flags = 0) : QObject(parent, flags) 
    { 
    wdg_back_= new BackWidget(this); 
    wdg_control_ = new Controls(wdg_back); 
    wdg_1_ = new GenericWidget(wdg_back); 

    //connect your signals/slots, etc 
    } 

private: 
    BackWidget *wdg_back_; 
    Controls *wdg_control_; 
    GenericWidget *wdg_1_; 
} 
+1

這就是我遵循的方法,我將所有控件分組到一個小部件中,其中包含適當的佈局。但問題是,即使屏幕上分散了一些小部件,此控件Widget佔據整個屏幕並阻止鼠標單擊事件。我相信可以解決這個問題的另一件事是,將堆疊小部件上的控件逐個添加爲單獨的圖層。這樣他們只會阻止在它們上面的鼠標點擊。 – Victor 2012-02-07 13:51:26

+0

您確定要將所有小部件添加爲此控件/背景部件的子項嗎?確保你的自定義小部件構造函數調用QWidget默認構造函數,並且在GUI初始化過程中將持有者小部件(可能是背景)設置爲所有小部件的父親。 – 2012-02-07 14:27:27

+0

這個問題似乎是這裏討論的問題:http://www.qtcentre.org/threads/45844-Mouse-events-with-StackAll-QStackedLayout 由於我使用了一個有兩個小部件的堆棧佈局(背景和控件控件),頂部的控件控件將阻止所有鼠標單擊事件。 我會嘗試將控件設置爲背景的子項,而不是他們是兄弟。 – Victor 2012-02-07 15:19:52

2

你可以在事件流的過濾器將使用QObject::installEventFilter()您的接口部件函數,並攔截所有傳入的鼠標單擊事件。一旦捕獲了這些事件,使用過濾器功能將它們委託給後臺小部件,或者將它們交付給前端界面按鈕。您很可能必須使用鼠標單擊的(x,y)座標來確定事件是否應該轉到背景小部件或前景按鈕小部件之一。

另一種選擇是創建QAbstractButton派生類(或任何QWidget的您正在使用您的按鈕),並重新實現對窗口小部件(即QAbstractButton::mousePressEvent()等)鼠標點擊事件函數。當鼠標點擊到達時,檢查鼠標是否在按鈕上,如果不是,則通過信號或QCoreApplication::sendEvent()將事件發送到後臺小部件。

+0

這是一個很好的方法,我沒有想到,如果我不能找到另一種方法將它們放置出來而不阻止鼠標單擊事件,我肯定會執行此操作。 – Victor 2012-02-07 13:38:23

+0

我試過實現這一點,目前我試圖只是將所有mousePressEvents轉發到背景部件:QCoreApplication :: sendEvent(_bgWidget,ev);在mousePressEvent處理程序中,但它們在後臺小部件的父級中接收,而不是在後臺小部件本身中接收。 – Victor 2012-02-07 15:35:08

+1

您的背景對象也必須重新實現'mousePressEvent()'或'event()'以便能夠正確處理您發送的事件......否則這些函數在基類中的默認實現您來源於意願的人會簡單地返回「假」,然後父母將成爲事件的接收者。 – Jason 2012-02-07 17:03:07

0

好吧,我終於找到了我的問題的解決方案。

我使用QStackedWidget的方法是錯誤的,背景上的小部件並不意味着可點擊,即使它可能已完成,但這不是我所期待的。

最後,這是我做了什麼:

QWidget *centralWidget = new QWidget(this); 
setCentralWidget(centralWidget); 

MapView *backgroundWidget = new MapView(centralWidget); 
backgroundWidget->setMinimumSize(1024,600); 

QGridLayout *controlsLayout = new QGridLayout(centralWidget); 
MyControlWidget *control1 = new MyControlWidget(centralWidget); 
control1->setMinimumSize(140,140); 
control1->show(); 

controlsLayout->addWidget(control1,2,0); 

所以我創建一個QWidget,centralWidget這將是背景與前景的父。將背景設置爲全屏,並在QGridLayout中組織控件,但不影響backgroundWidget。

如果我點擊一個控件,事件由這個控件處理,但是單擊一個空白的空間會觸發backgroundWidget上的鼠標事件,這正是我所需要的。

我會測試一段時間,如果工作正常,我會關閉這個問題。