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

相关推荐
伯明翰java2 小时前
Redis学习笔记-List列表(2)
redis·笔记·学习
AA陈超3 小时前
使用UnrealEngine引擎,实现鼠标点击移动
c++·笔记·学习·ue5·虚幻引擎
IMPYLH5 小时前
Lua 的 assert 函数
开发语言·笔记·junit·单元测试·lua
AA陈超5 小时前
Lyra源码分析:LyraCharacterMovementComponent
c++·笔记·学习·ue5·虚幻引擎·lyra
程序猿阿伟5 小时前
《从被动修复到免疫:游戏Bug闭环体系的深度搭建指南》
游戏·bug
Chase_______6 小时前
【Maven篇】我整理了一篇Maven笔记
笔记·python·maven
立志成为大牛的小牛7 小时前
数据结构——四十八、B树(王道408)
数据结构·笔记·b树·学习·考研·算法
三品吉他手会点灯7 小时前
stm32f103学习笔记-17-STM32 中断应用总结
笔记·stm32·单片机·嵌入式硬件·学习
Kapibalapikapi8 小时前
Python 笔记 | 常用的内置类、内置方法
笔记·python