【问题标题】:remove items from QComboBox from ui从 ui 中删除 QComboBox 中的项目
【发布时间】:2013-07-23 03:47:18
【问题描述】:

我正在尝试调整 QComboBox 的用户界面,使用户可以从下拉列表中删除项目(无需先选择它们)。

背景是我正在使用 QComboBox 来指示当前打开的数据文件。我还将它用作最近打开文件的缓存。我希望用户能够删除他不想再列出的条目。这可以通过点击删除键,或上下文菜单,或任何易于实现的方式来实现。我不想依赖先选择项目。在 Firefox 中可以找到类似的行为,其中可以删除条目字段的旧缓存建议。

我正在考虑对 QComboBox 使用的列表视图进行子类化,但是,我没有找到足够的文档来帮助我开始。

如有任何提示和建议,我将不胜感激。我正在使用 PyQt,但 C++ 示例没有问题。

【问题讨论】:

  • 我在 Firefox (OS X) 中找不到该功能。它看起来怎样?像这样编辑组合框对我来说听起来很神秘/无法发现/无法使用(但我可能错了)。
  • @FrankOsterfield,我仔细检查过,firefox 使用 shift-delete(至少在 Windows 上)link,我同意它是神秘且不可发现的(就像许多键盘快捷键一样)。我不认为它是不可用的。删除指向不再存在的文件的链接可能是最简单的。

标签: qt pyqt qcombobox


【解决方案1】:

我使用installEventFilter 文档中的代码解决了这个问题。

//must be in a header, otherwise moc gets confused with missing vtable
class DeleteHighlightedItemWhenShiftDelPressedEventFilter : public QObject
{
     Q_OBJECT
protected:
    bool eventFilter(QObject *obj, QEvent *event);
};

bool DeleteHighlightedItemWhenShiftDelPressedEventFilter::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
        if (keyEvent->key() == Qt::Key::Key_Delete && keyEvent->modifiers() == Qt::ShiftModifier)
        {
            auto combobox = dynamic_cast<QComboBox *>(obj);
            if (combobox){
                combobox->removeItem(combobox->currentIndex());
                return true;
            }
        }
    }
    // standard event processing
    return QObject::eventFilter(obj, event);
}

myQComboBox->installEventFilter(new DeleteHighlightedItemWhenShiftDelPressedEventFilter);

