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

相关推荐
油炸自行车14 分钟前
【Qt bug排查】Qt项目debug模式下,关闭可视化界面后,后台程序不退出,依然在打印log
bug
东京老树根40 分钟前
SAP学习笔记 - BTP CAP开发06 - Customize Criticality,Map Page,Value help
笔记·学习
AM越.2 小时前
助睿:!!零代码解决!!订单利润分流数据加工o(* ̄▽ ̄*)ブ
数据仓库·笔记·etl·助睿
咸鱼翻身小阿橙2 小时前
Qt QML调用C++注册类
java·c++·qt
魔都大虾3 小时前
旧时光里面有那些情话句子 什么比较热门
笔记
Java成神之路-3 小时前
【算法刷题笔记】全题型导航目录
笔记·算法
zhangrelay3 小时前
云课实践速通系列-基础篇汇总-必修-通识基础和专业基础-2026--工科--自动化、电气、机器人、测控等
linux·笔记·单片机·学习·ubuntu·机器人·自动化
05候补工程师3 小时前
【编译原理】自顶向下语法分析深度解析:从 LL(1) 文法判定、改写到预测分析表
经验分享·笔记·考研·自然语言处理
ErizJ5 小时前
Linux|学习笔记
linux·笔记·学习
wanghanjiett5 小时前
笔记:ESP32驱动SimpleFOC成功(基于Espressif-IDE)
笔记·esp32·foc