2月 15, 2009

【翻譯】Address Book 2 - Adding Addresses

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

  建立我們 Address Book 的下一步是,允許一點點使用者的互動。



  我們將要提供一個可以讓使用者點擊以新增一個聯絡人的按鈕(push button),以及允許加入新聯絡人的按鈕。另外,還需要某種資料結構(data structure)以有組織的方式儲存這些聯絡人。


Defining the AddressBook Class

  現在,我們已經設置好了標籤和輸入區塊,我們加入按鈕以完成新增一個聯絡人的處理。這代表我們的 addressbook.h 檔案現在擁有三個 QPushButton 物件宣告,與三個對應的公開(public) slot。

 public slots:
     void addContact();
     void submitContact();
     void cancel();

  一個 slot 是一個回應一個特定 signal 的函式。我們將會在實現 AddressBook 類別時更詳細的討論這個概念。然而,你可以參照 Signals and Slots 文件,以獲得一份 Qt signal 與 slot 概念的簡介。

  三個 QPushButton 物件:addButtonsubmitButtoncancelButton,現在與前一章的 nameLineaddressText 一同被包含在我們的私有變數宣告中。

 private:
     QPushButton *addButton;
     QPushButton *submitButton;
     QPushButton *cancelButton;
     QLineEdit *nameLine;
     QTextEdit *addressText;

  我們需要一個容器以儲存我們的 Address Book 聯絡人,讓我們能夠遍歷(traverse)並顯示它們。一個 QMap 物件:contacts 用以掌握一對 key-value 來達成這個目的:聯絡人的姓名為鍵(key),而聯絡人住址為值(value)。

     QMap<QString, QString> contacts;
     QString oldName;
     QString oldAddress;
 };

  我們也宣告了兩個私有的 QString 物件:oldNameoldAddress。在使用者點擊 "Add" 之前,需要這些物件保留最後顯示的聯絡人的姓名與地址。所以,當使用者點擊 "Cancel",我們可以回復顯示最後的聯絡人詳細資料。


Implementing the AddressBook Class

  在 AddressBook 的建構子中,我們將 nameLineaddressText 設為唯讀(read-only),所以我們只能顯示它,而不能編輯已存在的聯絡人詳細資料。

     ...
     nameLine->setReadOnly(true);
     ...
     addressText->setReadOnly(true);

  現在,我們實體化我們的按鈕:addButtonsubmitButton、與 cancelButton

     addButton = new QPushButton(tr("&Add"));
     addButton->show();
     submitButton = new QPushButton(tr("&Submit"));
     submitButton->hide();
     cancelButton = new QPushButton(tr("&Cancel"));
     cancelButton->hide();

  當 submitButtoncancelButton 藉由呼叫 hide() 被隱藏時,addButton 藉由呼叫 show() 函式而被顯示。這兩個按鈕只有在使用者按下 "Add" 時才會被顯示,且這是由下方敘述的 addContact() 函式處理的。

     connect(addButton, SIGNAL(clicked()), this, SLOT(addContact()));
     connect(submitButton, SIGNAL(clicked()), this, SLOT(submitContact()));
     connect(cancelButton, SIGNAL(clicked()), this, SLOT(cancel()));

  我們連結(connect)按紐的 clicked() signal 到它們各自的 slot。下圖說明了這件事。



  接下來,我們使用 QVBoxLayout 垂直對齊我們的按鈕,恰好排列到我們 Address Book 元件的右邊。

     QVBoxLayout *buttonLayout1 = new QVBoxLayout;
     buttonLayout1->addWidget(addButton, Qt::AlignTop);
     buttonLayout1->addWidget(submitButton);
     buttonLayout1->addWidget(cancelButton);
     buttonLayout1->addStretch();

  addStretch() 函式用以確保按鈕不會均分空間,而是緊密的排列在元件上方。下圖顯示了使用了 addStretch() 與不使用它的不同。



  我們現在使用 addLayout()buttonLayout1 加入到 mainLayout 中。這使得我們嵌套(nested)佈局,buttonLayout1 現在就像是 mainLayout 的一個子佈局。

     QGridLayout *mainLayout = new QGridLayout;
     mainLayout->addWidget(nameLabel, 0, 0);
     mainLayout->addWidget(nameLine, 0, 1);
     mainLayout->addWidget(addressLabel, 1, 0, Qt::AlignTop);
     mainLayout->addWidget(addressText, 1, 1);
     mainLayout->addLayout(buttonLayout1, 1, 2);

  我們的佈局座標現在看起來像這樣:



  在 addContact() 函式中,我們儲存最後的聯絡人詳細資料在 oldNameoldAddress 中。現在我們清除這些輸入區塊,並關閉唯讀模式。我們將焦點(focus)設在 nameLine 上,並顯示了 submitButtoncancelButton

 void AddressBook::addContact()
 {
     oldName = nameLine->text();
     oldAddress = addressText->toPlainText();

     nameLine->clear();
     addressText->clear();

     nameLine->setReadOnly(false);
     nameLine->setFocus(Qt::OtherFocusReason);
     addressText->setReadOnly(false);

     addButton->setEnabled(false);
     submitButton->show();
     cancelButton->show();
 }

  submitContact() 函式可以被分成三個部份:

  1. 我們設法從 nameLineaddressText 得到聯絡人的詳細資料,並儲存他們在 QString 物件中。我們也要確保使用者在輸入區塊空白時無法點擊 "Submit";此外,一個 QMessageBox 會被顯示,以提醒使用者輸入姓名與住址。

     void AddressBook::submitContact()
     {
         QString name = nameLine->text();
         QString address = addressText->toPlainText();
    
         if (name == "" || address == "") {
             QMessageBox::information(this, tr("Empty Field"),
                 tr("Please enter a name and address."));
             return;
         }
    

  2. 然後,我們開始確認聯絡人是否已經存在。假如不存在,我們加入聯絡人到 contacts 中,並顯示一個 QMessageBox 告知使用者:聯絡人已被加入。

         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;
         }
    

      假如聯絡人已存在,我們同樣顯示一個 QMessageBox 以告知使用者,預防使用者加入了重複的聯絡人。我們的 contacts 物件以一對姓名與住址的 key-value 為基礎。因此,我們要確保是唯一的。

  3. 一旦我們處理完上述兩種情況,我們用接下來的程式碼來將按鈕恢復成它們的標準狀態:

         if (contacts.isEmpty()) {
             nameLine->clear();
             addressText->clear();
         }
    
         nameLine->setReadOnly(true);
         addressText->setReadOnly(true);
         addButton->setEnabled(true);
         submitButton->hide();
         cancelButton->hide();
     }
    

  下方的螢幕截圖顯示了我們用以顯示給使用者的訊息的 QMessageBox 物件。



  cancel() 函式恢復了最後顯示的聯絡人詳細資料、啟用 addButton,並隱藏了 submitButtoncancelButton

 void AddressBook::cancel()
 {
     nameLine->setText(oldName);
     nameLine->setReadOnly(true);

     addressText->setText(oldAddress);
     addressText->setReadOnly(true);

     addButton->setEnabled(true);
     submitButton->hide();
     cancelButton->hide();
 }

  加入一個聯絡人的普遍構想,給了使用者在任何時間點擊 "Submit" 或是 "Cancel" 的彈性。下方的流程圖進一步的說明了這個概念:




來源:Address Book 2 - Adding Addresses
版本:4.4.3

0 回覆:

張貼留言