【笔记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);

相关推荐
r_oo_ki_e_11 分钟前
Java Map 集合学习笔记
java·笔记·学习
liuyicenysabel2 小时前
大模型学习笔记 · 第八篇 · 进阶:偏好对齐与多卡训练
人工智能·笔记·学习
必须得开心呀3 小时前
QT解决中文乱码问题
开发语言·qt
熊猫_豆豆4 小时前
QT6 Android C++ 自制美观闹钟
android·c++·qt·闹钟
李永奉5 小时前
杰理可视化SDK开发-【BUG】AC7006F8更换AC7006F6芯片添加双备份OTA升级功能报代码端空间不足问题
bug
番茄育学园5 小时前
我的三款主流云存储音乐库实测笔记
笔记·分类·媒体
stevenzqzq7 小时前
解决复杂bug思路
bug
十月的皮皮8 小时前
C语言学习笔记20260706-栈的压入、弹出序列验证
c语言·笔记·学习
维他奶糖619 小时前
基于 DrissionPage 实现小红书搜索笔记批量采集
笔记
hssfscv10 小时前
QT的学习笔记4——QMainWindow、资源文件以及主要控件的介绍
笔记·qt·学习