首页 > 其他分享 >QT(4)信号、SLOT和QMap - Addressbook例子2

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

时间:2023-08-04 23:35:49浏览次数:49  
标签:SLOT ... QT contacts Addressbook nameLine tr addressText name


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

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

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

  最后的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的截图如下

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

  我们在这个基础上做进一步处理。我们增加一个两个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相关文章


标签:SLOT,...,QT,contacts,Addressbook,nameLine,tr,addressText,name
From: https://blog.51cto.com/u_9877302/6970016

相关文章

  • 初识QT、窗口以及信号槽
    1基本规范:无论是写什么样的代码,第一步都应该是创建一个程序对象#include<QApplication>intmain(intargc,char*argv[]){QApplicationa(argc,argv);//创建对象并调用构造函数returna.exec();//因为是gui界面开发,那么程序的生存周期应该是一直存在的}2d......
  • 十五、基于MQTT协议上传属性至ONENET Studio
    1.准备工作(1)下载MQTT透传固件(安心可官网下载即可)(2)下载MQTT固件到ESP82662.AT指令连接设备上传属性值(1)AT\r\n(2)AT+RST\r\n(3)AT+CWMODE=1\r\n(4)AT+CWDHCP=1,1\r\n(5)AT+CWJAP="WIFISSID","密码"\r\n//连接路由器(6)AT+MQTTUSERCFG=0,1,"设备名/设备id","产品I......
  • Qt 在线程中invokeMethod采用QueuedConnection模式,调用带指针参数槽,实际不会调用
    widgetObject有操函数Test:voidTest(int*v);在线程中调用Test,会被忽略,实际不会调用。QMetaObject::invokeMethod(widgetObject,"Test",Qt::QueuedConnection,Q_ARG(int*,&v));下面是网上找的理由: 在同一个线程中当信号和槽都在同一个线程中时,值传递参数和引用传递参数有......
  • Qt 通过ADS实现倍福TwinCAT通信
    ADS通信分为两种:同步方式和异步方式。同步方式ADS客户端向ADS服务器发送ADS请求,在通信过程中客户端程序停止执行,直到获得ADS服务器返回的响应又可分为变量名方式和地址方式异步方式ADS客户端向ADS服务器发送ADS请求,同时客户端继续自己的工作。ADS服务器处理......
  • Qt 调用倍福TwinCAT通讯模块(TcAdsDll)
    Qt实现TwinCAT通讯目前这种方式是通过调用TwinCAT提供的AdsApi与倍福PLC通讯的。要求本机安装TwinCAT(无需作为主机,但是可能这个api依赖TwinCAT的一些服务)。关于AdsApi的官方资料请看这里,有函数的详细解释,还有例子。你值得拥有。https://infosys.beckhoff.com/english.php?conte......
  • Qt TwinCAT3中的变量回调函数的时间戳读取方式
    官网提供了例程,官网真是个宝库。基本ADS的操作都里面有例程了,但是可能会稍微分散一点,不过多看几遍,也就慢慢整理你所需要的东西出来了。https://infosys.beckhoff.com/index_en.htm1#include<Windows.h>2#include<conio.h>3#include<winbase.h>45#include<TcA......
  • Qt ADS中通过变量名访问变量的值
    在倍福提供的TwinCATADS的库的C(C++)接口中,有两种方式可以访问到PLC中的变量:根据地址访问、根据变量名访问。根据地址来访问的代码如下:1...2QStringhostNetId="192.168.12.51.1.1";3inthostPort=851;4AmsAddrtargetAddr=createAddr(hostNetId,hostPort);//这个......
  • pycharm配置QtDesigner
    一、安装需要的库pipinstallpyqt5pipinstallpyqt5-tools 二、配置QtDesigner 配置 QtDesignerName:QtDesignerGroup:QtProgram:C:\python\venv\Lib\site-packages\qt5_applications\Qt\bin\designer.exeWorkingdirectory:$ProjectFileDir$ 配置 PyUICNa......
  • iTOP-STM32MP157开发板一键烧写 QT 程序到开发板
    1根据上一小节设置好编译套件后,打开自己的qt工程,然后点击qtcreator里面的项目,把编译器切换成上一章节设置好的的编译器,如下图所示:2然后打开要编译的QT代码的pro文件,在里面添加以下代码,这俩行代码的意思是说把编译的可执行程序下载到开发板的/opt目录下并执行。target.pa......
  • MQTT:轻量级消息传输协议在物联网中的应用
    随着物联网技术的发展,越来越多的设备需要进行实时通信和数据交换。在这样的背景下,MQTT(MessageQueuingTelemetryTransport)作为一种轻量级的消息传输协议,逐渐成为物联网领域的热门选择。本文将介绍MQTT协议的基本概念、特点以及在物联网中的应用,同时通过代码实例演示如何使用MQTT......