检查ui元素的值是否已更改

时间:2014-04-03 13:05:28

标签: qt connect qdialog selectionchanged textchanged

有没有办法检查对话框的ui元素(行编辑,组合框等)是否已更改。

我想要的是在用户更改任何单个ui元素的值时向用户显示一条消息,说明细节已部分填充。

我能做的是为每个ui元素使用connect&根据每个元素的值更改,我设置一个布尔标志&在关闭事件发生时,我正在检查布尔标志 但是为每个小部件检查它非常复杂。 有没有更简单的方法。 我用于单个ui元素的代码是,

connect(ui->leAge,SIGNAL(textChanged(QString)),this,SLOT(functChanged())); //In Constructor

void DemoDialog::functChanged()   //Will be called if value of line edit (ui->leAge) is changed
{
    flag=true;
}

void DemoDialog::closeEvent(QCloseEvent *event)
{
 if (flag) {
    if (QMessageBox::warning(this,"Close","Do you want to close?",QMessageBox::Yes|QMessageBox::No)==QMessageBox::Yes) {
        this->close();
   }
}

2 个答案:

答案 0 :(得分:2)

您无法重新实施closeEvent以阻止关闭窗口。您执行的close()调用是冗余调用或错误调用(无限递归),因为closeEvent方法调用只是通知即将关闭的一种方式。那时候做任何事都为时已晚。

请记住以下内容:

  1. 关闭对话框通常相当于取消对话框。只需单击“确定”即可接受更改。

  2. 当用户想要关闭对话框时,您不必向他们询问相关信息。他们发起了这一行动。但是:

  3. 如果在OS X以外的平台上没有接受的更改,则询问用户关于对话框关闭是正确的。

  4. 所以,你必须做几件事:

    1. 重新实现void event(QEvent*)方法。这允许您拒绝关闭事件。

    2. 提供Apply/Reset/Cancel按钮。


    3. 您的旗帜方法可以自动化。您可以找到对话框的所有控件并自动设置连接。对于每种类型的控件重复以下声明 - 这会很快变得乏味:

      foreach(QTextEdit* w, findChildren<QTextEdit*>())
        connect(w, SIGNAL(textChanged(QString)), SLOT(functChanged()));
      

      您可以利用元属性系统。大多数控件都有user属性 - 这是保存控件主要值的属性(如文本,选定项等)。您可以扫描所有窗口小部件子项,并将用户属性的属性更改通知信号连接到您的标志:

      QMetaMethod slot = metaObject().method(
                           metaObject().indexOfSlot("functChanged()"));
      foreach (QWidget* w, findChildren<QWidget*>()) {
        QMetaObject mo = w->metaObject();
        if (!mo.userProperty().isValid() || !mo.userProperty().hasNotifySignal())
          continue;
        connect(w, mo.notifySignal(), this, slot);
      }
      

      每个小部件都是QObject。 QObjects可以具有属性,其中一个属性可以声明为用户属性。大多数可编辑的窗口小部件控件都具有这样的属性,它表示用户输入(文本,数值,项目的选定索引等)。通常这些属性也具有变化通知信号。所以你要做的就是得到表示通知信号的QMetaMethod,并将它连接到设置标志的函数。


      要确定更改的字段,您不一定需要标记。在许多对话框中,有一个表示对话框中数据的数据结构是有意义的。然后,您可以使用getset方法从对话框中检索数据,或在对话框中设置它。要检查更改的数据,只需将原始数据与当前数据进行比较:

      struct UserData {
        QString name;
        int age;
        UserData(const QString & name_, int age_) :
          name(name_), age(age_) {}
        UserData() {}
      };
      
      class DialogBase : public QDialog {
        QDialogButtonBox m_box;
      protected:
        QDialogButtonBox & buttonBox() { return m_box; }
        virtual void isAccepted() {}
        virtual void isApplied() {}
        virtual void isReset() {}
        virtual void isRejected() {}
      public:
        DialogBase(QWidget * parent = 0) : QDialog(parent) {
          m_box.addButton(QDialogButtonBox::Apply);
          m_box.addButton(QDialogButtonBox::Reset);
          m_box.addButton(QDialogButtonBox::Cancel);
          m_box.addButton(QDialogButtonBox::Ok);
          connect(&m_box, SIGNAL(accepted()), SLOT(accept()));
          connect(&m_box, SIGNAL(rejected()), SLOT(reject()));
          connect(this, &QDialog::accepted, []{ isAccepted(); });
          connect(this, &QDialog::rejected, []{ isRejected(); });
          connect(&buttonBox(), &QDialogButtonBox::clicked, [this](QAbstractButton* btn){
            if (m_box.buttonRole(btn) == QDialogButtonBox::ApplyRole)
              isApplied();
            else if (m_box.buttonRole(btn) == QDialogButtonBox::ResetRole)
              isReset();
          });
        }
      }
      
      class UserDialog : public DialogBase {
        QFormLayout m_layout;
        QLineEdit m_name;
        QSpinBox m_age;
        UserData m_initialData;
      public:
        UserDialog(QWidget * parent = 0) : QDialog(parent), m_layout(this) {
          m_layout.addRow("Name", &m_name);
          m_layout.addRow("Age", &m_age);
          m_age.setRange(0, 200);
          m_layout.addRow(&buttonBox());    
        }
        /// Used by external objects to be notified that the settings
        /// have changed and should be immediately put in effect.
        /// This signal is emitted when the data was changed.
        Q_SIGNAL void applied(UserData const &);
        UserData get() const {
          return UserData(
            m_name.text(), m_age.value());
        }
        void set(const UserData & data) {
          m_name.setText(data.name);
          m_age.setValue(data.age);
        } 
        void setInitial(const UserData & data) { m_initialData = data; }
        bool isModified() const { return get() == m_initialData; }
      protected:
        void isAccepted() Q_DECL_OVERRIDE { emit applied(get()); }
        void isApplied() Q_DECL_OVERRIDE { emit applied(get()); }
        void isReset() Q_DECL_OVERRIDE { set(m_initialData); }
      };
      

答案 1 :(得分:0)

如果您只是在对话框关闭时检查输入字段是否已填满,则您不需要标记,只能检查是否有任何输入。

如果您在某些点以编程方式填充输入字段,但也只对对话框关闭时的更改感兴趣,您还可以在close函数中检查当前输入是否等于您之前设置的输入。

从您发布的代码中,我无法真正看到您需要的标志。