【问题标题】:How do I prevent the enter key from closing my QDialog (Qt 4.8.1)如何防止回车键关闭我的 QDialog (Qt 4.8.1)
【发布时间】:2013-03-28 13:13:12
【问题描述】:

我有一个QDialog 和一个QDialogButtonBoxOKCancel 按钮处于活动状态。有时我会根据对话框的状态禁用或隐藏“确定”按钮。看来,无论我做什么,Enter 键总是会激活 OK 按钮。我真的不希望这种情况发生。我试过了:

  • 每次显示/隐藏/启用/禁用/无论按钮如何,都将默认和 autoDefault 属性设置为 false
  • 在 OK 按钮上安装一个事件过滤器来拦截按键事件(按下和释放)以进行返回、输入和空格
  • 将按钮的焦点策略设置为 NoFocus

在上述所有内容的组合中,Enter 键仍然接受对话框。有谁知道如何阻止这个?看起来我应该能够阻止这么简单的事情?

【问题讨论】:

  • 你能发布post事件过滤器代码吗?
  • 是您自己的对话框还是您谈论 Qt 提供的标准对话框?
  • 不要使用确定和取消按钮,将您自己的按钮添加到 QDialogBu​​ttonBox。
  • @MuhammadMinhazulHaque 但是我没有得到按钮在不同操作系统上正确定位的优势

标签: c++ qt qdialog qpushbutton


【解决方案1】:

按键事件过滤应该在对话框本身上完成,因为处理ReturnEnter键转发到默认按钮的代码在QDialog::keyPressEvent中。

void Dialog::keyPressEvent(QKeyEvent *evt)
{
    if(evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return)
        return;
    QDialog::keyPressEvent(evt);
}

或者

theDialog−>installEventFilter(anotherClassObject);

bool AnotherClass::eventFilter(QObject *obj, QEvent *evt)
{
    if(evt->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent*>(evt);
        if(keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return )
            return true; // mark the event as handled
    }
    return false;
}

【讨论】:

  • 我应该忽略()这个事件吗?
  • 这不起作用。按下 Enter 时,我在基于 QDialog 的类中没有收到 keyPressEvent 调用。
  • 你不应该 ignore() 事件,而是接受它并且什么也不做。但是如果取消按钮仍然启用,并且可以获得焦点,它可能仍然被 Enter 键激活并关闭对话框。
  • 奇怪的是这也不起作用。过滤方法或覆盖按键事件都不会被调用。
  • 第一个模式在 Python 中使用 pyside 1.2.4 / Qt 4.8.6 为我工作
【解决方案2】:

如果您在对话框上有正常的 QPushButtons,那么如果按钮上设置了 autoDefault 和/或默认属性,那么您将获得一个默认按钮 - 这是 enter 键触发的内容。在这种情况下,去掉按钮上的 autoDefault 并在另一个小部件中按 enter 不再关闭对话框。

在 QDialogBu​​ttonBox 的情况下,您可能可以遍历按钮以在对话框的 ctor 中关闭这些东西。没有在这里测试,但应该可以工作。如果没有,那么您还需要查看 QDialog 本身是否设置了默认按钮。

