ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Qt数据列表展示

2019-04-21 08:55:09  阅读:586  来源: 互联网

标签:widget Qt 展示 列表 scrollbar widgets new startPos


Qt数据列表展示

Qt中使用QListWidget,ableWidget,QTreeWidget(只考虑最大3层)自定义子widget来展示数据的时候,通常子widget的个数达到了上千加载展示就会很慢,而且很耗内存。原因是new出来的widget太多了。下面的解决方案希望能帮助你。

原理:

其实一个列表展示给用户看的高度是很有限的不会超过一个屏幕的高度,而这个高度只需要很少的子widget就可以填充满,所以,当你有1万个数据要展示时,并不需要每个数据都new一个widget(自定义的)来展示,你只需要new显示出来的那几个widget,当滚动条滚动的时候将超出屏幕的widget隐藏起来,将要新展示的数据重用隐藏的widget来展示而不需要new新的widget,只有当widget个数不足以覆盖列表显示的区域时才new新的(最多也就覆盖一个屏幕需要的个数)

组件组成

  1. 一个父widget,容纳子widget和滚动条;
  2. 子widget使用move方法填充满展示区域;
  3. 滚动条加载更多内容。

基本方法

  1. 在showEvent里面刷新要展示的数据到widget;
  2. resizeEvent会改变展示区域的大小,需重新刷新数据到widget使其新的区域能完全被widget展示;
  3. wheelEvent需要改变滚动条当前值;
  4. 连接QScrollBar::valueChanged事件,当事件发生时要将新的数据展示到widget上。

怎样重用子widget

QList<ItemWidget*> m_widgets;

m_widgets来缓存所有创建出来的子widget,当需要新widget的时候看缓存里是否有隐藏的,如果有就拿出来进行新数据的展示,如果没有就根据数据的类型来创建新的widget。

ItemWidget *TreeWidget::getWidget(const ItemInfo &info)

{

    // 存在这种类型的widget,并且没有被使用(不可见)直接返回

    ItemWidget *widget = nullptr;

    for (int i=0; i<m_widgets.size(); i++) {

        if (m_widgets[i]->data().type == info.type && !m_widgets[i]->isVisible()) {

            widget = m_widgets[i];

            break;

        }

    }

 

    if (widget == nullptr) {

        if (info.type == Top) {

            widget = new TopWidget(this);

        } else if (info.type == Parent) {

            widget = new ParentWidget(this);

        } else if (info.type == Child) {

            widget = new ChildWidget(this);

        } else {

            Q_ASSERT(0);

        }

        connect(widget, &ItemWidget::sigMousePress, [this, widget]() {

            if (widget->data().type != Child) {

                ItemInfo newInfo = widget->data();

                newInfo.isExpand = !newInfo.isExpand;

                updateItemInfo(newInfo);

                refreshWidgets();

            } else {

                gotoSelected(widget->data().id);

            }

            emit sigItemMousePress(widget->data());

        });

        connect(widget, &ItemWidget::sigMouseDoubleClick, [this, widget]() {

            emit sigItemMouseDoubleClick(widget->data());

        });

        m_widgets.append(widget);

    }

 

    widget->setData(info);

    // 如果是当前选中的widget

    if (widget->data().type == Child) {

        widget->setSelected(widget->data().id == m_curChildId);

    }

    widget->resize(this->width(), widget->height());

    widget->show();

    return widget;

}

重点是刷新数据到widget上

首先,将所有可见widget隐藏起来,遍历所有数据,y轴从0开始每次增加遍历数据展示时需要的高度,当y值大于滚动条值并且小于组件高度时就需要将子widget展示出来。

组件高度就是滚动条page step值。

滚动条mininum为0,maxinum为y – pageStep。

公式:document length = maxinum() - minimum() + pageStep()

void TreeWidget::refreshWidgets()

{

    for (int i=0; i<m_widgets.size(); i++) {

        m_widgets[i]->resize(this->width(), m_widgets[i]->height());

        m_widgets[i]->hide();

    }

 

    auto moveItem = [this](const ItemInfo &item, int &y, int &startPos, bool &isContinue) {

        if (y >= m_scrollbar->value() && isContinue) {

            getWidget(item)->move(0, startPos);

            startPos += item.height;

            isContinue = startPos < this->height();

        }

        y += item.height;

    };

 

    int y = 0, startPos = 0;

    bool isContinue = true;

    for (int i=0; i<m_list.count(); i++) {

        const ItemInfo &topItem = m_list[i];

        moveItem(topItem, y, startPos, isContinue);

        if (topItem.childList.count() > 0 && topItem.isExpand) {

            for (int j=0; j<topItem.childList.count(); j++) {

                const ItemInfo &parentItem = topItem.childList[j];

                moveItem(parentItem, y, startPos, isContinue);

                if (parentItem.childList.count() > 0 && parentItem.isExpand) {

                    for (int k=0; k<parentItem.childList.count(); k++) {

                        const ItemInfo &childItem = parentItem.childList[k];

                        moveItem(childItem, y, startPos, isContinue);

                    }

                }

            }

        }

    }

 

    qDebug() << "y:" << y << ", startPos:" << startPos << ", height:" << this->height();

    m_scrollbar->move(this->width() - m_scrollbar->width(), 0);

    m_scrollbar->resize(m_scrollbar->width(), this->height());

    m_scrollbar->setPageStep(this->height());

    if (y > startPos) {

        m_scrollbar->setMaximum(y - m_scrollbar->pageStep());

        m_scrollbar->show();

        m_scrollbar->raise();

    } else {

        m_scrollbar->setMaximum(0);

        m_scrollbar->setValue(0);

        m_scrollbar->hide();

    }

    qDebug() << "min:" << m_scrollbar->minimum() << ", max:" << m_scrollbar->maximum() << ", value:" << m_scrollbar->value();

}

结尾

  • 性能优化
  • 响应事件扩充
  • 代码中展示的元素有17000多个效率还是很高的
  • 代码中有三层也有两层,当然一层的话相信更简单
  • 红色item是最顶层
  • 绿色item是中间层
  • 白色item是最底层

https://www.icode9.com/i/?i=20160804225858636

标签:widget,Qt,展示,列表,scrollbar,widgets,new,startPos
来源: https://blog.csdn.net/liubing8609/article/details/89427605

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有