0
点赞
收藏
分享

微信扫一扫

QT(5)Dialog - Addressbook例子3


  我们丰富Addressbook的例子,增加一个Find按键,可弹出一个dialog,参考:http://doc.qt.nokia.com/latest/tutorials-addressbook-part5.html ,http://doc.qt.nokia.com/latest/tutorials-addressbook-part6.html和http://doc.qt.nokia.com/latest/tutorials-addressbook-part7.html,学习下面的内容:

  1. QDialog的使用方法。
  2. QFileDialog的使用方法
  3. 二进制和文本的文件读写
  4. split,QRegExp,QStringList等相关String的使用方法

  为此,我们增加FindDialg的类,继承QDialog。下图是主Window的界面,以及FindDialog的弹出界面。

  我们增加一个头文件finddialog.h和源文件finddialog.cpp来处理弹框。请注意在*.pro文件中加入相关的文件,通过qmake重新生成Makefile。finddialog.h如下:

QT(5)Dialog - Addressbook例子3_string

按Find按钮后弹框:

#ifndef WEI_FINDDIALOG_H
 #define WEI_FINDDIALOG_H

#include <QDialog>

 class QLineEdit;
 class QPushButton;

class FindDialog : public QDialog
 {
     Q_OBJECT

 public :
     FindDialog(QWidget * parent = NULL);
     QString getFindText();

 public slots:
     void findClicked();

 private:
     QPushButton * findButton;
     QLineEdit   * lineEdit;
     QString       findText;
 };

 #endif

  我们看看finddialog.cpp文件:

#include <QtGui>
 #include "finddialog.h"

FindDialog::FindDialog(QWidget *parent): QDialog(parent)
 {
     QLabel * findLabel = new QLabel(tr("Enter contact's name: "));
     lineEdit = new QLineEdit;
     findButton = new QPushButton(tr("&Find"));
     findText = "";

     QHBoxLayout * layout = new QHBoxLayout;
     layout->addWidget(findLabel);
     layout->addWidget(lineEdit);
     layout->addWidget(findButton);

     setLayout(layout);
     setWindowTitle(tr("Find Contact"));    /* 我们在这里作两个test case。方式一:将findButton的clicked()信号连接两个slot函数,先是findClicked()然后是accept()。accept()是QDialog的一个函数,当QDialog hide的时候给出dialog的返回数值QDialog::Accepted。当我们处理了findClicked后,则依次调用accept(),这是dialog将会hide(注意在QT中不是关闭),并且返回一个resultcode:Accepted。这个处理关系如图所示 */ 
     connect(findButton, SIGNAL(clicked()), this, SLOT(findClicked()));
     connect(findButton, SIGNAL(clicked()), this, SLOT(accept())); //在Test case 2中我们注释此行。
 }

 void FindDialog::findClicked()
 {
     QString text = lineEdit->text();
     if(text.isEmpty()){
         QMessageBox::information(this,tr("Empty Field"), tr("Please enter a name."));
         return; //在这个例子,如果是空的,执行完此,return后,调用accept,窗口会自行关闭
    }else{
         findText = text;
         lineEdit -> clear();
         //accept(); // Test Case2:由于处理findClicked后,没有下一步的accept,通过test2 我们可以比较了解信号依次出发的情况。
     }
 }
/*在这里,我们注意到,宁可增加一个public来读取属性, 也不将该属性设置为public,即使目前只提供读的功能,这是一种好的编写风*/
 QString FindDialog :: getFindText()
 {
    return findText;
 }

  现在补充addressbook.h,如下:

... ...
 #include "finddialog.h"
 ... ...
 class AddressBook : public QWidget
 {
     ... ...
 public slots:
     ... ...
     void findContact();

 private:
 ... ...
     FindDialog * dialog;
     QPushButton * findButton;
 };
 ... ...

  补充addressbook.cpp,如下:

