.tutorials/addressbook/part3/addressbook.h
.tutorials/addressbook/part3/main.cpp
.tutorials/addressbook/part3/part3.pro
Address Book 程式現在完成一半了。我們需要加入一些函式以在聯絡人之間做導覽(navigation)。不過首先,我們必須要決定:我們要使用哪種資料結構來存取這些聯絡人。
在章節 2,我們使用一個以聯絡人的姓名為鍵、以聯絡人住址為值的一對 key-value QMap。對於我們的情況,這是有效的。然而,為了要導覽並顯示每一個項目,是需要做點改良的。
我們藉由將 QMap 複製成一個類似於循環連結串列(circularly-linked list)的資料結構,其中所有的元素(element)都是被連接著的,包含了第一個元素與最後一個元素。下圖說明了這個資料結構。
Defining the AddressBook Class
為了要加入導覽函式到 Address Book 程式中,我們還需要加入兩個 slot 到我們的 AddressBook 類別中:next() 與 previous()。它們被加入到我們的 addressbook.h 檔案:
void next(); void previous();
我們也需要另外兩個 QPushButton 物件,所以我們在私有變數中宣告了 nextButton 與 previousButton:
QPushButton *nextButton; QPushButton *previousButton;
Implementing the AddressBook Class
在 addressbook.cpp 中的 AddressBook 建構子,我們實體化 nextButton 與 previousButton 並在預設情況下使他們失效。這是因為只有在在 Address Book 中的聯絡人多於一個時才能夠進行導覽。
nextButton = new QPushButton(tr("&Next")); nextButton->setEnabled(false); previousButton = new QPushButton(tr("&Previous")); previousButton->setEnabled(false);
然後,我們將這些按鈕連接到它們各自的 slot。
connect(nextButton, SIGNAL(clicked()), this, SLOT(next())); connect(previousButton, SIGNAL(clicked()), this, SLOT(previous()));
下圖是我們預期的圖形使用者介面。注意,它正在接近我們預期的最終成果。
對於 next() 與 previous() 函式,我們遵循基本的慣例,將 nextButton 放在右邊、將 previousButton 放在左邊。為了達到這個直觀的佈局,我們使用了 QHBoxLayout 來一步一步擺放元件:
QHBoxLayout *buttonLayout2 = new QHBoxLayout; buttonLayout2->addWidget(previousButton); buttonLayout2->addWidget(nextButton);
接著,QHBoxLayout 物件:buttonLayout2 被加入到 mainLayout 中。
mainLayout->addLayout(buttonLayout2, 3, 1);
下圖顯示了元件在 mainLayout 中的座標。
在我們的 addContact() 函式中,我們必須讓這些按鈕失效,所以使用者不會在加入一個聯絡人時試圖進行導覽。
nextButton->setEnabled(false); previousButton->setEnabled(false);
在我們的 submitContact() 函式,我們再讓導覽按鈕--nextButton 與 previousButton--根據聯絡人的數量生效。如同先前提到的,導覽只有在 Address Book 中的聯絡人多於一個時才是有效的。接下來的幾行程式展示了該如何做到這件事:
int number = contacts.size(); nextButton->setEnabled(number > 1); previousButton->setEnabled(number > 1);
我們也在 cancel() 函式中包含了這幾行程式。
回想到我們打算利用我們的 QMap 物件來模擬一個循環連結串列:contacts。所以,在 next() 函式中,我們為 contacts 取得一個迭代器(iterator),然後:
- 若是迭代器不在 contacts 的末端,我們將它加一
- 若是迭代器在 contacts 的末端,我們移動它到 contacts 的開頭。這給了我們 QMap 像是一個循環連結串列在運作的錯覺。
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()); }
一旦我們已經迭代到了 contacts 中正確的物件,我們在 nameLine 與 addressText 顯示它的內容。
同樣的,對於 previous() 函式,我們為 contacts 取得一個迭代器(iterator),然後:
- 若是迭代器在 contacts 的末端,我們清除顯示並返回。
- 若是迭代器在 contacts 的開頭,我們將它移動到末端。
- 然後,我們將迭代器減一。
void AddressBook::previous() { QString name = nameLine->text(); QMap<QString, QString>::iterator i = contacts.find(name); if (i == contacts.end()){ nameLine->clear(); addressText->clear(); return; } if (i == contacts.begin()) i = contacts.end(); i--; nameLine->setText(i.key()); addressText->setText(i.value()); }
再一次,我們顯示了當前 contacts 中的物件內容。
來源:Address Book 3 - Navigating between Entries
版本:4.4.3
0 回覆:
張貼留言