.tutorials/addressbook/part4/addressbook.h
.tutorials/addressbook/part4/main.cpp
.tutorials/addressbook/part4/part4.pro
在這一章,我們著眼於修改儲存在 Address Book 程式中聯絡人內容的方法。

我們現在擁有一個不只能以有系統的方式存取資料,還能夠允許導覽的 Address Book。而包含編輯和移除函式--使得聯絡人的詳細資料可以在需要時被改變--將會是方便的。然而,這需要在列舉(enum)的形式下做一點改良。在先前的章節中,我們有兩種模式(mode):AddingMode 與 NavigationMode--但是它們並不是作為列舉而被定義的。相反的,我們手動讓對應的按鈕生效或失效,結果就是多行重複的程式碼。
在這一章,我們定義了包含三種值的 Mode 列舉:
- NavigationMode,
- AddingMode, 與
- EditingMode.
Defining the AddressBook Class
addressbook.h 被更新成包含了 Mode 列舉:
enum Mode { NavigationMode, AddingMode, EditingMode };
我們也加入了兩個新的 slot--editContact() 與 removeContact()--到我們當前的公開 slot 列表。
void editContact();
void removeContact();
為了在模式間做轉換,我們引入了 updateInterface() 函式來管理所有 QPushButton 物件的生效與失效。為了先前提到的編輯和刪除函式,我們也加入了兩個新按鈕:editButton 與 removeButton。
void updateInterface(Mode mode);
...
QPushButton *editButton;
QPushButton *removeButton;
...
Mode currentMode;
最後,我們宣告了 currentMode 以追蹤當前的列舉模式。
Implementing the AddressBook Class
我們現在必須要實現 Address Book 程式的模式改變功能。editButton 與 removeButton 被實體化,並在預設情況下使其失效,因為 Address Book 啟動時並無聯絡人在記憶體中。
editButton = new QPushButton(tr("&Edit"));
editButton->setEnabled(false);
removeButton = new QPushButton(tr("&Remove"));
removeButton->setEnabled(false);
然後,這些按鈕被連接到它們各自的 slot:editContact() 與 removeContact()。且我們將這些按鈕加入到 buttonLayout1e 中。
connect(editButton, SIGNAL(clicked()), this, SLOT(editContact()));
connect(removeButton, SIGNAL(clicked()), this, SLOT(removeContact()));
...
buttonLayout1->addWidget(editButton);
buttonLayout1->addWidget(removeButton);
在模式轉換成 EditingMode 之前,editContact() 函式將聯絡人的舊資料儲存在 oldName 與 oldAddress 中。在這個模式,submitButton 與 cancelButton 都是有效的。因此,使用者可以改變聯絡人的詳細資料並點擊任一按鈕。
void AddressBook::editContact()
{
oldName = nameLine->text();
oldAddress = addressText->toPlainText();
updateInterface(EditingMode);
}
submitContact() 函式被一個 if-else 敘訴(statement)分割成兩個部分。我們檢查 currentMode 以確認它是否在 AddingMode 下。假如是,我們開始我們的加入動作。
void AddressBook::submitContact()
{
...
if (currentMode == AddingMode) {
if (!contacts.contains(name)) {
contacts.insert(name, address);
QMessageBox::information(this, tr("Add Successful"),
tr("\"%1\" has been added to your address book.").arg(name));
} else {
QMessageBox::information(this, tr("Add Unsuccessful"),
tr("Sorry, \"%1\" is already in your address book.").arg(name));
return;
}
否則,我們檢查 currentMode 以確認它是否在 EditingMode 下。假如是,我們比較 oldName 與 name。假如名字被改變了,我們從 contacts 移除舊的聯絡人,並插入更新過的新聯絡人。
} else if (currentMode == EditingMode) {
if (oldName != name) {
if (!contacts.contains(name)) {
QMessageBox::information(this, tr("Edit Successful"),
tr("\"%1\" has been edited in your address book.").arg(oldName));
contacts.remove(oldName);
contacts.insert(name, address);
} else {
QMessageBox::information(this, tr("Edit Unsuccessful"),
tr("Sorry, \"%1\" is already in your address book.").arg(name));
return;
}
} else if (oldAddress != address) {
QMessageBox::information(this, tr("Edit Successful"),
tr("\"%1\" has been edited in your address book.").arg(name));
contacts[name] = address;
}
}
updateInterface(NavigationMode);
}
只有在住址被改變(換言之,oldAddress 與 address 不相同)時,我們才更新聯絡人的住址。最後,我們將 currentMode 設為 NavigationMode。這是作為重新啟動所有失效按鈕的一個重要步驟。
為了從 Address Book 中移除一個聯絡人,我們實現了 removeContact() 函式。這個函式確認聯絡人是否在 contacts 中。
void AddressBook::removeContact()
{
QString name = nameLine->text();
QString address = addressText->toPlainText();
if (contacts.contains(name)) {
int button = QMessageBox::question(this,
tr("Confirm Remove"),
tr("Are you sure you want to remove \"%1\"?").arg(name),
QMessageBox::Yes | QMessageBox::No);
if (button == QMessageBox::Yes) {
previous();
contacts.remove(name);
QMessageBox::information(this, tr("Remove Successful"),
tr("\"%1\" has been removed from your address book.").arg(name));
}
}
updateInterface(NavigationMode);
}
假如存在,我們顯示一個 QMessageBox,以讓使用者確認(confirm)刪除動作。一旦使用者確認了,我們呼叫 previous() 以確保使用者介面顯示了另一個聯絡人,且利用 QMap 的 remove() 函式來移除聯絡人。基於禮貌,我們顯示了一個 QMessageBox 以告知使用者。這個函式中所使用的訊息視窗顯示如下:

Updating the User Interface
我們先前提到了 updateInterface() 函式作為使按鈕根據當前模式生效與失效的工具。函式根據傳入的 mode 引數更新當前模式,在確認它的值之前賦值(assign)給 currentMode。
這時,每個按鈕都根據當前模式生效或失效。其於 AddingMode 與 EditingMode 的程式碼顯示如下:
void AddressBook::updateInterface(Mode mode)
{
currentMode = mode;
switch (currentMode) {
case AddingMode:
case EditingMode:
nameLine->setReadOnly(false);
nameLine->setFocus(Qt::OtherFocusReason);
addressText->setReadOnly(false);
addButton->setEnabled(false);
editButton->setEnabled(false);
removeButton->setEnabled(false);
nextButton->setEnabled(false);
previousButton->setEnabled(false);
submitButton->show();
cancelButton->show();
break;
然而,對於 NavigationMode,我們在 QPushButton::setEnabled() 的參數中包含條件。這是為了確保在 Address Book 中至少有一個聯絡人時,能使 editButton 與 removeButton 按紐生效;只有在 Address Book 中有多於一個聯絡人時,能使 nextButton 與 previousButton 按紐生效。
case NavigationMode:
if (contacts.isEmpty()) {
nameLine->clear();
addressText->clear();
}
nameLine->setReadOnly(true);
addressText->setReadOnly(true);
addButton->setEnabled(true);
int number = contacts.size();
editButton->setEnabled(number >= 1);
removeButton->setEnabled(number >= 1);
nextButton->setEnabled(number > 1);
previousButton->setEnabled(number >1 );
submitButton->hide();
cancelButton->hide();
break;
}
}
藉由執行設置模式的任務以及在同一函式中更新使用者介面,我們避免了使用者介面的程式內部狀態發生「不同步(out of sync)」的可能性。
來源:Address Book 4 - Editing and Removing Addresses
版本:4.4.3
0 回覆:
張貼留言