当对话框中的任何小部件发出信号时,是否可以调用插槽?

时间:2017-05-31 04:51:24

标签: c++ qt qt5

我正在尝试为应用程序创建配置菜单框,并使用QDialog框显示用户可以更改的选项。这个盒子包含QComboBoxes和QLineEdits,但是很多(7个组合框和12行编辑)。底部有一个QPushButton,名为" Apply Changes"只有在框中的任何属性发生变化时才能启用。

我是否必须将来自每个小部件的每个信号与一个插槽链接以单独启用该按钮,或者当其组成小部件发生更改时,是否有QDialog框本身发出的信号?

现在我有这个:

connect(Combo1,SIGNAL(activated(QString)),this,SLOT(fnEnable(QString)));
connect(Combo2,SIGNAL(activated(QString)),this,SLOT(fnEnable(QString)))

接着是另外17行这些连接。

void MyClass::fnEnable(QString)
{
ApplyButton->setEnabled(true); //It is initialised as false
}

我想知道是否有更短的方法可以做到这一点,也许(就像我之前提到的那样)QDialog发出的信号(我无法在documentation找到一个)

我知道这不会加快程序的速度,因为只调用了所需的连接,但它会进一步尝试制作更加雄心勃勃的对话框。

2 个答案:

答案 0 :(得分:3)

实际上没有这样的信号,但一种方法是创建一个QComboBox列表,并与for建立连接,例如:

QList <*QCombobox> l; 
l<<combobox1<< combobox2<< ....; 
for (auto combo: l) {
    connect(combo, SIGNAL(activated(QString)), this, SLOT(fnEnable(QString))
}.

QLineEdit也是如此。

答案 1 :(得分:0)

您可以迭代窗口小部件框的初始化列表,并利用C ++ 11为您完成所有无聊的工作:

MyClass::MyClass(QWidget * parent) : QWidget(parent) {
  auto const comboBoxes = {Combo1, Combo2, ... };
  for (auto combo : comboBoxes)
    connect(combo, &QComboBox::activates, this, &MyClass::fnEnable);
}

您还可以自动查找所有组合框:

MyClass::MyClass(QWidget * parent) : QWidget(parent) {
  ui.setupUi(this); // or other setup code
  for (auto combo : findChildren<QComboBox*>(this))
    connect(combo, &QComboBox::activated, this, &MyClass::fnEnable);
}

或者您可以自动附加到用户属性的更改信号。这将适用于具有user属性的所有控件。 user属性是控件的属性,该控件包含控件正在显示的主数据。

void for_layout_widgets(QLayout * layout, const std::function<void(QWidget*)> & fun, 
                        const std::function<bool(QWidget*)> & pred = +[](QWidget*){ return true; })
{
  if (!layout) return;
  for (int i = 0; i < layout->count(); ++i) {
    auto item = layout->itemAt(i);
    for_layout_widgets(item->layout(), fun, pred);
    auto widget = item->widget();
    if (widget && pred(widget)) fun(widget);
  }
}

class MyClass : public QWidget {
  Q_OBJECT
  Q_SLOT void MyClass::fnEnable(); // must take no arguments
  ...
};

MyClass::MyClass(QWidget * parent) : QWidget(parent) {
  // setup code here
  auto slot = metaObject()->method(metaObject()->indexOfMethod("fnEnable()"));
  Q_ASSERT(slot.isValid());
  for_layout_widgets(layout(), [=](QWidget * widget){
    auto mo = widget->metaObject();
    auto user = mo->userProperty();
    if (!user.isValid()) return;
    auto notify = user.notifySignal();
    if (!notify.isValid()) return;
    connect(widget, notify, this, slot);
  });
}   

您还可以按值将组合框保留在数组中。这最大限度地降低了间接引用的成本,并导致代码占用最少的内存并且性能良好:

class MyClass : public QWidget {
  Q_OBJECT
  QVBoxLayout m_layout{this};
  std::array<QComboBox, 14> m_comboBoxes;
  ...
};

MyClass(QWidget * parent) : QWidget(parent) {
  for (auto & combo : m_comboBoxes) {
    m_layout.addWidget(&combo);
    connect(&combo, &QComboBox::activates, this, &MyClass::fnEnable);
  }
}