.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 回覆:
張貼留言