QComboBox多选框的实现(源码):采用QListWidget实现多选后控件丢失的问题(探讨)

本文探讨了在使用QComboBox实现多选功能时,采用QListWidget作为视图导致的控件丢失问题。分析了问题原因在于视图与滑动条关联断裂,并提供了两种解决方案:滑动条位置复位和记录并重置滑动条位置。附带自定义MyCheckBox的完整代码。
摘要由CSDN通过智能技术生成

1. 多选下拉框(带搜索功能)的问题

示例代码
上述代码是本文的主要参考代码,但是它会产生如下问题:
当下拉框条目较多,出现右侧滑动条后,将滑动条拉到最后,收起下拉框,再点开下拉框,上方的所有控件都会丢失,下方出现对应个数的空白区域。反复这样操作:每次将滑动条拉到最底下收起再弹出,可以发现最终所有条目都会消失,只留下一堆空白
问题

2. 问题分析

由于采用了自定义的视图,即用QListWidget替换了QComboBox的默认视图,导致内部关联缺失。
可以发现,在每次弹出下拉框时,右侧的滑动条都会默认置位最顶端,而左侧视图部分依旧是上次收起下拉框时所显示的视图条目,因此视图范围和滑动条直接的关联断开了,故出现该问题。

3. 解决方法

上问所提博客的代码中的条目采用QCheckBox,但是由于可能会存在的一些问题:

  • QCheckBox样式中hover背景颜色只有鼠标在最左侧的“框+文本”才显示,右侧空白无法显示,而显示的是QComboBox默认条目的hover背景颜色
  • 鼠标点击QCheckBox左侧“框+文本”与右侧空白所触发的事件很可能是不同的(行为不同)

所以推荐继承QCheckBox进行稍微修改以克服,相关代码在最后的附录。
代码中鼠标释放事件必须屏蔽,至于另外两个为什么要屏蔽,当然你也可以不屏蔽,跑跑看,满足效果就行。
在这里插入图片描述
下面的解决方法都是基于采用自定义MyCheckBox才成立的,如果依旧使用系统的QCheckBox,则行为不可预测

3.1 完美方案

最完美的解决方法是将这种关联正确连接,但是折腾很久目前未能实现

3.2 滑动条位置复位

重写hidePopup函数,在其收起的前一刻强制将滑动条复位:

void MCC::hidePopup(){
   
	......
    this->list_widget_->verticalScrollBar()->setSliderPosition(0);
    QComboBox::hidePopup();
}

这样就可以让视图位置和滑动条位置一致,该方法的缺陷就是每次弹出下拉框,都会显示第一行内容,无法记录上一刻收起的位置

3.3 重置滑动条位置

重写hidePopup函数,在其收起的一刻记录滑动条位置,再重写showPopup,在其弹出重置滑动条位置

void MCC::hidePopup(){
   
	......
    this->scroll_value = this->list_widget_->verticalScrollBar()->value();
    QComboBox::hidePopup();
}

void MCC::showPopup(){
   
    QComboBox::showPopup();
    this->list_widget_->verticalScrollBar()->setSliderPosition(this->scroll_value);
}

该方法看起来美好,但是实际使用下会出现一个问题:如果仅仅是滑动,确实能够保留上次收起的位置,但是如果点击任意一个条目后,下次弹出又是从头开始(其实重置位置是有效的,但是重置后的150ms后,下拉框的视图居然诡异的重置了!),和方法3.2效果一样了,这个问题我用了一天采用各种事件、信号过滤器解决,差点走火入魔,但是转念一想,用户选择条目后往往要从头开始,很可能要用到搜索框,所以这很明显不是BUG而是特性(如果实在要保持一致性,可以在showPopup最后加个定时器延迟200毫秒再次执行一次滑动条置位
无题

4. 附录(完整代码)

4.1 mycheckbox.h

#ifndef MYCHECKBOX_H
#define MYCHECKBOX_H
#include <QCheckBox>
class MyCheckBox : public QCheckBox {
   
    Q_OBJECT
public:
    explicit MyCheckBox(QWidget *parent = 0);
protected:
    void mousePressEvent(QMouseEvent *e);
    void mouseReleaseEvent(QMouseEvent *e);
    void mouseMoveEvent(QMouseEvent *);

signals:
public slots:
private:
    QObject* ptr;
};
#endif // MYCHECKBOX_H

4.2 mycheckbox.cpp

#include "mycheckbox.h"
#include "mcc.h"
#include <QMouseEvent>
#include <QEvent>
#include <QApplication>
#include <QDebug>
#define cout qDebug() << "[" << __FILE__ <<":" << __LINE__ << "]"
MyCheckBox::MyCheckBox(QWidget *parent) : QCheckBox(parent) {
   
    ptr = parent;
}
void MyCheckBox::mousePressEvent(QMouseEvent *e){
   
//    QCheckBox::mousePressEvent(e);
    Q_UNUSED(e);
}
void MyCheckBox::mouseReleaseEvent(QMouseEvent *e){
   
//    QCheckBox::mouseReleaseEvent(e);
    Q_UNUSED(e);
    this->setChecked(!this->isChecked());
    // 其他需要处理的函数
}
void MyCheckBox::mouseMoveEvent(QMouseEvent *e){
   
//    QCheckBox::mouseMoveEvent(e);
    Q_UNUSED(e);
}

4.3 mcc.h

#ifndef MCC_H
#
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值