QtでGUIアプリーション作成入門(3)
登録した連絡先の間をナビゲートする能力を加える。
しかし、その前にどんな種類のデータ構造が必要なのか決める必要がある。前のセクションでは QMap の鍵-値ペア、名前を鍵/住所を値、を用いた。我々の場合ではこれでいいが、各エントリーを表示しナビゲートするにはもう少し拡張する必要がある。
QMap を円環状に結合したリストを模したデータ構造にするため拡張する。下の図で示すようなイメージ。
※QtはSTLライクなイテレータとJavaライクなイテレータがある。QMap::iteratorはSTLライクだが(end()は最後の要素の一つ後の空要素である)、QMapIteratorはJavaライクなイテレータ。QMapのイテレータは、QMap::iteratorでも、直接、イテレータが指し示す要素のkeyとvalueにアクセスできる。
AddressBook クラスの定義
ナビゲーション関数を追加するために、AddressBookクラスに2つのスロット(next() と previous())を addressbook.h に加える。:
void next(); void previous();
また2つの QPushButton オブジェクトが必要なので nextButton と previousButton をプライベート変数に加える:
QPushButton *nextButton; QPushButton *previousButton;
AddressBook クラスの実装
addressbook.cppのAddressBookコンストラクタの中で、nextButton と previousButton をインスタンス化し、デフォルトでは無効にする。これはナビゲーションは複数の連絡先が登録された時だけに有効にするため。
nextButton = new QPushButton(tr("&Next")); nextButton->setEnabled(false); previousButton = new QPushButton(tr("&Previous")); previousButton->setEnabled(false);
その後、それらのpushボタンを対応するスロットに結合する。
connect(nextButton, SIGNAL(clicked()), this, SLOT(next()));
connect(previousButton, SIGNAL(clicked()), this, SLOT(previous()));
GUIのイメージは以下
基本的な慣例に従って nextButton を右 previousButton を左に配置する。この直感的なレイアウトのために QHBoxLayout を使う:
QHBoxLayout *buttonLayout2 = new QHBoxLayout;
buttonLayout2->addWidget(previousButton);
buttonLayout2->addWidget(nextButton);
この QHBoxLayout オブジェクトbuttonLayout2を、メインレイアウトの(2,1)要素に加える。
mainLayout->addLayout(buttonLayout2, 2, 1);
下の図はこのウィジェットのmainLayoutの座標を示している。
我々の addContact() 関数の中で、それらのボタンを無効にするので、連絡先を加えるときに間違えて押すこともない。
nextButton->setEnabled(false); previousButton->setEnabled(false);
また、submitContact()関数の中で、nextButton と previousButton, を有効にする、連絡先の数に応じて有効にする。これをするには以下のコードを使う。
int number = contacts.size(); nextButton->setEnabled(number > 1); previousButton->setEnabled(number > 1);
このコードは cancel() 関数でも使う。
QMap オブジェクトを環状連結リストのように使うことを意図している。なので、next()関数では連絡先のイテレータを得る必要がある、なので:
もし、イテレータが終末でないなら、一つインクリメントする
もし、イテレータが終末なら、最初の連絡先に移動させる。これで環状連結リストのように振る舞う。
void AddressBook::next() { QString name = nameLine->text(); QMap<QString, QString>::iterator i = contacts.find(name); if (i != contacts.end()) i++; if (i == contacts.end()) i = contacts.begin(); nameLine->setText(i.key()); addressText->setText(i.value()); }
正しいオブジェクトに移動できたら、その内容をnameLineとaddressTextに表示する。
同様に、previous()関数でもイレテータを得る必要がある。
もし、イレテータが最初なら、終末に移動する。
そしてイテレータを1つデクリメントする。
void AddressBook::previous() { QString name = nameLine->text(); QMap<QString, QString>::iterator i = contacts.find(name); if (i == contacts.begin()) i = contacts.end(); i--; nameLine->setText(i.key()); addressText->setText(i.value()); }
再び、現在のオブジェクトの内容を表示する。
Files:
tutorials/addressbook/part3/addressbook.cpp
tutorials/addressbook/part3/addressbook.h
tutorials/addressbook/part3/main.cpp
tutorials/addressbook/part3/part3.pro