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
#