2月 18, 2009

【翻譯】Address Book 4 - Editing and Removing Addresses

@
tutorials/addressbook/part4/addressbook.cpp
tutorials/addressbook/part4/addressbook.h
tutorials/addressbook/part4/main.cpp
tutorials/addressbook/part4/part4.pro

  在這一章,我們著眼於修改儲存在 Address Book 程式中聯絡人內容的方法。



  我們現在擁有一個不只能以有系統的方式存取資料,還能夠允許導覽的 Address Book。而包含編輯和移除函式--使得聯絡人的詳細資料可以在需要時被改變--將會是方便的。然而,這需要在列舉(enum)的形式下做一點改良。在先前的章節中,我們有兩種模式(mode):AddingModeNavigationMode--但是它們並不是作為列舉而被定義的。相反的,我們手動讓對應的按鈕生效或失效,結果就是多行重複的程式碼。

  在這一章,我們定義了包含三種值的 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 物件的生效與失效。為了先前提到的編輯和刪除函式,我們也加入了兩個新按鈕:editButtonremoveButton

     void updateInterface(Mode mode);
     ...
     QPushButton *editButton;
     QPushButton *removeButton;
     ...
     Mode currentMode;

  最後,我們宣告了 currentMode 以追蹤當前的列舉模式。


Implementing the AddressBook Class

  我們現在必須要實現 Address Book 程式的模式改變功能。editButtonremoveButton 被實體化,並在預設情況下使其失效,因為 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() 函式將聯絡人的舊資料儲存在 oldNameoldAddress 中。在這個模式,submitButtoncancelButton 都是有效的。因此,使用者可以改變聯絡人的詳細資料並點擊任一按鈕。

 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 下。假如是,我們比較 oldNamename。假如名字被改變了,我們從 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);
 }

  只有在住址被改變(換言之,oldAddressaddress 不相同)時,我們才更新聯絡人的住址。最後,我們將 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

  這時,每個按鈕都根據當前模式生效或失效。其於 AddingModeEditingMode 的程式碼顯示如下:

 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 中至少有一個聯絡人時,能使 editButtonremoveButton 按紐生效;只有在 Address Book 中有多於一個聯絡人時,能使 nextButtonpreviousButton 按紐生效。

     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 回覆:

張貼留言