2012/01/22

[qt]QListWidgetへのアイテム追加

Qtでリスト形式の表示をさせたい場合、DesignerのUI一覧を見ると「Item Views(Model-Based)」と「Item Widgets(Item-Based)」の2つがある。

そう書くと混乱しそうだが、それぞれ別のclassなので大丈夫だ。

  • Item Views(Model-Based)・・・List View・・・QListView
  • Item Widgets(Item-Based)・・・List Widget・・・QListWidget

Qt本の「10章 アイテムビュークラス」によると、少量のデータを表示させるようなよくある場合には「QListWidget」を使い、大量のデータを使うなど工夫がいるような場合はデータモデルと「QListView」を組み合わせてMVCをやんなさい、ということらしい。

QListWidgetのヘッダファイルを見るとわかるが、QListViewを継承している。
今回は、このQListWidgetにアイテムを追加してみよう。


QListWidgetクラスに対してQListWidgetItemクラスがあり、表示されるのは追加されたQListWidgetItemになるそうだ。

追加しそうなメンバ関数の名前は、こんなのだ。

  • addItem()
  • addItems()
  • insertItem()
  • insertItems()
  • setCurrentItem()
  • setItemWidget()

addItem系は、末尾に追加。
insertItem系は、指定した行に追加。
setCurrentItem()は、現在のQListWidgetItemの差し替え。
setItemWidget()は・・・よくわからん。指定されたアイテムに表示させたいウィジェットを設定する?とかなんとか。

 

アプリを起動したときに、既にリストに文字列が入っているような場合は、addItem()とかaddItems()でいいんじゃなかろうかね。
文字列だけなら、QListWidgetItemインスタンスを作らずとも、QStringを指定できて楽そうだ。


では、addItems()でやってみよう。
これは引数として、const QStringList&を渡すことになっている。

QStringListを初期値入りで作るなら、コンストラクタでやってしまえるようだ。
複数データを設定する場合は、

  • QStringList(const QList<QString>&)
  • QStringList(std::initializer_list<QString>)

この2つがある。

QListを初期値入りで作るなら、

  • QList(std::initializer_list<T>)

std::initializer_listってのがあるらしい。
昔はなかったような気がするが、時代に乗り遅れたのか・・・。

初期値入りにこだわったのは、ちょっとしたツールくらいだったら文字列固定で済むことが多いからだ。
どっかのリソースから引っ張ってこないといかんのなら、QStringListに<<していってもいいだろう。
CSVみたいにセパレータが決まっているなら、1行をQStringで読み込み、split(",")などとするとコンマ区切りでアイテムを追加してくれるみたいだ。


ここを読み、C++11対応。
initializer_listはC++11なのだ。だから知らんのだ。
http://labs.qt.nokia.co.jp/2011/06/09/cpp0x-in-qt.html

proファイルに、以下を追加。

QMAKE_CXXFLAGS += -std=c++0x

・・・ビルドエラーになった。
::swprintfと::vswprintfがわからんとおっしゃる。

stdio.hをインクルードする前に、undefすることで対策できるらしい。
http://stackoverflow.com/questions/3445312/swprintf-and-vswprintf-not-declared

確かに、通った。
通ったけど、納得いかん。
全ファイルにundefなんか、わざわざ書きたくないぞ。

makeのオプションに-Uってのがあるので、それでよいのか。
http://stackoverflow.com/questions/6699734/qt-creator-compilation-error-swprintf-and-vswprintf-has-not-been-declared

 

mingwの問題だとは思うが、直った方がうれしいですな。


std::initializer_list<T>は、そんなに難しくないみたいだ。

#include <initializer_list>
 
std::initializer_list<QString> ilist = {
    "str1", "str2", "str3", ...
};
ui->listWidget->addItems(ilist);

 

QStringListインスタンスを作らずとも、std::initializer_listから直接いけた。
うーむ。

これはおそらく、『プログラミング言語C++ 第3版』の「11.3.3 初期設定」と「11.4.1 曖昧さ」から読み取れるんじゃなかろうかと思う。

「11.3.3 初期設定」には、こうある。

単一の引数を取るコンストラクタは、その引数の方からコンストラクタの型への変換方法を規定する。

QStringListにはstd::initializer_list<T>を1つだけ引数に取るコンストラクタがある。
だから、これはコンストラクタであると同時に変換方法でもあるのだ。
また、こうもある。

つまり、引数を1つ取るコンストラクタは、明示的に呼び出されるとは限らない。

本には例が載っているのだが、そこら辺は読んでおくれ。
明示的なだけでなく、暗黙で呼び出されることもあるという話だ。
まあ、わざわざ

char c = (char)0;

みたいなのはめんどくさいよな。

「11.4.1 曖昧さ」には、ルールとしてこうある。

文法上認められているユーザー定義の暗黙の変換は、1レベルだけである。

なので、たどりたどってわけがわからないコンストラクタが呼び出されることはなく、型変換が発生する可能性があるコンストラクタだけ探してみればよいことになる。


心配性なので、デバッガで確認した。
うん、addItems()のときにQStringList(std::initializer_list<QString>)が呼び出されている。
確認できて、安心した。

 

QStringListにはコンストラクタが追加されたので、わざわざinitializer_listを使わずともよさそうだ。

QStringList str = {
    "str1", "str2", "str3", ...
};
ui->listWidget->addItems(str);

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。