【讨论】:

    【解决方案2】:
    comboBox->removeItem(int index) // removes item at index
    

    【讨论】:

    • 抱歉不够清楚。问题是:gui 的用户如何在不先选择项目的情况下表明她或他想要删除项目。一旦清楚这一点,从组合框中删除一个项目确实像您所说的那样简单。
    • @gui 的用户如何在不先选择项目的情况下表明她或他想要删除项目...。这取决于应用程序的逻辑。也许“QComboBox”不适合展示您的数据。我认为在你的情况下'QListWidget'更合适。
    【解决方案3】:

    您可以使用专门的类来自动化流程,因此最终可以节省时间。

    例如,there's a class 命名为 KrHistoryComboBox(继承自 KHistoryComboBox 类)在名为 Krusader 的程序中为 used

    虽然这一次,对于这个答案:以下代码是直接从QComboBox 继承的版本(尽管QComboBox 不能像KHistoryComboBox 那样做很多事情),以及它的一个使用示例:

    文件 main.cpp

    #include "mainwindow.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
    
        return a.exec();
    }
    

    文件 mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    
    namespace Ui {
        class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui;
    };
    
    #endif // MAINWINDOW_H
    

    文件 mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "krhistorcombobox.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        // Creates a new editable comboBox, and populates it with data
        KrHistorComboBox *combox;
        combox = new KrHistorComboBox(this);
        combox->setEditable(true);
        QStringList elementsToAdd = {"one", "two", "three", "four", "five", "six"};
        combox->insertItems(0, elementsToAdd);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    

    文件 krhistorcombobox.h

    /*****************************************************************************
    * Copyright (C) 2018-2019 Shie Erlich <krusader@users.sourceforge.net>      *
    * Copyright (C) 2018-2019 Rafi Yanai <krusader@users.sourceforge.net>       *
    * Copyright (C) 2018-2019 Krusader Krew [https://krusader.org]              *
    *                                                                           *
    * This file is part of Krusader [https://krusader.org].                     *
    *                                                                           *
    * Krusader is free software: you can redistribute it and/or modify          *
    * it under the terms of the GNU General Public License as published by      *
    * the Free Software Foundation, either version 2 of the License, or         *
    * (at your option) any later version.                                       *
    *                                                                           *
    * Krusader is distributed in the hope that it will be useful,               *
    * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
    * GNU General Public License for more details.                              *
    *                                                                           *
    * You should have received a copy of the GNU General Public License         *
    * along with Krusader.  If not, see [http://www.gnu.org/licenses/].         *
    *****************************************************************************/
    
    #ifndef KRHISTORCOMBOBOX_H
    #define KRHISTORCOMBOBOX_H
    
    // QtWidgets
    #include <QComboBox>
    
    /**
     * A specialized version of a QComboBox, e.g. it deletes the current
     *  item when the user presses Shift+Del
     */
    class KrHistorComboBox : public QComboBox
    {
        Q_OBJECT
    
    public:
        explicit KrHistorComboBox(QWidget *parent = nullptr);
    };
    
    #endif // KRHISTORCOMBOBOX_H
    

    文件 krhistorcombobox.cpp

    /*****************************************************************************
    * Copyright (C) 2018-2019 Shie Erlich <krusader@users.sourceforge.net>      *
    * Copyright (C) 2018-2019 Rafi Yanai <krusader@users.sourceforge.net>       *
    * Copyright (C) 2018-2019 Krusader Krew [https://krusader.org]              *
    *                                                                           *
    * This file is part of Krusader [https://krusader.org].                     *
    *                                                                           *
    * Krusader is free software: you can redistribute it and/or modify          *
    * it under the terms of the GNU General Public License as published by      *
    * the Free Software Foundation, either version 2 of the License, or         *
    * (at your option) any later version.                                       *
    *                                                                           *
    * Krusader is distributed in the hope that it will be useful,               *
    * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
    * GNU General Public License for more details.                              *
    *                                                                           *
    * You should have received a copy of the GNU General Public License         *
    * along with Krusader.  If not, see [http://www.gnu.org/licenses/].         *
    *****************************************************************************/
    
    #include "krhistorcombobox.h"
    
    // QtCore
    #include <QEvent>
    // QtGui
    #include <QKeyEvent>
    // QtWidgets
    #include <QAbstractItemView>
    
    /**
     *  A KrHistorComboBox event filter that e.g. deletes the current item when Shift+Del is pressed
     *  There was more information in https://doc.qt.io/qt-5/qobject.html#installEventFilter,
     *  https://forum.qt.io/post/160618 and
     *  https://stackoverflow.com/questions/17820947/remove-items-from-qcombobox-from-ui/52459337#52459337
     */
    class KHBoxEventFilter : public QObject
    {
        Q_OBJECT
    
    public:
        explicit KHBoxEventFilter(QObject *parent = nullptr) : QObject(parent) {}
    
    protected:
        bool eventFilter(QObject *obj, QEvent *event) override;
    };
    
    bool KHBoxEventFilter::eventFilter(QObject *obj, QEvent *event)
    {
        if (event->type() == QEvent::KeyPress) {
            auto keyEvent = static_cast<QKeyEvent *>(event);
            if (keyEvent->modifiers() == Qt::ShiftModifier && keyEvent->key() == Qt::Key::Key_Delete) {
                auto comboBox = qobject_cast<QComboBox *>(obj);
                if (comboBox != nullptr) {
                    // Delete the current item
                    comboBox->removeItem(comboBox->currentIndex());
                    return true;
                }
            }
        }
        // Perform the usual event processing
        return QObject::eventFilter(obj, event);
    }
    
    /**
     *  An event filter for the popup list of a KrHistorComboBox, e.g. it deletes the current
     *  item when the user presses Shift+Del
     */
    class KHBoxListEventFilter : public QObject
    {
        Q_OBJECT
    
    public:
        explicit KHBoxListEventFilter(QObject *parent = nullptr) : QObject(parent) {}
    
    protected:
        bool eventFilter(QObject *obj, QEvent *event) override;
    };
    
    bool KHBoxListEventFilter::eventFilter(QObject *obj, QEvent *event)
    {
        if (event->type() == QEvent::KeyPress) {
            auto keyEvent = static_cast<QKeyEvent *>(event);
            if (keyEvent->modifiers() == Qt::ShiftModifier && keyEvent->key() == Qt::Key::Key_Delete) {
                auto itemView = qobject_cast<QAbstractItemView *>(obj);
                if (itemView->model() != nullptr) {
                    // Delete the current item from the popup list
                    itemView->model()->removeRow(itemView->currentIndex().row());
                    return true;
                }
            }
        }
        // Perform the usual event processing
        return QObject::eventFilter(obj, event);
    }
    
    #include "krhistorcombobox.moc" // required for class definitions with Q_OBJECT macro in implementation files
    
    KrHistorComboBox::KrHistorComboBox(QWidget *parent): QComboBox(parent)
    {
        installEventFilter(new KHBoxEventFilter(this));
    
        QAbstractItemView *itemView = view();
        if (itemView != nullptr)
            itemView->installEventFilter(new KHBoxListEventFilter(this));
    }
    

    文件 krexample.pro

    #-------------------------------------------------
    #
    # Project created by QtCreator 2018-09-22T18:33:23
    #
    #-------------------------------------------------
    
    QT       += core gui
    
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    
    TARGET = untitled
    TEMPLATE = app
    
    # The following define makes your compiler emit warnings if you use
    # any feature of Qt which has been marked as deprecated (the exact warnings
    # depend on your compiler). Please consult the documentation of the
    # deprecated API in order to know how to port your code away from it.
    DEFINES += QT_DEPRECATED_WARNINGS
    
    # You can also make your code fail to compile if you use deprecated APIs.
    # In order to do so, uncomment the following line.
    # You can also select to disable deprecated APIs only up to a certain version of Qt.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
    
    
    SOURCES += \
            main.cpp \
            krhistorcombobox.cpp \
            mainwindow.cpp
    
    HEADERS += \
            krhistorcombobox.h \
            mainwindow.h
    
    FORMS += \
            mainwindow.ui
    

    文件 mainwindow.ui

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>MainWindow</class>
     <widget class="QMainWindow" name="MainWindow" >
      <property name="geometry" >
       <rect>
        <x>0</x>
        <y>0</y>
        <width>400</width>
        <height>300</height>
       </rect>
      </property>
      <property name="windowTitle" >
       <string>MainWindow</string>
      </property>
      <widget class="QMenuBar" name="menuBar" />
      <widget class="QToolBar" name="mainToolBar" />
      <widget class="QWidget" name="centralWidget" />
      <widget class="QStatusBar" name="statusBar" />
     </widget>
     <layoutDefault spacing="6" margin="11" />
     <pixmapfunction></pixmapfunction>
     <resources/>
     <connections/>
    </ui>
    

    这是正在执行的示例程序的屏幕截图,在按下 Shift+Del 之前(这将删除名为“two”的选项):


    注意:当前答案中的一些源代码基于https://doc.qt.io/qt-5/qobject.html#installEventFilterhttps://forum.qt.io/post/160618 以及https://stackoverflow.com/a/26976984 中名为“nwp”的用户的出色工作(尽管该答案不包括删除元素的代码弹出列表,如果弹出列表被看到,并且它有一个“内存泄漏”(一个对象被构造但没有被销毁)因此如果开发人员添加了一个析构函数,例如~DeleteHighlightedItemWhenShiftDelPressedEventFilter() { QTextStream(stdout) &lt;&lt; "DESTRUCTED" &lt;&lt; endl; },开发人员稍后会看到析构函数的代码从未执行,因此存在内存泄漏;目前我还没有 stackoverflow 点以便在https://stackoverflow.com/a/26976984 中添加评论。

    【讨论】:

      【解决方案4】:

      很抱歉这么晚了,但我想贡献一些我找到的其他方法,以防其他人像我一样寻找它。这些方法已经用 Qt 5.6 进行了测试。我不能保证它们可以在其他版本中使用。

      一种可能性是收听 QCombobox 的 view() 的“pressed()”信号。这样我们就可以使用鼠标右键从列表中删除项目。我惊讶地发现 view() 始终可用,从不为 NULL,并且在显示时可以删除项目,所以下面的工作非常好:

      class MyCombobox : public QComboBox
      {
        Q_OBJECT
        public: MyCombobox(QWidget *pParent = NULL);
        protected slots: void itemMouseDown(const QModelIndex &pIndex);
      };
      
      MyCombobox::MyCombobox(QWidget *pParent)
      {
        connect( QComboBox::view(), SIGNAL(pressed(const QModelIndex &)),
                 this, SLOT(itemMouseDown(const QModelIndex &)) );
      }
      
      void MyCombobox::itemMouseDown(const QModelIndex &pIndex)
      {
        if( QApplication::mouseButtons() == Qt::RightButton )
        {
          QComboBox::model()->removeRow(pIndex.row());
        }
      }
      

      第二个选项是安装事件过滤器,但也安装到视图中。这样我们就可以使用删除键或其他任何东西来删除项目。测试 NULL 指针和无效的行索引可能是个好主意,但为了清楚起见,我省略了。

      class MyCombobox : public QComboBox
      {
        Q_OBJECT
        public: MyCombobox(QWidget *pParent = NULL);
        protected: bool eventFilter(QObject *pWatched, QEvent *pEvent);
      };
      
      MyCombobox::MyCombobox(QWidget *pParent)
      {
        QComboBox::view()->installEventFilter(this);
      }
      
      bool MyCombobox::eventFilter(QObject *pWatched, QEvent *pEvent)
      {
        if( pEvent->type() == QEvent::KeyPress )
        {
          QKeyEvent *tKeyEvent = static_cast<QKeyEvent*>(pEvent);
          if( tKeyEvent->key() == Qt::Key_Delete )
          {
            QComboBox::model()->removeRow(QComboBox::view()->currentIndex().row());
            return true;
          }
        }
      
        return QObject::eventFilter(pWatched, pEvent);
      }
      

      就是这样。

      【讨论】:

        【解决方案5】:

        您可以通过以下方式删除 QComboBox 的活动选定值:

        ui->comboBox->removeItem(ui->comboBox->currentIndex());
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-11-02
          • 2023-03-15
          • 1970-01-01
          • 2013-05-22
          • 2019-01-26
          • 2021-10-07
          • 2021-10-19
          • 2015-06-02
          相关资源
          最近更新 更多