【讨论】:

    【解决方案3】:

    QDialog 有一个名为accept() 的专用槽。每当 QDialogBu​​ttonBox 发出accepted()(通过按回车键或单击确定)时,就会调用该私有插槽。所以尝试断开它们。

    disconnect(ui-&gt;buttonBox, SIGNAL(accepted()), this, SLOT(accept()));

    这对我有用。

    【讨论】:

    • 很久以前我从未明确设置过该连接并从 ui 文件中删除了该连接
    【解决方案4】:

    问题是事件过滤器不应该安装在确定按钮上。

    如果您的“确定”按钮被禁用,则它不会收到 enter 事件。无论哪个小部件都有焦点。如果他们不接受 enter 事件,那么 QDialog 将转到 accept() 本身。

    两种方法解决问题:

    1) 覆盖QDialog::accept(),并在新的accept 函数中调用QDialog 的accept 方法,前提是OK 启用

    void MyDialog::accept() {
        if (okEnabled) {
            QDialog::accept();
        }
    }
    

    2)对话框中每个不接受回车键的小部件上安装事件过滤器(行编辑,...)。

    事件过滤器是这样的:

    class KeyPressEater : public QObject
    {
        Q_OBJECT
    
    protected:
        bool eventFilter(QObject *obj, QEvent *event);
    };
    
    bool KeyPressEater::eventFilter(QObject *obj, QEvent *event)
    {
        if (event->type() == QEvent::KeyPress) {
            QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
            bool res = QObject::eventFilter(obj, event);
    
            if (keyEvent->key() == Qt::Key_Return) {
                return true; /* Always accept return */
            } else {
                return res;
            }
        } else {
            // standard event processing
            return QObject::eventFilter(obj, event);
        }
    }
    

    在您的代码中,对于对话框中的每个小部件:

    myWidget->installEventFilter(myKeyPressEater);
    

    【讨论】:

      【解决方案5】:

      要避免关闭对话框中的“OK”按钮或“Enter”键: 在 ui xml 文件中,删除用于接受/拒绝的连接/插槽。然后,在您的代码中,根据需要在您的代码中发出 accept();

      连接accept()槽的ui文件示例:

       <connections>  
        <connection>  
      
         <sender>products_ButtonBox</sender>
      
          <signal>accepted()</signal>  
      
           <receiver>Products_Dialog</receiver>
            <slot>accept()</slot>
             <hints>
              <hint type="sourcelabel">
               <x>248</x>
               <y>254</y>
              </hint>
              <hint type="destinationlabel">
               <x>157</x>
               <y>274</y>
              </hint>e
             </hints>
            </connection>
      

      【讨论】:

        【解决方案6】:

        在对话框的accept() 方法中,检查确定按钮以获得焦点:

        void accept() override
        { if (!dialogButtonBox->button(QDialogButtonBox::Ok)->hasFocus())
          return;
        
        ...
        
          QDialog::accept();
        }
        

        【讨论】:

          【解决方案7】:

          关键是设置自己的按钮,全部用NoRole,既不接受也不拒绝来自按钮框的信号。这将允许您为默认按钮设置自己的行为。

          class Dialog(QDialog):
              def __init__():
                  super(Dialog, self).__init__()
                  self.buttonBox = QDialogButtonBox()
          
                  self.btn_save = self.buttonBox.addButton('Save', QDialogButtonBox.NoRole)
                  self.btn_cancel = self.buttonBox.addButton('Cancel', QDialogButtonBox.NoRole)
                  self.btn_save.clicked.connect(self.onAccept)
                  self.btn_save.setMouseTracking(True)
                  self.btn_cancel.clicked.connect(self.onReject)
          
                  #  STATUS BAR
                  self.status = QStatusBar()
                  self.status.addPermanentWidget(self.buttonBox)
          
              def onAccept(self):
                  if not self.btn_save.underMouse():
                      return
                  self.submitChanges(self.model)
                  self.accept()
          
              def onReject(self):
                  self.reject()
          

          【讨论】:

            【解决方案8】:

            一种选择是覆盖对话框的显示事件,以允许显示 QDialogBu​​ttonBox,之后它将设置一个带有 AcceptRole 的默认按钮,然后将所有按钮设置为非默认按钮。

            void MyDialog::showEvent(QShowEvent* event)
            {
                // When a QDialogButtonBox is shown, it will set a default button if none are found so we need to disable the
                // default buttons after the button box has been shown.
                QDialog::showEvent(event);
            
                // For example, with a dialog which has two buttons, Save and Cancel, we remove all defaults
                // It might be good enough to remove the default on just the buttons with have the AcceptRole, but
                // I didn't test extensively enough to see what would happen if any buttons had "autoDefault" set or
                // verify this behavior on all platforms.
                ui->buttonBox->button(QDialogButtonBox::Save)->setDefault(false);
                ui->buttonBox->button(QDialogButtonBox::Cancel)->setDefault(false);
            }
            

            尝试在 QDialogBu​​ttonBox 显示之前删除默认值,例如在对话框的构造函数中,将被 QDialogBu​​ttonBox::showEvent() 中的代码覆盖。

            【讨论】:

              【解决方案9】:

              在 PySide(我想是 PyQt)中,我能够重新定义 QDialog 的接受和拒绝功能。

              def custom_accept ():
                  # perform custom actions when you hit open
                  pass
              
              def custom_reject ():
                  # perform custom actions when you hit cancel
                  pass
              
              file_dialog = QtGui.QFileDialog(directory=".")
              file_dialog.accept = custom_accept
              file_dialog.reject = custom_reject
              

              这使文件对话框无法关闭,并允许我在触发“确定”(接受)或“取消”(拒绝)功能(通过输入或单击按钮)时访问数据

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2020-06-09
                • 1970-01-01
                • 2020-09-15
                • 1970-01-01
                • 1970-01-01
                • 2016-12-19
                • 1970-01-01
                • 2015-09-17
                相关资源
                最近更新 更多