2012-02-07 57 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上的鼠标事件,这正是我所需要的。

我会测试一段时间,如果工作正常,我会关闭这个问题。