C++ Qt QColorDialog-退出键不为“;“吃”;(即不从事件队列中删除)

C++ Qt QColorDialog-退出键不为“;“吃”;(即不从事件队列中删除),c++,qt,events,dialog,C++,Qt,Events,Dialog,在我的应用程序中,我有一个QTableWidget,其中有一列用户可以单击以选择颜色。它在以下限制下正常工作:当用户键入转义键时,对话框将按预期取消并关闭,但键事件仍保留在队列中。当对话框关闭时,这将导致此键事件的第二个效果,就像用户按了两次键一样 以下是全部代码: void CChildrenConfigScreen::actionCellClicked(int row, int col) { // ui->config_children_table->selectRow

在我的应用程序中,我有一个QTableWidget,其中有一列用户可以单击以选择颜色。它在以下限制下正常工作:当用户键入转义键时,对话框将按预期取消并关闭,但键事件仍保留在队列中。当对话框关闭时,这将导致此键事件的第二个效果,就像用户按了两次键一样

以下是全部代码:

void CChildrenConfigScreen::actionCellClicked(int row, int col)
{
   //   ui->config_children_table->selectRow(row);
   switch(col) {
      case eColChildColor: {
            CBiStateButton* cbox = reinterpret_cast<CBiStateButton*>(ui->config_children_table->cellWidget(row, 0));
            assert( cbox != nullptr );

            if( cbox->state() != Qt::Unchecked ) {
               QTableWidgetItem* cell = ui->config_children_table->item(row, col);
               cell->setSelected(false);
               // =======
               QColorDialog dialog(this);
               dialog.setCurrentColor(cell->background().color());
               dialog.exec();
               if( dialog.result() == QDialog::Accepted ) {
                  cell->setBackground(QBrush(dialog.currentColor()));
               } else {
                  // drop escape key event ???
               }
               // =======
            }
         }
         break;
   }
}
void CChildrenConfigScreen::actionCellClicked(int行,int列)
{
//用户界面->配置子表->选择行(行);
开关(col){
案例生态儿童颜色:{
CBiStateButton*cbox=重新解释强制转换(ui->config_children_table->cellWidget(行,0));
断言(cbox!=nullptr);
如果(cbox->state()!=Qt::未选中){
QTableWidgetItem*cell=ui->config\u children\u table->item(行、列);
单元格->所选设置(假);
// =======
QColorDialog对话框(此对话框);
setCurrentColor(单元格->背景().color());
dialog.exec();
if(dialog.result()==QDialog::Accepted){
单元格->设置背景(QBrush(dialog.currentColor());
}否则{
//丢钥匙事件???
}
// =======
}
}
打破
}
}
所以,我的问题是:

  • 这是正常的行为吗?还是Qt中的一个bug
  • 我做错什么了吗
    • 如果是,什么
    • 如果没有,我可以做什么来“吃”这个活动?(最好不用创建QColorDialog子类)

      • 以下是我实施的解决方案。不是很漂亮,但我能做到最好,并按要求工作。定义有点冗长,但使用起来非常方便

        首先,一个基于堆栈的对象(Android和MacOS尚未实现,只有Windows):

        跳过实际上已经处理过的Esc键(在本例中,在上面的QColorDialog中,但可能是QMessageBox或任何其他对话框):


        我希望这对某些人有用。

        使用了一种难看的解决方法,在“else”代码块中设置标志,以避免在其他地方处理事件。很难看,但一切都在控制之中,运作良好,但我想知道发生了什么。非常奇怪。将尝试QCoreApplication::installNativeEventFilter和QCoreApplication::removeNativeEventFilter
        // ==============================
        // Used to disable the Escape key
        
        class CKeyEventFilter {
           public:
              typedef char KeyType;
              typedef  std::function<void()> Functor;
        
           private:
              class CFilter: public QAbstractNativeEventFilter
              {
                 public:
        
                 private:
                    KeyType mKey;
                    Functor mAction;
        
                 public:
                    explicit CFilter(KeyType key, Functor action)
                       : mKey(key)
                       , mAction(action)
                    {
                    }
        
                    bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override
                    {
                       bool stop_it = false;
        
        #if defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)
                       if (eventType == "xcb_generic_event_t") {
                           xcb_generic_event_t* event = reinterpret_cast<xcb_generic_event_t *>(message);
                           assert(event != nullptr);
                           // ...
                       }
        #elif defined(Q_OS_MACOS)
                       if (eventType == "mac_generic_NSEvent" {
                           MSG  * event = reinterpret_cast<NSEvent*>(message);
                           assert(event != nullptr);
                          // ...
                       }
        #elif defined(Q_OS_WINDOWS)
                       if (eventType == "windows_generic_MSG" || eventType == "windows_dispatcher_MSG") {
                           MSG* event = reinterpret_cast<MSG*>(message);
                           assert(event != nullptr);
        
                           if(event->message == WM_KEYDOWN || event->message == WM_KEYUP ) {
                              if( event->wParam == mKey ) {
                                 // keep stop_it to false for the key being processed
                                 // but tells the 'next client' that he doesn't need
                                 // to process it a second time.
                                 mAction();
                              }
                           }
                       }
        #else
        #error "Yet unsupported OS"
        #endif
        
                       return stop_it;
                    }
              };
        
              CFilter mFilter;
        
           public:
              explicit CKeyEventFilter(KeyType key, Functor action)
                 : mFilter(key, action)
              {
                 qApp->installNativeEventFilter(&mFilter);
              }
        
              virtual ~CKeyEventFilter()
              {
                 qApp->removeNativeEventFilter(&mFilter);
              }
        };
        
        {
           // Workaround with this stack based object (0x1B = 27 = ascii code for Esc char)
           CKeyEventFilter filter(0x1B, []() { CMainWindow::win()->setSkipEscape(); } );
        
           // Example of purpose: if dialog is left with the Escape Key,
           // CMainWindow::setSkipEscape() in the lambda above will be called
           QTableWidgetItem* cell = ui->config_children_table->item(row, col);
           cell->setSelected(false);
           QColorDialog dialog(this);
           dialog.setCurrentColor(cell->background().color());
           dialog.exec();
           if( dialog.result() == QDialog::Accepted ) {
              cell->setBackground(QBrush(dialog.currentColor()));
           }
        }
        
        void CMainWindow::popScreen()
        {
           // mSkipEscape is initialized to false in CMainWindow's constructor
           // and set by CMainWindow::setSkipEscape() in the lambda above.
           if( mSkipEscape ) {
              mSkipEscape = false;
           } else {
              if( ! mScreenStack.empty()) {
                 EScreens screen = mScreenStack.top();
                 mScreenStack.pop();
                 this->goScreen(screen);
              }
           }
        }