在之前的MeeGo开发者(五):QT(3)对象和继承小例子基础上,我们增加三个button,参考http://doc.qt.nokia.com/latest/tutorials-addressbook-part2.html 、http://doc.qt.nokia.com/latest/tutorials-addressbook-part3.html和http://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相关文章