【问题标题】:Performance problems w/ many widgets respectively stacked QTableWidgets性能问题与/许多小部件分别堆叠 QTableWidget
【发布时间】:2018-12-17 12:56:14
【问题描述】:

我需要显示一个复杂的表格并决定使用堆叠的 QTableWidgets。随着行数的增加,程序需要大量时间来创建所有小部件,并且几乎需要同样的时间来显示。

主表如下所示:MainTable

表格中堆叠的TableWidget:

堆叠表

如果单元格包含数据,则在 MainTable 的一个单元格中至少有一个 TableWidget,在最坏的情况下,该单元格中还有 2 个 TableWidgets。这意味着我可以在一个单元格中拥有 3 个 TableWidget。

使用 cProfile 和 time.time 测量 80 行(每行包含 48 个复杂单元):

complete update time: 15s (manually stopped)
time to create the table: 7.548534870147705s (time.time over complete function)
display time: 7.5s (complete update time - function time)
rows: 80

     63600 function calls in 7.462 seconds

   Ordered by: internal time

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
 1896    2.455    0.001    3.882    0.002     DigitalePlanungstafel.py:6054(grundWidgetErstellen) -- (create table in cell)
 3936    2.027    0.001    2.027    0.001 {built-in method setCellWidget}
 2535    1.306    0.001    1.306    0.001 {built-in method setColumnCount}
  630    0.770    0.001    1.183    0.002 DigitalePlanungstafel.py:6035(obenWidgetErstellen) -- (create table in table in cell)
 2607    0.674    0.000    0.674    0.000 {built-in method setRowCount}
 2528    0.059    0.000    0.059    0.000 {built-in method horizontalHeader}
 2526    0.021    0.000    0.021    0.000 {built-in method verticalHeader}
  163    0.019    0.000    0.019    0.000 {method 'execute' of 'sqlite3.Cursor' objects}
 2526    0.016    0.000    0.016    0.000 {built-in method setFrameShape}
 1410    0.014    0.000    0.014    0.000 {built-in method setStyleSheet}
 4502    0.013    0.000    0.013    0.000 {built-in method setRowHeight}
 2526    0.009    0.000    0.009    0.000 {built-in method setFixedSize}
 2546    0.009    0.000    0.009    0.000 {built-in method setColumnWidth}
 5052    0.009    0.000    0.009    0.000 {built-in method setVisible}
 1329    0.007    0.000    0.007    0.000 {built-in method setItem}
 2181    0.006    0.000    0.006    0.000 {built-in method cellWidget}
   80    0.005    0.000    0.005    0.000 {built-in method addWidget}
 2526    0.004    0.000    0.004    0.000 {built-in method setEditTriggers}
  929    0.004    0.000    0.004    0.000 {built-in method setBackground}
 1330    0.003    0.000    0.003    0.000 {method 'format' of 'str' objects}
  414    0.003    0.000    0.003    0.000 {built-in method _pickle.loads}
  336    0.003    0.000    0.003    0.000 {method 'strftime' of 'datetime.date' objects}
 2526    0.003    0.000    0.003    0.000 {built-in method setHorizontalScrollBarPolicy}
 1410    0.002    0.000    0.002    0.000 {built-in method setFixedHeight}
 1377    0.002    0.000    0.002    0.000 {built-in method setTextAlignment}
   83    0.002    0.000    0.004    0.000 _strptime.py:321(_strptime)
    2    0.002    0.001    0.002    0.001 {built-in method setSortingEnabled}
 2526    0.001    0.000    0.001    0.000 {built-in method setShowGrid}
 1570    0.001    0.000    0.001    0.000 {built-in method rowHeight}
 2526    0.001    0.000    0.001    0.000 {built-in method setSelectionMode}
  163    0.001    0.000    0.001    0.000 {method 'fetchall' of 'sqlite3.Cursor' objects}
  240    0.001    0.000    0.001    0.000 DigitalePlanungstafel.py:7494(__init__)
 2526    0.001    0.000    0.001    0.000 {built-in method setVerticalScrollBarPolicy}
    1    0.001    0.001    0.001    0.001 {built-in method sortByColumn}
   80    0.001    0.000    0.001    0.000 {built-in method setLayout}
   83    0.001    0.000    0.001    0.000 {built-in method _locale.setlocale}
    1    0.001    0.001    0.001    0.001 {built-in method _sqlite3.connect}
   89    0.000    0.000    0.000    0.000 {built-in method setForeground}
   83    0.000    0.000    0.000    0.000 {method 'match' of '_sre.SRE_Pattern' objects}
   83    0.000    0.000    0.004    0.000 _strptime.py:562(_strptime_datetime)
   48    0.000    0.000    0.000    0.000 {built-in method setHorizontalHeaderItem}
   80    0.000    0.000    0.000    0.000 {built-in method setContentsMargins}
   83    0.000    0.000    0.005    0.000 {built-in method strptime}
   83    0.000    0.000    0.000    0.000 locale.py:379(normalize)
   88    0.000    0.000    0.000    0.000 {built-in method setFont}
  160    0.000    0.000    0.000    0.000 {built-in method setData}
   83    0.000    0.000    0.000    0.000 {method 'groupdict' of '_sre.SRE_Match' objects}
   80    0.000    0.000    0.000    0.000 {built-in method setAlignment}
   83    0.000    0.000    0.001    0.000 _strptime.py:29(_getlang)
   83    0.000    0.000    0.001    0.000 locale.py:565(getlocale)
   83    0.000    0.000    0.001    0.000 locale.py:462(_parse_localename)
   80    0.000    0.000    0.000    0.000 {built-in method setUnderline}
    1    0.000    0.000    0.000    0.000 {built-in method io.open}
  249    0.000    0.000    0.000    0.000 {method 'get' of 'dict' objects}
    1    0.000    0.000    0.000    0.000 {method 'close' of 'sqlite3.Connection' objects}
  160    0.000    0.000    0.000    0.000 {built-in method item}
  742    0.000    0.000    0.000    0.000 DigitalePlanungstafel.py:7499(__lt__)
   48    0.000    0.000    0.000    0.000 {built-in method today}
  165    0.000    0.000    0.000    0.000 {method 'toordinal' of 'datetime.date' objects}
  475    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
  167    0.000    0.000    0.000    0.000 {built-in method builtins.len}
  166    0.000    0.000    0.000    0.000 {built-in method builtins.isinstance}
   83    0.000    0.000    0.000    0.000 {method 'end' of '_sre.SRE_Match' objects}
   84    0.000    0.000    0.000    0.000 {method 'lower' of 'str' objects}
    1    0.000    0.000    0.000    0.000 {method 'close' of '_io.TextIOWrapper' objects}
    2    0.000    0.000    0.000    0.000 {built-in method builtins.print}
   83    0.000    0.000    0.000    0.000 {method 'keys' of 'dict' objects}
   47    0.000    0.000    0.000    0.000 {built-in method columnCount}
   83    0.000    0.000    0.000    0.000 {method 'weekday' of 'datetime.date' objects}
   96    0.000    0.000    0.000    0.000 {method 'date' of 'datetime.datetime' objects}
   20    0.000    0.000    0.000    0.000 {built-in method columnWidth}
    1    0.000    0.000    0.000    0.000 {built-in method _locale._getdefaultlocale}
    3    0.000    0.000    0.000    0.000 {method 'split' of 'str' objects}
    1    0.000    0.000    0.000    0.000 _strptime.py:284(_calc_julian_from_U_or_W)
    1    0.000    0.000    0.000    0.000 _bootlocale.py:11(getpreferredencoding)
    1    0.000    0.000    0.000    0.000 {built-in method sortIndicatorOrder}
    2    0.000    0.000    0.000    0.000 {built-in method time.time}
    1    0.000    0.000    0.000    0.000 {method 'cursor' of 'sqlite3.Connection' objects}
    2    0.000    0.000    0.000    0.000 {method 'index' of 'list' objects}
    1    0.000    0.000    0.000    0.000 {built-in method fromordinal}
    1    0.000    0.000    0.000    0.000 {built-in method sortIndicatorSection}
    1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
    1    0.000    0.000    0.000    0.000 codecs.py:259(__init__)

