有一个容器 Widget 实例 A,并且包含 Widget 实例 C1、C2、C3、...等在 A 内。
有一个插槽处理小部件 A 的 action_triggreed() 信号。
有没有办法确定哪个目标小部件 C1、C2、C3、...被点击了?这种必要性的原因是包含许多小部件,并且在每个小部件上使用connect()方法没有意义,这将需要50+行额外的连接语句,每个一个!
例如:考虑一个有很多按钮的QToolBox。您将如何使用 QToolBox action_triggered或类似信号来确定按下哪个按钮,而无需分别使用单个按钮的信号和插槽?
QObject::sender()
函数。
void A::triggeredSlot() {
QObject* obj = sender();
QButton* but = qobject_cast<QButton*>(obj);
}
只需使用正确的类型等。
有几种通用方法。
第一个很简单 - 您应该将每个小部件的信号连接到插槽并检查sender()
是什么。是的,用于连接的代码行。
第二种是使用一种映射器。每个小部件都连接到映射器,只有映射器连接到目标插槽。再次是代码行,至少在将小部件连接到映射器的部分中。有一个通用QSignalMapper
或者您可以使用适合您的小部件的更具体的。例如,如果它们是按钮,则可以使用QButtonGroup
类。每个按钮都在组中注册,只需要一个信号/插槽连接。
QButtonGroup group;
group->addButton(buttonC1,C1_ID);
...
group->addButton(buttonC1,Cn_ID);
connect(&group,SIGNAL(buttonClicked(QAbstractButton*),this,SLOT(buttonClicked(QAbstractButton*));
第三种方法是仅在母亲的小部件 A 上检测鼠标事件,然后遍历其所有子项并找到鼠标下的一个。更少的代码,您可以轻松添加新的小部件,但成本是在运行时遍历所有小部件。下面是一个示例。请注意,您可以将特定的QObject
名称或属性添加到小部件 C1...这样,如果您只对给定类型的子小部件的一部分感兴趣,则可以过滤它们。
void mousePressEvent(QMouseEvent* event)
{
if (event->button()==Qt::LeftButton)
{
QList<QToolButton*> buttons=findChildren<QToolButton*>(); // you can also use specific object names on the widgets under your interest
foreach (QToolButton* button, buttons)
{
if (button->underMouse()) // you could try isDown() for button, but I'm not sure if that will work here
{
emit buttonClicked(button);
break;
}
}
}
}
好吧,您也可以尝试另一种方法。检测鼠标事件,获取光标位置并找到该位置上的子小部件。运行时成本不高。
void mousePressEvent(QMouseEvent* event)
{
if (event->button()==Qt::LeftButton)
{
QPoint pt=mapFromGlobal(QCursor::pos());
QWidget* child=childAt(pt);
if (child)
{
emit childClicked(child);
}
}
}