удаление элементов из QComboBox из пользовательского интерфейса



Я пытаюсь настроить пользовательский интерфейс QComboBox таким образом, чтобы пользователь мог удалить элементы из выпадающего списка (без предварительного их выбора).



Фон заключается в том, что я использую QComboBox, чтобы указать, какой файл данных открыт прямо сейчас. Я также использую его в качестве кэша для недавно открытых файлов. Я хотел бы, чтобы пользователь мог удалить записи, которые он больше не хочет иметь в списке. Это может быть либо просто нажав клавишу delete, либо контекстное меню, или что угодно еще. простой в реализации. Я не хочу полагаться на выбор предмета в первую очередь. Аналогичное поведение можно найти в Firefox, где старые кэшированные предложения для поданной записи могут быть удалены.



Я рассматривал подклассы представления списка, используемого QComboBox, однако я не нашел достаточно документации, чтобы начать работу.



Буду признателен за любые подсказки и предложения. Я использую PyQt, но у меня нет проблем с образцами C++.

874   3  

3 ответов:

Я решил эту проблему, используя код из документации 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);
comboBox->removeItem(int index) // removes item at index

Вы можете создать специализированный класс, который автоматизирует некоторые процессы, и таким образом экономит время в конечном итоге. Например, в https://phabricator.kde.org/D15693 (для программы с именем Krusader) можно увидеть новый класс KrHistorComboBox (который наследует от KHistoryComboBox) и его использование; но на этот раз для этого ответа: это версия, которая наследует непосредственно от QComboBox, и один пример ее использования:

Файл main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

Файл главное окно.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~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"};
    combox->insertItems(0, elementsToAdd);
}

MainWindow::~MainWindow()
{
    delete ui;
}

Файл krhistorcombobox.h

/*****************************************************************************
 * Copyright (C) 2018 Shie Erlich <[email protected]>           *
 * Copyright (C) 2018 Rafi Yanai <[email protected]>            *
 * Copyright (C) 2018 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 KrHistorComboBox event filter that e.g. deletes the current item when the user presses Shift+Del

    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;
};

//! 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;
};


//! 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);

protected:
    KHBoxEventFilter boxEF;
    KHBoxListEventFilter listEF;
};

#endif // KRHISTORCOMBOBOX_H

Файл krhistorcombobox.cpp

/*****************************************************************************
 * Copyright (C) 2018 Shie Erlich <[email protected]>           *
 * Copyright (C) 2018 Rafi Yanai <[email protected]>            *
 * Copyright (C) 2018 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>

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 box = dynamic_cast<QComboBox *>(obj);
            if (box != nullptr) {
                // Delete the current item
                box->removeItem(box->currentIndex());
                return true;
            }
        }
    }
    // Perform the usual event processing
    return QObject::eventFilter(obj, event);
}

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 iv = dynamic_cast<QAbstractItemView *>(obj);
            if (iv->model() != nullptr) {
                // Delete the current item from the popup list
                iv->model()->removeRow(iv->currentIndex().row());
                return true;
            }
        }
    }
    // Perform the usual event processing
    return QObject::eventFilter(obj, event);
}

KrHistorComboBox::KrHistorComboBox(QWidget *parent) : QComboBox(parent)
{
    installEventFilter(&boxEF);

    QAbstractItemView* iv = view();
    if (iv != nullptr)
        iv->installEventFilter(&listEF);
}

Файл krhcexample.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

<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, которая удалит опцию с именем " два "


Примечание: некоторые источники код в настоящем ответе основан на https://doc.qt.io/qt-5/qobject.html#installEventFilter, https://forum.qt.io/post/160618 и хорошая работа пользователя с именем " nwp "в https://stackoverflow.com/a/26976984 (хотя этот ответ не включает код для удаления элемента всплывающего списка, если всплывающий список виден, и у него есть" утечка памяти "(объект построен, но не уничтожен), поэтому, если разработчик добавляет деструктор, например ~DeleteHighlightedItemWhenShiftDelPressedEventFilter() { QTextStream(stdout) << "DESTRUCTED" << endl; }, то разработчик позже видит, что код деструктора никогда не выполняется, и поэтому есть утечки памяти; в настоящее время у меня нет точек stackoverflow, чтобы добавить комментарий в https://stackoverflow.com/a/26976984).

Comments

    Ничего не найдено.