... ...
 AddressBook :: AddressBook(QWidget * parent) : QWidget(parent)
 {
... ...
     findButton = new QPushButton(tr("&Find"));
     findButton->setEnabled(false);
     dialog = new FindDialog();
 ... ...
     buttonLayout1->addWidget(findButton);
 ... ...
     connect(findButton, SIGNAL(clicked()),this,SLOT(findContact()));
 }

 void AddressBook::updateUI(Mode mode){
... ...
     case NavigationMode:
 ... ...
         findButton -> setEnabled(!contacts.isEmpty());
 ... ...    
 }

 void AddressBook::findContact()
 {
    dialog->show();
    if(dialog->exec() == QDialog::Accepted){
        QString contactName = dialog->getFindText();
        if(contacts.contains(contactName)){
            nameLine->setText(contactName);
            addressText->setText(contacts.value(contactName));
        }else{
            QMessageBox::information(this,tr("Not Found"), tr("Sorry, %1 is not found").arg(contactName));
        }
    }
 }

二进行的文件读写

  我们进一步完善,增加两个button,saveButton和loadButton,将click()信号connect置saveToFile()和loadFromFile(),相关的updateUI修改方式就不在重复,对于一个button,我们还可以采用setToolTip鼠标放在上面,出现提示方式。

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

  我们重点看看save和load,对应写文件和读文件。文件采用QFile,QFile是QIODevice的subclass。通过QFile来open一个文件,如果文件不存在,则创建这个文件。使用 QDataStream来从QIODevice中二进制读写数据。下面是写的例子:


//对于文件类型,假设Address Book类型有两种*.a和*.b,方式为Address Book(*.a *.b),如果多个文件类型,之间使用“;;”来分割
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Address Book"),"",  tr("Address Book(*.abk);;All Files (*)"));
if(fileName.isEmpty())
     return;
QFile file(fileName);
 if(file.open(QIODevice::ReadOnly)){
     QDataStream in(&file);
     contacts.empty();
    in >> contacts; //将in的内容导入contacts。}
 }  下面是读的例子:

    QString fileName = QFileDialog::getSaveFileName(this, tr("Save Address Book"),"", tr("Address Book(*.abk);;All Files (*)"));
    if(fileName.isEmpty())
         return;
     QFile file(fileName);
     if(!file.open(QIODevice::WriteOnly)){ 
         QMessageBox::information(this,tr("Unable to open file!"), file.errorString());
         return;
     }
     QDataStream out(&file);
     out << contacts;
     file.close();

  在Tutorial的例子中我们发现没有加入close(),close是调用flush后close文件,必须加入的,否则容易出问题。

文本读写方式和String的一些高级用法

  上面是二进制的读写,有时我们需要采用文本text的方式,我们在上面的例子中增加到处vCard格式,并将其保存。我们需要将名字name中区分firstName,llastName。相当于获取一个字符串用空格分隔的第一个字符串和最后一个字符串。

// 其中nameList是QStringList,相当于一个String数组来保存,用split来分开,第二个参数表示如果分割后,entry为空,忽略,例如我们使用;分割,如果有;;,则有一个空的entry,将这个忽略。用户的输入,可能中间隔一个空格,也可能隔两个空格,无论多少个空格我们都作为一个分割符号来处理。这里我们使用了QRegExp来处理。/s表示空格,+表示可以多个。
 nameList = name.split(QRegExp("//s+"),QString::SkipEmptyParts); 
 firstName = nameList.first();  lastName = nameList.last();

  对于文本文件的写,获得有效的QFile file后,如下操作:

   

QTextStream out(&file);
     out << "BEGIN:VCARD" << "/n";
     out << "VERSION:2.1" << "/n";
     out << "N:" << lastName <<";" <<firstName <<  "/n"; ... ... //根据vCard格式加入,此处略去
     file.close();

  对于close,在我们的实验中,似乎二进制的方式,如果忘记了问题还表示很大,但是文本方式就很有问题。我们编写了一个采用文本方式读文件的函数,如果在write后面(没有close)马上调用之前读函数,读出来为空,如果在write最后有close,则正常。所有我们应该在open之后,加入close。


举报

相关推荐

0 条评论