如何在Qt C ++应用程序中显示包含大量小部件的可滚动列表? [英] How to display a scrollable list with a substantial amount of widgets as items in a Qt C++ app?

查看:63
本文介绍了如何在Qt C ++应用程序中显示包含大量小部件的可滚动列表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目标:要在Windows 7、10下的Qt5 C ++应用程序中显示可滚动的自定义窗口小部件列表,这些列表共计成千上万(甚至更多)个小数目.

问题:程序将窗口最小化到任务栏并再次还原后,停止响应.它不会崩溃.CPU使用率常数为25%.即使等待了几分钟,GUI也没有再次响应.此外,通常会消耗大量内存(超过200M),即使对于10万个 QLabels (每个 QLabel 大约2k),我认为这也太多了./p>

此处是一些建议的解决方案类似的问题,我认为这不适合我的情况.

示例:以下示例说明了该问题.为了演示起见,使用了 QLabels 列表,但是它可以是从 QWidget 派生的任何类.

MainWindow.h

  #ifndef MAINWINDOW_H#define MAINWINDOW_H#include< QMainWindow>#include< QScrollArea>#include< QVBoxLayout>#include< QLabel>类MainWindow:公共QMainWindow{Q_OBJECT上市:显式MainWindow(QWidget * parent = 0);};#endif//MAINWINDOW_H 

MainWindow.cpp

  #include"MainWindow.h"MainWindow :: MainWindow(QWidget * parent):QMainWindow(parent){QScrollArea * scrollArea =新的QScrollArea(this);QFrame * frame =新的QFrame();QVBoxLayout * l =新的QVBoxLayout(frame);整数N = 121004;scrollArea-> setWidget(frame);scrollArea-> setWidgetResizable(true);for(int n = 0; n< N; n ++){l-> addWidget(new QLabel(QString :: number(n),this));}调整大小(640,480);setCentralWidget(scrollArea);} 

解决方案

我有一些坏消息和一些好消息:

坏消息:您不能直接使用Qt Widgets完成此操作.

好消息:有一种方法可以做到,这与列表中的项目数量(数十亿)无关,但是您需要给自己一些时间来学习如何做到这一点.

所以,第一件事:QScrollArea并不是这样做的方法.正确的方法是使用模型/视图/控制器编程范例.具有要显示信息的数据模型必须与视图完全分开,以便Qt仅担心显示用户尝试查看的项目.想想看:如果您要在列表中放入十亿个元素,这是否意味着用户必须一次查看所有元素?这是否意味着Qt必须全部渲染?在您的代码中,这就是您要Qt执行的操作.您感到惊讶吗?

咨询电话.1::了解Qt如何管理模型/视图编程,然后选择正确的查看工具.我建议您使用 QListView . QTableView 如果可以将它们放在表中,将使事情变得更容易.

列表上的控件是通过委托完成的.委托是负责在视图中绘制小部件的类.默认将只做文本还是图标.

咨询电话.2:不必为每个元素创建Qt小部件.我刚刚回答了另一个人的问题即使使用委托也无法使用.看一下 Qt Torrent示例,看看如何绘制控件在那里.

您可以执行的是绘制控件,而不是小部件.这是因为您创建的每个小部件都必须进入Qt中的主事件循环,这会使您的程序变慢(并且您已经体验到了).如果从1循环到1百万只是为了增加数字,则将花费大量时间.您是否真的希望Qt的事件循环遍历您的所有小部件以处理每个小部件?

咨询电话.3:从简单开始!您似乎有很多事要做.从模型/视图开始,然后添加将绘制自定义控件的委托,然后将其展开.给自己时间去学习所有这一切.

祝你好运!

Goal: To have a scrollable list of custom widgets amounting hunderts of thousands (and possibly more) in a Qt5 C++ application under Windows 7, 10.

Problem: The program stops responding after minimizing the window to the task bar and restoring it again. It doesn't crash though. The CPU usage constants 25%. The GUI doesn't become responsive again even after several minutes of waiting. Furthermore, a large amount of memory is being consumed in general (more than 200M), which I think is too much even for 100k QLabels (aprox 2k per QLabel).

Here are some suggested solutions to a similar problem, which I don't find suitable for my case.

Example: The following example illustrates the problem. For the sake of the demonstration a list of QLabels is used, but it could be any class derived from QWidget.

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QLabel>

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
};

#endif // MAINWINDOW_H

MainWindow.cpp

#include "MainWindow.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    QScrollArea *scrollArea = new QScrollArea(this);
    QFrame *frame = new QFrame();
    QVBoxLayout *l = new QVBoxLayout(frame);
    int N = 121004;

    scrollArea->setWidget(frame);
    scrollArea->setWidgetResizable(true);

    for (int n = 0; n < N; n++) { l->addWidget(new QLabel(QString::number(n), this)); }

    resize(640, 480);
    setCentralWidget(scrollArea);
}

解决方案

I have some bad news and some good news:

The bad news: You cannot do this with Qt Widgets directly.

The good news: There's a way to do it, that's independent of the number of items you have in the list (even billions), but you need to give yourself the time to learn how to do this.

So, first thing: QScrollArea is SO not the way to do this. The correct way to do this is using the Model/View/Controller programming paradigm. The data model that has the information to be displayed has to be completely separated from the view, so that Qt could only worry about displaying the items the user is trying to view. Think about it: If you have a billion elements to put in that list, does that mean the user has to see them all at once? Does that mean Qt has to render them all? In your code, that's what you're asking Qt to do. Are you surprised it's slow?

Advice Nr. 1: Read how Qt manages Model/View programming, then choose the correct viewing tool. I suggest QListView for what you described. QTableView will make things easier for you if you can put things in a table.

The control on the list is done through delegates. A delegate is the class responsible for drawing widgets in the view. The default will just do text vs icons.

Advice Nr. 2: Forget about creating Qt widgets for every element. I just finished answering another guy's question on why this won't work, even when using delegates. Take a look at Qt Torrent Example to see how controls are drawn there.

What you can do is draw controls, not widgets. This is because every widget you create has to go to the main event loop in Qt, which will make your program slow (and you experienced that already). If you loop from one to million just to add numbers it'll take a significant amount of time. Do you really want Qt's event loop to loop over all your widgets to process every one of them?

Advice Nr. 3: Start simple! You seem to have a lot to do. Start with model/view, then add a delegate that will paint a custom control, then expand it. Give yourself the time to learn all this.

Good luck!

这篇关于如何在Qt C ++应用程序中显示包含大量小部件的可滚动列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