2月 24, 2009

【翻譯】Address Book 6 - Loading and Saving

@
tutorials/addressbook/part6/addressbook.cpp
tutorials/addressbook/part6/addressbook.h
tutorials/addressbook/part6/finddialog.cpp
tutorials/addressbook/part6/finddialog.h
tutorials/addressbook/part6/main.cpp
tutorials/addressbook/part6/part6.pro

  這一章涵蓋了 Qt 的檔案處理功能,我們可以使用它來撰寫 Address Book 程式載入與儲存的例行程序。



  雖然導覽與搜尋聯絡人都是有用的功能,但是我們的 Address Book 在我們能儲存現存的聯絡人,並能在之後再度載入它們之前,都還不完全算是真的可以使用。Qt 為輸入(input)與輸出(output)提供了一些類別,不過我們已經選擇使用其中兩種簡易使用的組合:QFileQDataStream

  一個 QFile 物件代表一個硬碟上可被讀寫的檔案。QFile 是代表著許多不同種類裝置(device)的 QIODevice 類別的一個子類別。

  一個 QDataStream 物件被使用來序列化(serialize)二元(binary)資料,所以它可以被儲存在一個 QIODevice 並在之後再度被讀取。從一個 QIODevice 中進行讀寫,與開啟--將各自的裝置作為參數--與讀取或寫入到串流(stream)是相似的。


Defining the AddressBook Class

  我們宣告了兩個公開 slot:saveToFile()loadFromFile(),以及兩個 QPushButton 物件:loadButtonsaveButton

     void saveToFile();
     void loadFromFile();
     ...
     QPushButton *loadButton;
     QPushButton *saveButton;


Implementing the AddressBook Class

  在我們的建構子,我們實體化 loadButtonsaveButton。理論上,將按鈕的標籤設為「從一個檔案載入聯絡人(Load contacts from a file)」與「儲存聯絡人到一個檔案(Save contacts to a file)」將會更加友善於使用者的。然而,由於我們其他按鈕的大小,我們將標籤設為 Load...Save...。幸運地,Qt 提供一個簡單的方式來利用 setToolTip() 設定工具提示(tooltip),我們為我們的按鈕用接下來的方式來使用它:

     loadButton->setToolTip(tr("Load contacts from a file"));
     ...
     saveButton->setToolTip(tr("Save contacts to a file"));

  雖然並不會顯示在這裡,不過如同其餘我們實現的功能,我們將按鈕加入到右邊的佈局控制板--button1Layout--並連接按鈕的 clicked() signal 到它們各自的 slot。

  對於儲存功能,我們首先使用 QFileDialog::getSaveFileName() 取得 fileName。這是一個由 QFileDialog 提供的方便函式。QFileDialog 彈出一個典型的檔案對話視窗,並允許使用者輸入一個檔案名稱或是選擇任何存在的 .abk 檔。.abk 檔是我們的 Address Book 在我們儲存聯絡人時所建立的擴展(extension)。

 void AddressBook::saveToFile()
 {
     QString fileName = QFileDialog::getSaveFileName(this,
         tr("Save Address Book"), "",
         tr("Address Book (*.abk);;All Files (*)"));

  彈出的檔案對話視窗顯示於下方截圖:



  假如 fileName 不為空,我們利用 fileName 建立一個 QFile 物件:file。QFile 與 QDataStream 的運作,如同 QFile 是一個 QIODevice。

  接下來,我們試圖在 WriteOnly 模式下開啟檔案。假如開啟不成功,我們顯示一個 QMessageBox 以告知使用者。

     if (fileName.isEmpty())
         return;
     else {
         QFile file(fileName);
         if (!file.open(QIODevice::WriteOnly)) {
             QMessageBox::information(this, tr("Unable to open file"),
                 file.errorString());
             return;
         }

  否則,我們實體化一個 QDataStream 物件:out。QDataStream 需要與用來讀寫的串流版本相同。在序列化資料到檔案前,我們藉由設定使用的版本為採用的 Qt 4.3 版本,以確保這種情況。

         QDataStream out(&file);
         out.setVersion(QDataStream::Qt_4_3);
         out << contacts;
     }
 }

  對於讀取功能,我們也使用 QFileDialog::getOpenFileName() 來 取得 fileName。這個與 QFileDialog::getSaveFileName() 極為相像的函式,也彈出一個典型的對話視窗,並允許使用者輸入一個檔案名稱,或是選擇任何存在的 .abk 檔以讀取到 Address Book 中。

 void AddressBook::loadFromFile()
 {
     QString fileName = QFileDialog::getOpenFileName(this,
         tr("Open Address Book"), "",
         tr("Address Book (*.abk);;All Files (*)"));

  舉例來說,在 Windows 上,這個函式彈出一個原生檔案對話視窗,如同接下來顯示的截圖:



  再一次,假如 fileName 不為空,我們使用一個 QFile 物件--file--並試圖以。 ReadOnly 模式下開啟檔案。與我們在 saveToFile() 中實現相同的方式,假如開啟不成功,我們顯示一個 QMessageBox 以告知使用者。

     if (fileName.isEmpty())
         return;
     else {

         QFile file(fileName);

         if (!file.open(QIODevice::ReadOnly)) {
             QMessageBox::information(this, tr("Unable to open file"),
                 file.errorString());
             return;
         }

         QDataStream in(&file);
         in.setVersion(QDataStream::Qt_4_3);
         contacts.empty();   // empty existing contacts
         in >> contacts;

  否則,我們實體化一個 QDataStream 物件:in,將它的版本如前述設定,並讀取序列化的資料到 contacts 資料結構中。 注意,我們在讀入資料到 contacts 以簡化檔案讀取程序之前,先清空 contacts。一個更進階的方法為讀取聯絡人到暫時的 QMap 物件中,並且只有在聯絡人並非已存在於 contacts 時複製它。

         if (contacts.isEmpty()) {
             QMessageBox::information(this, tr("No contacts in file"),
                 tr("The file you are attempting to open contains no contacts."));
         } else {
             QMap<QString, QString>::iterator i = contacts.begin();
             nameLine->setText(i.key());
             addressText->setText(i.value());
         }
     }

     updateInterface(NavigationMode);
 }

  為了顯示已經從檔案讀取到的聯絡人,首先我們必須驗證(validate)獲取的資料,以確保我們讀取的檔案真的包含 Address Book 聯絡人。假如是,我們顯示第一個聯絡人;否則,我們顯示一個 QMessageBox 以告知使用者這個問題。之後,我們會更新介面來以此生效或失效按鈕。


來源:Address Book 6 - Loading and Saving
版本:4.4.3

0 回覆:

張貼留言