如何在Qt中分层独立的小部件?

我正在使用Qt创建一个应用程序,它包含一个用作应用程序背景的小部件,以及一个浮动在上面的用户控制界面 .

类似的示例是谷歌 Map ,其中 Map 位于背景上,控件位于背景之上 .

但问题是背景小部件可以更改为不同的小部件(有一个显示 Map 的小部件,另一个显示视频输入的小部件,......)

对于用户控制界面中的按钮也会发生同样的事情,它们与当前背景没有直接关系,可以通过动态更改 .

我尝试使用QStackedLayout,使用两个层,后台小部件和用户控制界面 . 但是您无法与背景图层进行交互,因为前面的窗口小部件会阻止所有点击 .

有什么建议?

回答(3)

2 years ago

您可以使用 QObject::installEventFilter() 函数将事件流的过滤器放置到接口窗口小部件,并拦截所有传入的鼠标单击事件 . 捕获这些事件后,使用过滤器功能将它们委派给后台窗口小部件,或将它们传递到前端接口按钮 . 您很可能必须使用鼠标单击的(x,y)坐标来确定事件是应该转到后台窗口小部件还是其中一个前景按钮窗口小部件 .

另一种选择是从 QAbstractButton (或者您用于按钮的任何QWidget)创建派生类,并重新实现事件函数以便在该窗口小部件上单击鼠标(即 QAbstractButton::mousePressEvent() 等) . 当鼠标单击到达时,检查鼠标是否在按钮上,如果不是,则通过信号或 QCoreApplication::sendEvent() 将事件发送到后台窗口小部件 .

2 years ago

您的问题过于通用,无法给出具体答案,但最明显的解决方案是为系统的每个可能组件实现从QWidget继承的类 . 在您的示例中,我可以可视化2个不同的组件:背景和控件 . 背景将存储所有图像数据,如 Map 和视频,而控件将具有与系统交互的按钮 . 您甚至可以将背景分成不同的类来管理图像或视频 . 我建议使用继承自QObject的中央GUIController类来管理所有接口交互,例如连接信号/插槽或实现任何动画,这样您就可以添加/管理多个小部件而无需通过不同的.cpp .

EDIT: 根据您的评论,似乎您的主要问题是您的鼠标事件没有像您预期的那样传播到您的小部件 . 可能原因是您没有在组件之间设置父/子关系 . 确保在上面的自定义窗口小部件类中调用默认的QWidget构造函数:

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

创建Controller类时,设置组件之间的正确关系 . 在你的系统环境中,我认为所有组件都将作为Background子项添加,所以它如下所示:

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_;
}

2 years ago

好的,我终于为我的问题找到了解决方案 .

我使用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上的鼠标事件,这就是我所需要的 .

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