.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)提供了一些類別,不過我們已經選擇使用其中兩種簡易使用的組合:QFile 與 QDataStream。
一個 QFile 物件代表一個硬碟上可被讀寫的檔案。QFile 是代表著許多不同種類裝置(device)的 QIODevice 類別的一個子類別。
一個 QDataStream 物件被使用來序列化(serialize)二元(binary)資料,所以它可以被儲存在一個 QIODevice 並在之後再度被讀取。從一個 QIODevice 中進行讀寫,與開啟--將各自的裝置作為參數--與讀取或寫入到串流(stream)是相似的。
Defining the AddressBook Class
我們宣告了兩個公開 slot:saveToFile() 與 loadFromFile(),以及兩個 QPushButton 物件:loadButton 與 saveButton。
void saveToFile(); void loadFromFile(); ... QPushButton *loadButton; QPushButton *saveButton;
Implementing the AddressBook Class
在我們的建構子,我們實體化 loadButton 與 saveButton。理論上,將按鈕的標籤設為「從一個檔案載入聯絡人(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 回覆:
張貼留言