【笔记1-8】Qt bug记录:QListWidget窗口的浏览模式切换为ListMode后,滚轮滚动速度变慢

  • 问题现象是,在QListWidget的一个窗口中有一些item,可以用IconMode和ListMode两种模式显示,一开始在IconMode用滚轮滑动速度是正常的,切换到ListMode后滚动速度也正常,但是再切换回来,滚动速度明显变慢,只要不切换ListMode速度就不会变化

最后调查发现是Qt自身的限制,这里先做一个简单的demo,可以再现这个问题

  • idiombrowser.cpp
c 复制代码
#include "idiombrowser.h"

#include <QApplication>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QListWidget>
#include <QPushButton>
#include <QListWidgetItem>

IdiomBrowser::IdiomBrowser(QWidget *parent) : QWidget(parent)
{
    setupUI();
    populateList();
    connectSignals();
}

void IdiomBrowser::switchToListMode()
{
    listWidget->setViewMode(QListView::ListMode);
    listWidget->setDragDropMode(QAbstractItemView::NoDragDrop);
    adjustListSize();
}

void IdiomBrowser::switchToIconMode()
{
    listWidget->setViewMode(QListView::IconMode);
    listWidget->setDragDropMode(QAbstractItemView::NoDragDrop);
    listWidget->setIconSize(QSize(64, 64));
    adjustListSize();
}

void IdiomBrowser::setupUI()
{
    QVBoxLayout *mainLayout = new QVBoxLayout(this);

    // 创建按钮布局
    QHBoxLayout *buttonLayout = new QHBoxLayout();
    listModeButton = new QPushButton("list mode", this);
    iconModeButton = new QPushButton("icon mode", this);

    buttonLayout->addWidget(listModeButton);
    buttonLayout->addWidget(iconModeButton);

    // 创建列表控件
    listWidget = new QListWidget(this);
    listWidget->setSelectionMode(QAbstractItemView::SingleSelection);

    // 初始设置为列表模式
    switchToIconMode();

    mainLayout->addLayout(buttonLayout);
    mainLayout->addWidget(listWidget);

    setWindowTitle("scroll test");
    resize(600, 400);
    // listWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
}

void IdiomBrowser::populateList()
{

    QStringList idioms = {
        "aaaa", "bbbb", "cccc", "dddd",
        "eeee", "ffff", "gggg", "hhhh",
        "iiii", "jjjj", "kkkk", "llll",
        "mmmm", "nnnn", "oooo", "pppp",
        "qqqq", "rrrr", "ssss", "tttt",
        "uuuu", "vvvv", "wwww", "xxxx",
        "vvvv", "wwww",

    };

    for (const QString &idiom : idioms) {
        QListWidgetItem *item = new QListWidgetItem(idiom);
        listWidget->addItem(item);
    }
}

void IdiomBrowser::connectSignals()
{
    connect(listModeButton, &QPushButton::clicked, this, &IdiomBrowser::switchToListMode);
    connect(iconModeButton, &QPushButton::clicked, this, &IdiomBrowser::switchToIconMode);
}

void IdiomBrowser::adjustListSize()
{
    if (listWidget->viewMode() == QListView::IconMode) {
        listWidget->setGridSize(QSize(100, 100));
        listWidget->setSpacing(10);
        listWidget->setWordWrap(true);
    } else {
        listWidget->setGridSize(QSize());
        listWidget->setSpacing(2);
    }
}
  • idiombrowser.h
c 复制代码
#ifndef IDIOMBROWSER_H
#define IDIOMBROWSER_H

#include <QWidget>

class QListWidget;
class QPushButton;

class IdiomBrowser : public QWidget
{
    Q_OBJECT

public:
    IdiomBrowser(QWidget *parent = nullptr);

private slots:
    void switchToListMode();
    void switchToIconMode();

private:
    void setupUI();
    void populateList();
    void connectSignals();
    void adjustListSize();

    QListWidget *listWidget;
    QPushButton *listModeButton;
    QPushButton *iconModeButton;
};

#endif // IDIOMBROWSER_H
  • main.cpp
c 复制代码
#include <QApplication>
#include "idiombrowser.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    IdiomBrowser browser;
    browser.show();

    return app.exec();
}

通过对Qt6源码进行debug发现了问题原因

首先是在void QListModeViewBase::updateVerticalScrollBar(const QSize &step)这个函数中

如果切换到ListMode就会走进第一个if,然后setSingleStep(1)

设置为1后,这里的viewMayChangeSingleStep就会变成false

viewMayChangeSingleStep是false的情况下,后续切换模式时,就无法切换step,也就是滚动单步步长singleStep永远是1

这里源码的注释也说明了,如果将setSingleStep设置为一个reasonable值,就无法切换了,需要再设为-1才能恢复

singleStep用于滑动时计算步长

解决方案是将滚动模式设为按像素滚动,这样不会走setSingleStep(1);

setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);

相关推荐
把我格子衫拿来5 小时前
VTK 9.5 与 Qt 6 联合开发:从嵌入三维窗口到可维护的桌面架构
c++·python·qt·vtk·三维可视化
优选资源分享6 小时前
PicGo v3.0.3 新版 | 开源免费图床工具
javascript·笔记·electron
星恒随风7 小时前
Linux线程概念详解:从分页存储、页表、MMU与TLB,深入理解线程和进程的区别与联系
linux·运维·笔记·学习·状态模式
qq_284274057 小时前
数控机床编程基础与坐标系:编程六步流程、程序号/程序段/程序字格式,与右手定则下车床铣床XYZ轴判定(含考点)
笔记·学习·自动化·制造
问心无愧05137 小时前
[SUCTF 2019]EasySQL
笔记
ss2737 小时前
PG实战笔记 | 09 PostgreSQL psql客户端基本操作
数据库·笔记·postgresql
xxwl5858 小时前
区域赛分类题解
c++·笔记·学习·算法
成都蜀味缘餐饮技术培训学校11 小时前
油炸串串技术培训实战指南,核心食材选购与预处理标准
数据仓库·经验分享·笔记·课程设计·微信公众平台
摇滚侠11 小时前
《大模型应用开发实践:基于 Spring AI+DeepSeek 实现》第 11 章 大模型技术概览 阅读笔记 1
人工智能·笔记·spring
把我格子衫拿来11 小时前
VTK 与 Qt 的 CMake 工程怎么组织?模块、工具链与二进制兼容排错
c++·qt·vtk·cmake·工程实践