.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 物件:addButton、submitButton 與 cancelButton,現在與前一章的 nameLine 與 addressText 一同被包含在我們的私有變數宣告中。
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 物件:oldName 與 oldAddress。在使用者點擊 "Add" 之前,需要這些物件保留最後顯示的聯絡人的姓名與地址。所以,當使用者點擊 "Cancel",我們可以回復顯示最後的聯絡人詳細資料。
Implementing the AddressBook Class
在 AddressBook 的建構子中,我們將 nameLine 與 addressText 設為唯讀(read-only),所以我們只能顯示它,而不能編輯已存在的聯絡人詳細資料。
... nameLine->setReadOnly(true); ... addressText->setReadOnly(true);
現在,我們實體化我們的按鈕:addButton、submitButton、與 cancelButton。
addButton = new QPushButton(tr("&Add")); addButton->show(); submitButton = new QPushButton(tr("&Submit")); submitButton->hide(); cancelButton = new QPushButton(tr("&Cancel")); cancelButton->hide();
當 submitButton 與 cancelButton 藉由呼叫 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() 函式中,我們儲存最後的聯絡人詳細資料在 oldName 與 oldAddress 中。現在我們清除這些輸入區塊,並關閉唯讀模式。我們將焦點(focus)設在 nameLine 上,並顯示了 submitButton 與 cancelButton。
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() 函式可以被分成三個部份:
- 我們設法從 nameLine 與 addressText 得到聯絡人的詳細資料,並儲存他們在 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; }
- 然後,我們開始確認聯絡人是否已經存在。假如不存在,我們加入聯絡人到 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 為基礎。因此,我們要確保鍵是唯一的。
- 一旦我們處理完上述兩種情況,我們用接下來的程式碼來將按鈕恢復成它們的標準狀態:
if (contacts.isEmpty()) { nameLine->clear(); addressText->clear(); } nameLine->setReadOnly(true); addressText->setReadOnly(true); addButton->setEnabled(true); submitButton->hide(); cancelButton->hide(); }
下方的螢幕截圖顯示了我們用以顯示給使用者的訊息的 QMessageBox 物件。
cancel() 函式恢復了最後顯示的聯絡人詳細資料、啟用 addButton,並隱藏了 submitButton 與 cancelButton。
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 回覆:
張貼留言