QT(4)信号、SLOT和QMap - Addressbook例子2

    技术2022-07-05  150

      在之前的MeeGo开发者(五):QT(3)对象和继承小例子基础上,我们增加三个button,参考http://doc.qt.nokia.com/latest/tutorials-addressbook-part2.html 、http://doc.qt.nokia.com/latest/tutorials-addressbook-part3.htmlhttp://doc.qt.nokia.com/latest/tutorials-addressbook-part4.html,学习下面三个内容:

    这三个button放置在layout上,然后摆放在GuidLayout。当按这些button的时候,释放signal,这些信号将触发某些slot的函数。这是本次学习的重点。 学习QMap的使用方法。

      最后的UI如图所示。我们在GuidLayou的(1,2)上摆放一个layout,layout上有三个button,按Add这进入增加新的联系人,按submit表示确定增加该联系人,按Cancel表示取消增加该联系人。在图的右边我们还看到一种三个button的摆放方式,我们会在程序中进行说明。

      用户的信息存放在QMap中,QMap适合存放带索引的数据,在这个例子中,以name为索引,address为该人名对应的信息。QMap是不使用外置数据库的情况下存储数据库的很好的方式。

      当button click后,释放一个signal,我们需要将这个signal和某个函数,在QT上称为slot函数。 在这个例子中,我们需要建立三个对应关心,如图所示。方式为:connect(addButton/*发出信号的对象*/, SIGNAL(clicked())/*捕抓的信号*/, this,SLOT(addContact())/*监测到信号后触发的slot函数*/);

      main.cpp无需修改,addressbook.h如下所示:

    #ifndef COM_WEI_ADDRESSBOOK_H #define COM_WEI_ADDRESSBOOK_H

    #include <QWidget> #include <QMap>

    class QLineEdit; class QLabel; class QTextEdit; class QPushButton;

    class AddressBook : public QWidget {     Q_OBJECT

    public:     AddressBook(QWidget * parent = NULL);

    /* A slot is a function that responds to a particular signal.  */ public slots:     void addContact();     void submitContact();     void cancel();

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

        /* contacts用于存储联系人信息,是QMap对象,是存储key-value:这里联系人名字作为key,联系人地址作为value. */     QMap contacts;     QString oldName,oldAddress; };

    #endif

    addressbook.cpp如下所示

    /* addressbook.cpp - the implementation file for the AddressBook class */

    #include <QtGuid> #include "addressbook.h"

    AddressBook :: AddressBook(QWidget * parent) : QWidget(parent) {     QLabel * nameLabel = new QLabel(tr("Name:"));     nameLine = new QLineEdit();     nameLine->setReadOnly(true); // not editable

        QLabel * addressLabel = new QLabel(tr("Address:"));     addressText = new QTextEdit();     addressText->setReadOnly(true);

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

        QVBoxLayout * buttonLayout1 = new QVBoxLayout;     buttonLayout1->addWidget(addButton,Qt::AlignTop);     buttonLayout1->addWidget(submitButton);     buttonLayout1->addWidget(cancelButton);     buttonLayout1->addStretch(); //紧凑排列,否则按三等分布局,即上面UI图中的右图。

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

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

        setLayout(mainLayout);     setWindowTitle(tr("Simple Address Book")); }

    void AddressBook::addContact() {     printf("Line %d: %s/n",__LINE__,__FUNCTION__);     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(); }

    void AddressBook::submitContact() {     printf("Line %d: %s/n",__LINE__,__FUNCTION__);     QString name = nameLine->text();     QString address = addressText->toPlainText();     if(name.isEmpty() || address.isEmpty()){         QMessageBox::information(this,tr("Empty Field"), tr("Please enter a name and address"));         return;     }

        if(contacts.contains(name)){         QMessageBox::information(this,tr("Add Unsuccessful!"), tr("Sorry,/"%1/" is already in your address book").arg(name));         return;     }

        contacts.insert(name, address); //QMap的用法     QMessageBox::information(this, tr("Add Successful!"),      tr("<%1,%2> has been added to your address book.").arg(name,address)); //%1,%2表示arg中的参数顺序,图见下       nameLine -> setReadOnly(true);     addressText -> setReadOnly(true);     addButton -> setEnabled(true);     submitButton->hide();     cancelButton->hide(); }

    void AddressBook::cancel() {     printf("Line %d: %s/n",__LINE__,__FUNCTION__);     nameLine->setText(oldName);     nameLine->setReadOnly(true);     addressText->setText(oldAddress);     addressText->setReadOnly(true);

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

      QMessageBox的截图如下

      我们在这个基础上做进一步处理。我们增加一个两个button,用于向前查看或者向后查看,再次实践布局,并且学习一个QMap这个存储。QMap是的entry是<key,value>,key的排列具体是否安hash值不清楚,但是在试验中,我们可以看到如果我们一次读取QMap的元素,将是按顺序(字母大小顺序)进行读出。begin是第一个元素,但是end不是最后一个元素,end可能是NULL,因此end-1才是最后一个有效元素。QMap的元素iterator是可以简单进行++和--操作的。

      数据的基础操作是增/删/改/查,我们增加删/改两个功能,其中submit和cancel按键通用,在不同的功能要求下各组建的editabled/disenditabled,enabled/disenable,show/hide的显示要求不一样,我们采用一个函数updateUI来统计进行处理,利用一个enum区分不同的模式。将UI独立与功能也是开发的原则之一。

      对于addressbook.h,我们增加相关的button定义和SLOT函数。

    ... ... class AddressBook : public QWidget { ... ... public:     ... ...     enum Mode {NavigationMode,AddingMode, EditingMode};//设置枚举方式 public slots:     ... ...     void next();     void previous();     void editContact();     void removeContact(); private:     ... ...     QPushButton * nextButton, * previousButton;     QPushButton * editButton, * removeButton;     Mode currentMode;     void updateUI(Mode mode); //用于专门处理UI的函数 }; ... ...

      对于addressbook.cpp文件,我们修改如下,并让程序看起来更为优雅:

    ... ... AddressBook :: AddressBook(QWidget * parent) : QWidget(parent) {     ... ...     editButton = new QPushButton(tr("&Edit"));     editButton->setEnabled(false);     removeButton = new QPushButton(tr("&Remove"));     removeButton->setEnabled(false);     ... ...     buttonLayout1->addWidget(editButton); //将edit和remove两个button放置在sumbit和calcel前面     buttonLayout1->addWidget(removeButton);     buttonLayout1->addWidget(submitButton);     buttonLayout1->addWidget(cancelButton);     ... ...     connect(editButton, SIGNAL(clicked()),this,SLOT(editContact()));     connect(removeButton, SIGNAL(clicked()),this,SLOT(removeContact()));     ... ...     nextButton = new QPushButton(tr("&Next"));     nextButton->setEnabled(false);     previousButton = new QPushButton(tr("&Previous"));     previousButton->setEnabled(false);     connect(nextButton,SIGNAL(clicked()),this,SLOT(next()));     connect(previousButton,SIGNAL(clicked()),this,SLOT(previous()));     QHBoxLayout * buttonLayout2 = new QHBoxLayout;     buttonLayout2->addWidget(nextButton);     buttonLayout2->addWidget(previousButton);     ... ...     mainLayout->addLayout(buttonLayout1,1,2);     mainLayout->addLayout(buttonLayout2,2,1);     ... ... } void AddressBook::updateUI(Mode mode){     currentMode = mode;     switch(mode){     case AddingMode:     case EditingMode:         if(mode == AddingMode)             editButton->hide();         else if(mode == EditingMode)             addButton->hide();         removeButton->hide();         nameLine->setReadOnly(false);         nameLine->setFocus(Qt::OtherFocusReason);         addressText -> setReadOnly(false);         addButton->setEnabled(false);         editButton->setEnabled(false);         removeButton->setEnabled(false);         nextButton->setEnabled(false);         previousButton->setEnabled(false);         submitButton->show();         cancelButton->show();         break;     case NavigationMode: //浏览模式:任何功能完成后都进入浏览模式,如果有一个元素,则next和previous有效,并在此模式下可以进入功能操作         nameLine->setReadOnly(true);         addressText -> setReadOnly(true);         if(contacts.isEmpty()){             nameLine->clear();             addressText->clear();         }         addButton->setEnabled(true);         editButton->setEnabled(!contacts.isEmpty());         removeButton -> setEnabled(!contacts.isEmpty());         nextButton -> setEnabled(!contacts.isEmpty());         previousButton -> setEnabled(!contacts.isEmpty());         addButton->show();         editButton->show();         removeButton->show();         submitButton->hide();         cancelButton->hide();         break;     default:         break;     }    } void AddressBook::addContact() {     oldName = nameLine->text();     oldAddress = addressText->toPlainText();     nameLine->clear();     addressText->clear();     updateUI(AddingMode); } void AddressBook::editContact(){     oldName = nameLine->text();     oldAddress = addressText->toPlainText();     updateUI(EditingMode); } void AddressBook::removeContact(){     QString name = nameLine->text();     QString address = addressText->toPlainText();         if(contacts.contains(name)){         if(QMessageBox::question(this,tr("Confirm Remove"), tr("Are you sure you want to remove %1").arg(name),          QMessageBox ::Yes | QMessageBox :: No) == QMessageBox :: Yes){             previous();             contacts.remove(name);//QMap操作             if(contacts.isEmpty()){                 nameLine->clear();                 addressText->clear();             }             QMessageBox::information(this,tr("Remove successful!"),              tr("/"%1/" is already removed from your address book").arg(name));         }     }     updateUI(NavigationMode); } void AddressBook::submitContact() {     QString name = nameLine->text();     QString address = addressText->toPlainText();        if(name.isEmpty() || address.isEmpty()){         QMessageBox::information(this,tr("Empty Field"),          tr("Please enter a name and address"));         return;     }     switch(currentMode){     case AddingMode:         if(contacts.contains(name)){             QMessageBox::information(this,tr("Add Unsuccessful!"), tr("Sorry,/"%1/" is already in your address book").arg(name));             return;         }else{             contacts.insert(name, address);//QMap的使用:增加             QMessageBox::information(this, tr("Add Successful!"),  tr("<%1,%2> has been added.").arg(name,address));         }         break;     case EditingMode:         if(oldName != name){             if(!contacts.contains(name)){                 QMessageBox::information(this, tr("Edit successful!"), tr("Sorry,<%1> has been edited.").arg(name));                 contacts.remove(oldName);//QMap使用:删除                 contacts.insert(name,address); //QMap的使用:增加             }else{                 QMessageBox::information(this, tr("Edit Unsuccessful!"), tr("Sorry,<%1> already in your addressbook.").arg(name));                 cancel();             }         } else if(oldAddress != address){             QMessageBox::information(this, tr("Edit successful!"), tr("Sorry,<%1> has been edited.").arg(name));             contacts[name] = address; //可以采用类似数组的方法对QMap[key]进行赋值             cancel();         }break;     default:         break;     }     updateUI(NavigationMode); } void AddressBook::cancel() {     nameLine->setText(oldName);     addressText->setText(oldAddress);     updateUI(NavigationMode); } void AddressBook::next() {     QString name = nameLine->text();     QMap<QString,QString>::iterator i = contacts.find(name); //QMap的查找和interator     i ++; //可通过i++,将元素移到下一个元素     if(i == contacts.end()) //由于最后一个元素为NULL,并不实际存在,需要设为第一个元素         i = contacts.begin();     nameLine->setText(i.key()); //获取key的值     addressText->setText(i.value()); //获取value的值 } void AddressBook::previous() {     QString name = nameLine->text();     QMap<QString,QString>::iterator i = contacts.find(name);     if(i == contacts.begin()){ //如果是第一元素,需要移为实际的最后一个元素,即end-1         i = contacts.end()-1;     }else{         i --;     }     nameLine->setText(i.key());     addressText->setText(i.value()); }

    相关链接:我的MeeGo/Moblin相关文章


    最新回复(0)