Qt ソートON状態のアイテムビュークラスへのアイテムの追加の際の実行コスト

QtにはQAbstractItemViewを継承したアイテムビュークラスがいくつかデフォルトで用意されていますが、この内のQListWidget,QTableView,QTreeViewとこれらを継承したクラス(QTableWidget, QTreeWidget)にはアイテムを自動でソートして表示してくれる機能があり、setSortingEnabled関数でソート機能のON/OFFを切り替えられます。

このソート機能ですが、クラスによってはこれがONの状態でアイテムが編集された場合その都度ソートが実行されるようでOFFの場合と比べると実行コストの差があるようです。

そこでQListWidget,QTableWidget,QTreeWidgetの3つのクラスに連続にアイテムを追加していった場合のソートON/OFFによる影響を計測してみました。

以下がそのコードとその出力です。

#include <QApplication>
#include <QListWidget>
#include <QTableWidget>
#include <QTreeWidget>
#include <QDebug>
#include <QTime>
#include <QStringList>
#include <QVector>

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);

  // アイテム作成用の文字列のリストを作成
  // アイテムは "0000", "0001", "0002", ....... "9999" までの10000個
  const int N = 10000;
  QVector<QString> item_strings;
  item_strings.reserve( N );
  for( int i = 0; i < N; ++i )
  {
    item_strings.push_back( QString::number( i ).rightJustified( 4, '0' ) );
  }


  { // QListWidget
    QListWidget *list_widget = new QListWidget();
    {
      QTime t;
      t.start();
      foreach( const QString &item_string, item_strings )
      {
        list_widget->addItem( item_string );
      }
      qDebug() << "QListWidget sorting OFF :" << t.elapsed() << "ms";
    }
    // clear & sorting ON
    list_widget->clear();
    list_widget->setSortingEnabled( true );
    {
      QTime t;
      t.start();
      foreach( const QString &item_string, item_strings )
      {
        list_widget->addItem( item_string );
      }
      qDebug() << "QListWidget sorting ON  :" << t.elapsed() << "ms";
    }
  }

  { // QTableWidget
    QTableWidget *table_widget = new QTableWidget();
    table_widget->setColumnCount( 1 );
    table_widget->setRowCount( N );
    {
      QTime t;
      t.start();
      for( int i = 0; i < N; ++i )
      {
        table_widget->setItem( i, 0, new QTableWidgetItem( item_strings[i] ) );
      }
      qDebug() << "QTableWidget sorting OFF :" << t.elapsed() << "ms";
    }
    // clear & sorting ON
    table_widget->clear();
    table_widget->setColumnCount( 1 );
    table_widget->setRowCount( N );
    table_widget->setSortingEnabled( true );
    {
      QTime t;
      t.start();
      for( int i = 0; i < N; ++i )
      {
        table_widget->setItem( i, 0, new QTableWidgetItem( item_strings[i] ) );
      }
      qDebug() << "QTableWidget sorting ON  :" << t.elapsed() << "ms";
    }
  }

  { // QTreeWidget
    QTreeWidget *tree_widget = new QTreeWidget();
    {
      QTime t;
      t.start();
      for( int i = 0; i < N; ++i )
      {
        QTreeWidgetItem *item = new QTreeWidgetItem( QStringList() << item_strings[i] );
        tree_widget->addTopLevelItem( item );
      }
      qDebug() << "QTreeWidget sorting OFF :" << t.elapsed() << "ms";
    }
    // clear & sorting ON
    tree_widget->clear();
    tree_widget->setSortingEnabled( true );
    {
      QTime t;
      t.start();
      for( int i = 0; i < N; ++i )
      {
        QTreeWidgetItem *item = new QTreeWidgetItem( QStringList() << item_strings[i] );
        tree_widget->addTopLevelItem( item );
      }
      qDebug() << "QTreeWidget sorting ON  :" << t.elapsed() << "ms";
    }
  }
  
  return 0;
}

出力

QListWidget sorting OFF : 250 ms 
QListWidget sorting ON  : 491 ms 
QTableWidget sorting OFF : 12 ms 
QTableWidget sorting ON  : 13 ms 
QTreeWidget sorting OFF : 350 ms 
QTreeWidget sorting ON  : 352 ms 

結果としてQTableWidgetとQTreeWidgetはソートON/OFFの差はみられないようですが、QListWidgetの場合ソートON時はOFFに比べて2倍近く実行コストがかかっていることがわかります。
QListWidgetを使う場合で大量のアイテムを一気に追加する際などは一度ソート機能をOFFにしておいた方がパフォーマンスが少しあがりそうです。

ちなみに今回の検証に用いた環境はMac版のQt4.8.3です。その他の環境ではまた違った結果となる可能性がありますのでその点はご了承ください。

参考
QAbstractItemView Class Reference | Documentation | Qt Project