调用函数和创建表的时间是可以的,但程序需要几乎相同的时间,直到它做出反应。

我们的目标是将更新时间减少大约。 50%。我需要显示大约 200 行。

堆叠的 QTableWidget 是正确的方法吗?如果是,我必须做些什么来优化更新时间?

我已经考虑过将演示文稿从 QTableWidget 更改为 QGraphicsView 并简单地绘制矩形。 或者可能是一个组合,例如:使用 QTableWidget 作为标题和第一列,然后合并所有复杂的单元格并插入 QGraphicsView 但我不确定我是否能够为绘制的单元格获得正确的大小,我做到了不知道显示时间会不会更短。

你们认为这样的桌子的正确方法是什么?

如果你需要,我可以追加更新表格的函数。

编辑:

我现在在 MainTable 中为一个 Block 使用 2 行,这将堆叠的小部件数量从 2.526 个减少到 7 个!

相同行的时间测量现在如下所示:

complete update time: ~2s (manually stopped)
time to create the table: 0.572490930557251 (time.time over complete function)
display time: ~1.5s (complete update time - function time)
rows: 160
     20912 function calls in 0.534 seconds

Ordered by: internal time

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
 1417    0.258    0.000    0.258    0.000 {built-in method setCellWidget}
   88    0.209    0.002    0.209    0.002 {built-in method setRowCount}
  163    0.017    0.000    0.017    0.000 {method 'execute' of 'sqlite3.Cursor' objects}
 1410    0.010    0.000    0.010    0.000 {built-in method setStyleSheet}
   80    0.005    0.000    0.005    0.000 {built-in method addWidget}
 1336    0.004    0.000    0.004    0.000 {built-in method setItem}
    7    0.003    0.000    0.004    0.001 DigitalePlanungstafel.py:6037(obenWidgetErstellen)
  501    0.003    0.000    0.003    0.000 {built-in method _pickle.loads}
 1990    0.003    0.000    0.003    0.000 {built-in method cellWidget}
  336    0.002    0.000    0.002    0.000 {method 'strftime' of 'datetime.date' objects}
   83    0.002    0.000    0.004    0.000 _strptime.py:321(_strptime)
 1330    0.002    0.000    0.002    0.000 {method 'format' of 'str' objects}
 1410    0.002    0.000    0.002    0.000 {built-in method setFixedHeight}
  929    0.001    0.000    0.001    0.000 {built-in method setBackground}
 1377    0.001    0.000    0.001    0.000 {built-in method setTextAlignment}
  240    0.001    0.000    0.001    0.000 DigitalePlanungstafel.py:7452(__init__)
  163    0.001    0.000    0.001    0.000 {method 'fetchall' of 'sqlite3.Cursor' objects}
   16    0.001    0.000    0.001    0.000 {built-in method setColumnCount}
  770    0.001    0.000    0.001    0.000 {built-in method setSpan}
 2127    0.001    0.000    0.001    0.000 {built-in method item}
 1570    0.001    0.000    0.001    0.000 {built-in method rowHeight}
   80    0.001    0.000    0.001    0.000 {built-in method setLayout}
   83    0.000    0.000    0.000    0.000 {built-in method _locale.setlocale}
    1    0.000    0.000    0.000    0.000 {built-in method _sqlite3.connect}
  167    0.000    0.000    0.000    0.000 {built-in method setRowHeight}
   89    0.000    0.000    0.000    0.000 {built-in method setForeground}
   83    0.000    0.000    0.000    0.000 {method 'match' of '_sre.SRE_Pattern' objects}
   48    0.000    0.000    0.000    0.000 {built-in method setHorizontalHeaderItem}
   83    0.000    0.000    0.004    0.000 _strptime.py:562(_strptime_datetime)
    7    0.000    0.000    0.000    0.000 {built-in method takeItem}
   80    0.000    0.000    0.000    0.000 {built-in method setContentsMargins}
   83    0.000    0.000    0.004    0.000 {built-in method strptime}
   88    0.000    0.000    0.000    0.000 {built-in method setFont}
  160    0.000    0.000    0.000    0.000 {built-in method setData}
   83    0.000    0.000    0.000    0.000 locale.py:379(normalize)
   80    0.000    0.000    0.000    0.000 {built-in method setAlignment}
   83    0.000    0.000    0.001    0.000 _strptime.py:29(_getlang)
   83    0.000    0.000    0.000    0.000 {method 'groupdict' of '_sre.SRE_Match' objects}
   83    0.000    0.000    0.001    0.000 locale.py:565(getlocale)
    1    0.000    0.000    0.000    0.000 {method 'close' of 'sqlite3.Connection' objects}
    1    0.000    0.000    0.000    0.000 {built-in method io.open}
    7    0.000    0.000    0.000    0.000 {built-in method horizontalHeader}
   80    0.000    0.000    0.000    0.000 {built-in method setUnderline}
  249    0.000    0.000    0.000    0.000 {method 'get' of 'dict' objects}
   83    0.000    0.000    0.000    0.000 locale.py:462(_parse_localename)
   48    0.000    0.000    0.000    0.000 {built-in method today}
    7    0.000    0.000    0.000    0.000 {built-in method verticalHeader}
  475    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
  167    0.000    0.000    0.000    0.000 {built-in method builtins.len}
  165    0.000    0.000    0.000    0.000 {method 'toordinal' of 'datetime.date' objects}
    1    0.000    0.000    0.000    0.000 {method 'close' of '_io.TextIOWrapper' objects}
  166    0.000    0.000    0.000    0.000 {built-in method builtins.isinstance}
    7    0.000    0.000    0.000    0.000 {built-in method setFrameShape}
   27    0.000    0.000    0.000    0.000 {built-in method setColumnWidth}
   84    0.000    0.000    0.000    0.000 {method 'lower' of 'str' objects}
    1    0.000    0.000    0.000    0.000 {method 'sort' of 'list' objects}
   83    0.000    0.000    0.000    0.000 {method 'end' of '_sre.SRE_Match' objects}
   87    0.000    0.000    0.000    0.000 DigitalePlanungstafel.py:6059(<lambda>)
   83    0.000    0.000    0.000    0.000 {method 'keys' of 'dict' objects}
    2    0.000    0.000    0.000    0.000 {built-in method builtins.print}
    7    0.000    0.000    0.000    0.000 {built-in method setFixedSize}
   14    0.000    0.000    0.000    0.000 {built-in method setVisible}
   83    0.000    0.000    0.000    0.000 {method 'weekday' of 'datetime.date' objects}
   96    0.000    0.000    0.000    0.000 {method 'date' of 'datetime.datetime' objects}
    7    0.000    0.000    0.000    0.000 {built-in method setEditTriggers}
   20    0.000    0.000    0.000    0.000 {built-in method columnWidth}
    7    0.000    0.000    0.000    0.000 {built-in method setHorizontalScrollBarPolicy}
    1    0.000    0.000    0.000    0.000 {built-in method _locale._getdefaultlocale}

更新时间很好,但由于拆分,我有两个问题。

  1. 排序(在标题上)不再起作用。这是由合并引起的,它把一切都搞砸了。有没有办法在排序之前冻结两个关联的行?

  2. 我只想一次选择一行。拆分的原因无论选择哪一个,我都需要选择两个关联的行。没什么大不了的,但看起来不太好(见图)。

MainTable selected row

MainTable selected row

【问题讨论】:

  • 为了获得快速执行的 GUI,您肯定需要使用 QTableView(带有模型)。
  • 您需要更清楚地解释为什么您在这样的表格中使用表格。您是否只是将它们用作在单元格中进行复杂格式化的快速而肮脏的方式?如果是这样,更好的方法是使用item-delegates,然后可以直接绘制单元格。如果单元格不是只读的,这也将允许您使用自定义编辑小部件。
  • 我在表格中使用表格,因为它是我能够管理复杂格式的唯一方法。单元格是只读的 (NoEditTriggers)。我是 Python 和 QT 的初学者——这就是为什么我不想让它变得太复杂。目前我的想法是使用 2 行而不是 1 行并合并前 6 行,这应该会大大减少堆叠的表格 - 完成后我会告诉你它会快多少。跨度>

标签: python python-3.x pyqt pyqt5


【解决方案1】:

您不想这样做 - 而是:

  1. 为您的数据使用模型。

  2. 使用使模型适应您希望拥有的视图的视图模型。

  3. 使用QTableView 显示视图模型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-18
    • 2016-11-13
    • 1970-01-01
    • 2019-04-25
    • 1970-01-01
    • 1970-01-01
    • 2013-05-26
    • 2020-12-27
    相关资源
    最近更新 更多