Evgenii Legotckoi
23 апреля 2018 г. 15:07

Qt/C++ - Урок 077. QComboBox - игнорирование скрытых пунктов в выпадающем списке при скроллинге

В одной из предыдущих статей было показано, как скрыть некоторые пункты в выпадающем списке QComboBox , чтобы пользователь не мог их выбрать. Однако я не обратил внимание на то, что если пользователь наведёт курсор мыши на сам комбобокс и прокрутит колёсико мышки, то он сможет выбрать данный скрытый пункт меню. Следовательно такое поведение следует запретить.

Сделать это можно с помощью перехвата события прокрутки колёсика мышки в рамках данного комбобокса.

В зависимости от структуры программы можно сделать это двумя способами:

  1. Наследоваться от класса QComboBox и переопределить метод wheelEvent(QWheelEvent event* ).
  2. Наследоваться от класса QObject и переопределить метод eventFilter(QObject obj , QEvent * event* )

Сам по себе основной код метода будет аналогичен в обоих случаях, будет различно местонахождения данного кода. Это будет определяться тем, требуется ли вам создавать кастомный класс QComboBox или нет.


С наследованием от QComboBox

При наследовании от QComboBox переопределим метод wheelEvent(QWheelEvent event* ) и будем проверять, какие из строк скрытые. Все скрытые строки при событии прокрытки будем игнорировать и перескакивать на следующую доступную видимую строку.

  1. void CustomComboBox::wheelEvent(QWheelEvent* event)
  2. {
  3. int row = this->currentIndex();
  4. int count = this->count();
  5. QListView* dropdownList = static_cast<QListView*>(this->view());
  6.  
  7. do
  8. {
  9. event->angleDelta().y() < 0 ? ++row : --row;
  10. if (row >= 0 && row < count && !dropdownList->isRowHidden(row))
  11. {
  12. this->setCurrentIndex(row);
  13. return;
  14. }
  15. }
  16. while (row >= 0 && row < count);
  17. }

С установкой фильтра

Если же вы не хотите создавать кастомный QComboBox , но вам требуется данный функционал, то вы можете создать фильтр в том окне (все виджеты наследованы от QObject ), где установлен ваш QComboBox.

Для этого переопределим у окна метод eventFilter(QObject obj , QEvent * event* ).

  1. bool Widget::eventFilter(QObject* obj, QEvent *event)
  2. {
  3. if (event->type() == QEvent::Wheel)
  4. {
  5. QWheelEvent *wheelEvent = static_cast<QWheelEvent*>(event);
  6. QComboBox* comboBox = static_cast<QComboBox*>(obj);
  7.  
  8. int row = comboBox->currentIndex();
  9. int count = comboBox->count();
  10. QListView* dropdownList = static_cast<QListView*>(comboBox->view());
  11.  
  12. do
  13. {
  14. wheelEvent->angleDelta().y() < 0 ? ++row : --row;
  15. if (row >= 0 && row < count && !dropdownList->isRowHidden(row))
  16. {
  17. comboBox->setCurrentIndex(row);
  18. return true;
  19. }
  20. }
  21. while (row >= 0 && row < count);
  22.  
  23. return true;
  24. }
  25.  
  26. return QObject::eventFilter(obj, event);
  27. }

и установим этот фильтр на целевой QComboBox

  1. Widget::Widget(QWidget *parent) :
  2. QWidget(parent),
  3. ui(new Ui::Widget)
  4. {
  5. ui->setupUi(this);
  6. ui->comboBox->installEventFilter(this); // Установим фильтр
  7. }

По статье задано0вопрос(ов)

3

Вам это нравится? Поделитесь в социальных сетях!

P
  • 19 марта 2020 г. 14:32
  • (ред.)

Здравствуйте, у меня есть вопрос по комбобоксу. Примеры из интернета со стилями не дают того, что нужно.

есть комбобокс. рядом кнопка по нажатии которой текущему элементу комбобокса устанавливается некий цвет.

  1. QComboBox * cb
  2. QColor color = QColorDialog::getColor( );
  3. cb->setItemData( cb->currentIndex(), QBrush( color ), Qt::BackgroundRole );

например второму элементу такой цвет

но при наведении мыши цвет перекрывается цыетом селектора. даже если ему затать прозразный цвет.

как можно решить это?

Evgenii Legotckoi
  • 19 марта 2020 г. 16:35
  • (ред.)

Добрый день. Думаю, что нужно писать кастомный делегат. На форуме уже какие-то делегаты проскакивали, не помню только, для комбобоксов их делали или нет.
Но принцип похожий будет.

P
  • 22 марта 2020 г. 2:48
  • (ред.)

вобщем решил проблему. может пригодится кому
без наследования, переопределений , делегатов и т.д ))
не знаю насколько правильно, но всё работает.
весь фокус - несколько строк кода.
можно задать любой цвет которым будет выделяться элемент при наведении.
если цвет брать из самого элемента на котором курсор, то получется , что выделение "как бы прозрачное"
только рамочка видна.

подключение к сигналу взял из примера в документации.
как соорудить стиль из цвета - наткнулся на просторах инета.

  1. connect(comboBox, QOverload<int>::of(&QComboBox::highlighted), [=](int index)
  2. {
  3. QColor color = ... // задаем нужный цвет. или берем цвет из элемента по индексу index
  4. QString style = "QComboBox QAbstractItemView { selection-background-color: rgb(%1, %2, %3); }" ;
  5. style = style.arg(color.red( )).arg(color.green( )).arg(color.blue( ) );
  6. comboBox->setStyleSheet(style);
  7. });

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь