我对qt信号槽系统有疑问。
首先,我创建了一个名为System in Singleton模式的类,因此我可以访问我想要的实例。系统有一个信号SelectionChanged。
我有一个列表小部件,我将它的itemSelectionChanged信号连接到我的自定义插槽,该插槽名为onSelectionChanged。在onSelectionChanged插槽中,我发出System的SelectionChanged信号。还没有问题。
在我的软件设计中,许多GUI小部件或自定义类可以使用一系列对象,System的SelectionChanged信号可以由列表小部件以外的小部件发出。
所以我在列表小部件中创建一个名为OnSystemSelectionChanged的插槽,然后将其连接到System的SelectionChanged信号。 OnSystemSelectionChangedSlot就是这样。
void MyListWidget::OnSystemSelectionChanged(QObject *sender)
{
if (sender == this) return;
// Then I want to get a list of selected objects and set them as selection of this widget like this:
this->SetSelection(System::Instance()->GetSelectedObjects());
}
但问题是当我开始设置列表小部件的所选项时,它将发出itemSelectionChanged信号并且将调用我的onSelectionChanged插槽。然后插槽将发出System的SelectionChanged信号,然后也将调用OnSystemSelectionChanged。它将通过发送者参数停止,但没有方法可以立即设置列表小部件的所选项目。
我怎样才能解决这个问题。
我希望我能很好地解释我的问题。提前谢谢。
编辑:更正了拼写和语法错误。
答案 0 :(得分:8)
在Qt中有几种方法可以解决这个问题。
对一个基础模型使用多个视图。这会自动处理对多个视图控件的更改传播,您无需执行任何额外操作。您可以使用QDataWidgetMapper
将“普通旧”小部件链接到模型中的数据元素。我会说这应该是首选的做事方式。无论如何,为所有用户界面建立基础模型都是朝着良好软件设计方向迈出的一步。
在数据模型之间传播更改时,请同时实施DisplayRole
和EditRole
。视图将使用其中一个角色(例如EditRole
)名义上修改模型,而您可以通过编程方式使用其他角色(例如DisplayRole
)修改模型。您可以在自己的插槽中处理来自模型的dataChanged
信号,正确处理角色,并在其他模型上使用其他角色调用setData
。这可以防止循环。
对于非QAbstractItemView
s的控件,请实现两个信号:一个在任何更改时发出,另一个仅在基于键盘/鼠标输入的更改时发出。这是QAbstractButton
公开的界面,例如:toggled(bool)
信号是前者,clicked()
是后者。然后,您只能连接到基于输入的信号。
您自己的代码必须将编程更改传播到所有相互关联的控件,因为从代码中更改一个控件不会修改其他控件。这应该不是问题,因为设计良好的代码应该从其余代码封装UI控件的实现细节。因此,对话框/窗口类将以一种与显示特定属性的控件数量无关的方式公开其属性。
使用禁止信号发射的标志(Bartosz's answer)。
在更改期间(Bartosz's answer)中断信号/插槽连接。
使用QObject::blockSignals()
。
答案 1 :(得分:2)
我能想到两种可能的解决方案:
void MyListWidget::OnSystemSelectionChanged(QObject *sender)
{
if (sender == this || inhibitSelectionChanged)
return;
this->inhibitSelectionChanged = true;
this->SetSelection(System::Instance()->GetSelectedObjects());
this->inhibitSelectionChanged = false;
}
void MyListWidget::OnSystemSelectionChanged(QObject *sender)
{
if (sender == this)
return;
this->disconnect(SIGNAL(SelectionChanged()));
this->SetSelection(System::Instance()->GetSelectedObjects());
this->connect(
this, SIGNAL(SelectionChanged()),
this, SLOT(OnSystemSelectionChanged(QObject*)));
}
答案 2 :(得分:2)
我在QObject :: blockSignals()方法中找到了我的解决方案。当我设置所选项目时,它将阻止从列表小部件发出信号。
感谢BartoszKP的所有答案和解决方案。这个解决方案看起来像是他第一个解决方案的官方方式。
答案 3 :(得分:1)
问题:你试图偷工减料并创造了一个单身人士。不是单身人士的经典案例。
信号和插槽用于通知,每个对象通知感兴趣的对象它做了什么或反映其新状态。
我建议改变设计如下: