• QT 信号与槽 QT简单加法器的实现


    信号与槽

    背景:

        面向过程

         模块之间低耦合设计(高内聚)。

                函数调用:

                     直接调用

                     回调调用(低耦合)

        面向对象

            模块之间低耦合设计(高内聚)

               对象调用

                  直接调用

                  接口调用

    QT:

       信号与槽解决问题:

           对象的成员变量调用?

          对象的成员函数调用?

    案例:

         窗体,有一个文本框

         线程,每个一秒改变文本框

         问题:

                                线程类访问窗体组件比较麻烦,需要传递。

                                在QT中,使用线程程序可能不工作。

    代码:

    #include<QApplication>

    #include “shake.h”

    int main(int  args , char **argv)

    {

        QApplication  app(args , argv);

        ShakeForm dlg;

        dlg.setVisible(true);

         return  app.exec();

    }

    shake.h

    #ifndef SHAKE_H

    #define SHAKE_H

    #include<QDialog>

    #include<QLineEdit>

    #include “mythread.h”

    class ShakeForm : public QDialog

    {

     public:

         ShakeForm(QWidget * parent=NULL);

         ~ShakeForm();

     private:

         QLineEdit *txt;

         ShakeThread *th;

    };

    #endif

    shake.cpp

    #include “shake.h”

    ShakeForm::ShakeForm(QWidget *parent)

    {

        txt = new QLineEdit(this);

        this->resize(400,300);

        txt->resize(100,30);

        txt->move(10,10);

        th=new ShakeThread(txt);

         th->start();

    }

    ShakeForm::~ShakeForm()

    {

        delete txt;

    }

    mythread.h

    #ifndef SHAKE_THREAD_H

    #define SHAKE_THREAD_H

    #include<pthread.h>

    #include<QLineEdit>

    class ShakeThread

    {

     public:

         pthread_t  tid;

         static  void * s_run(void *);

         QLineEdit *m_txt;

     private:

         ShakeThread(QLineEdit *txt);

         void start();

         virtual void run();

         

    };

    #endif

    mythread.cpp

    #include “mythread.h”

    #include<unistd.h>

    #include<math.h>

    ShakeThread::ShakeThread(QLineEdit *txt)

    {

      m_txt=txt;

    }

    void *ShakeThread::s_run(void * data)

    {

        ShakeThread *st=(ShakeThread*)data;

        st->run();

         returnNULL;

    }

    void ShakeThread::start()

    {

         pthread_create(&tid , 0, s_run ,this);

    }

    void ShakeThread::run()

    {

        //实现线程逻辑

         intnum;

         while(1)

        {

              //修改文本框

              num=rand()%10000000;

              m_txt->setText(QString::number(num));

              sleep(1);

              

        }

    }

    注意:全局函数调用成员函数不能通过编译:pthread_create全局函数调用run成员函数不能通过编译,ShakeThread::run(voiddata) 与 void*(*run)(void*) 参数不匹配。解决办法:把成员函数run定义成静态成员函数:staticvoid * run(void * data);

    原因:成员函数代码在局部栈中,全局函数在全局栈,静态成员函数代码在全局栈,则可定义为静态成员函数。

    案例总结:窗体中编辑框中并没有产生随机数的变化

            原因:窗体为了防止界面混乱,为界面加了异步锁,线程很难访问窗体

    使用信号与槽

    最大的好处,通过参数传递,直接调用对象

    以及在对象之间传递数据

    1.       头与实现必须分开

    2.       必须继承QObject

    3.       被调用函数称为槽slot

    4.       调用函数称为信号

    5.       必须在类引入QObject中一个宏Q_OBJECT

    6.       实现与c++完全一样

    7.       信号与槽的返回值必须是void

    8.       关联的信号与槽原型必须一致,名字可以不同

    思考:

         信号与槽在对象耦合上有什么优点?

    例子:

    log.h

    #ifndef LOG_H

    #define LOG_H

    #include<QObject>

    class Log :public QObject

    {

     Q_OBJECT         //建议放到类的开始位置

     public slots:       //槽函数,可以被某个函数调用

        void  log();

    };

    #endif

    log.cpp

    #include “log.h”

    #include<iostream>

    using namespace std;

    void Log::log()

    {

       cout<<“日志调用”<<endl;

    }

    biz.h //业务类

    #ifndef BIZ_H

    #define BIZ_H

    #include<QObject>

    class Biz : public QObject

    {

    Q_OBJECT

    public:

    void  biz();

    public:  signals:       //定义一个信号函数,信号函数不需要实现

        void  siglog();

    };

    #endif

    biz.cpp

    #include “biz.h”

    #include<iostream>

    #include<unistd.h>

    using namespace std;

    void Biz::biz()

    {

      while(1)

       {

           sleep(1);

           cout<< “业务处理”<<endl;

           //怎么调用槽?

           emit siglog();     //调用信号函数,emit发送信号

        }

        

        

    }

    main.cpp

    #include “biz.h”

    #include “log.h”

    int main()

    {

        Log  log;

        Biz  biz;

        QObject::connect(

    &biz,   //信号源对象

    SIGNAL(siglog()), //信号函数

    &log,  //槽目标对象

    SLOT(log()));  //槽函数

        biz.biz();

    }

    注意:信号和槽函数返回值必须为void

    使用信号和槽实现上边的案例:

    代码:

    #include<QApplication>

    #include “shake.h”

    int main(int  args , char **argv)

    {

        QApplication  app(args , argv);

        ShakeForm dlg;

        dlg.setVisible(true);

         return app.exec();

    }

    shake.h

    #ifndef SHAKE_H

    #define SHAKE_H

    #include<QDialog>

    #include<QLineEdit>

    #include “mythread.h”

    class ShakeForm : public QDialog

    {

    Q_OBJECT

     public:

         ShakeForm(QWidget * parent=NULL);

         ~ShakeForm();

     private:

          QLineEdit *txt;

         ShakeThread *th;

    };

    #endif

    shake.cpp

    #include “shake.h”

    ShakeForm::ShakeForm(QWidget *parent)

    {

        txt = new QLineEdit(this);

        this->resize(400,300);

        txt->resize(100,30);

        txt->move(10,10);

        th=new ShakeThread();

        QObject::connect(th,SIGNAL(setNumber(QString)),txt,SLOT(setText(QString)));

        th->start();

    }

    ShakeForm::~ShakeForm()

    {

        delete txt;

    }

    mythread.h

    #ifndef SHAKE_THREAD_H

    #define SHAKE_THREAD_H

    #include<pthread.h>

    #include<QLineEdit>

    class ShakeThread : public QObject

    {

    Q_OBJECT

     public:

         pthread_t  tid;

         static  void * s_run(void *);

     private:

         ShakeThread();

         void start();

         virtual void run();

    public : signals:

         void  setNumber(QString)

         

    };

    #endif

    mythread.cpp

    #include “mythread.h”

    #include<unistd.h>

    #include<math.h>

    ShakeThread::ShakeThread()

    {

    }

    void *ShakeThread::s_run(void * data)

    {

        ShakeThread *st=(ShakeThread*)data;

        st->run();

         returnNULL;

    }

    void ShakeThread::start()

    {

          pthread_create(&tid , 0, s_run ,this);

    }

    void ShakeThread::run()

    {

        //实现线程逻辑

         intnum;

         while(1)

        {

              //修改文本框

              num=rand()%10000000;

              emit setNumber(QString::number(num));

              sleep(1);

              

        }

    }

    总结:QLineEdit类中的setText函数就是个槽函数,只要在线程类中添加个信号函数setNumber ,在线程处理函数中发送信号函数并传值,则setText函数就会修改QLineEdit中的值。

    注意:线程类要继承QObject类,并在线程类和窗体类中添加Q_OBJECT宏.

    这样就不需要给线程类传递QLineEdit类的对象,而且可以修改文本框中的值了

    QT可视化组件(控件)

         其中的信号时怎么发出的?

         信号时自动发出

    案例:

         使用按钮的信号

            按钮事件发生的时候发出信号

            事件->信号->槽

         信号与槽解决如下问题:事件发生时,怎么调用用户函数

         新的类:

              QMessageBox提供一组静态函数弹出对话框

    步骤:

    1.       main.cpp

    2.       *.pro

    3.       对话框类

    4.       实现按钮clicked信号对应槽函数

            槽函数必须与clicked信号同型

            void clicked(bool checked=false);

            槽函数在哪个类实现?槽函数放入访问成员最多的类

    5.       绑定信号与槽

    代码:

    main.cpp

    #include<QApplication>

    #include “mydialog.h”

    int main(int  args , char ** argv)

    {

        QApplication  app(args,argv);

        MyDialog dlg;

        dlg.setVisible(true);

         return  app.exec();

    }

    main.pro

    TEMPLATE=app

    SOURCES=main.cpp mydialog.cpp

    HEADERS=mydialog.h

    CONFIG=release qt

    QT=core gui

    TARGET=main

    mydialog.h

    #ifndef MY_DIGLOG_H

    #define MY_DIGLOG_H

    #include<QDialog>

    #include<QPushButton>

    class MyDialog : public QDialog

    {

    Q_OBJECT

     private:

         QPushButton *btn;

     public:

         MyDialog(QWidget * parent=NULL);

         ~MyDialog();

     public slots:

          void showBox();

    };

    #endif

    mydialog.cpp

    #include “mydialog.h”

    #include<iosteam>

    #include<QMessageBox>

    using std::cout;

    using std::endl;

    MyDialog::MyDialog(QWidget * parent)

    {

         resize(400,300);

         btn = new QPushButton(this);

          btn->resize(100,30);

         btn->move(150,150);

         btn->setText(“ok”);

         QObject::connect(btn,SIGNAL(clicked),this,SLOT(showBox));

    }

    MyDialog::~MyDialog()

    {

       delete btn;

    }

    void MyDialog::showBox()

    {

         //cout<< “我被点击”<<endl;

         QMessageBox::information(this, “Information”, “this is information”);

    }

    总结:用户点击按钮,按钮发生点击事件,事件发出clicked信号,用户实现槽函数,并绑定槽函数与信号函数。

    QMessageBox类实现了很多静态函数实现弹出对话框

           Information

           about 关于对话框

           …….看手册

    案例2:

    加法器

        界面:文本框 + 文本框 =(按钮) 标签库

          1.设计界面(*.ui,*.h)

                  2.main.cpp

                  3.pro

                  4.对话框

                  5.处理信号与槽

    界面设计器设计界面并保存为frmjfq.ui

    编译:uicfrmjfq.ui –o frmjfq.h

    代码:

    main.cpp

    #include<QApplication>

    #include “dlgjfq.h”

    int main(int args , char ** argv)

    {

        QApplication  app(args , argv);

         DlgJFQdlg;

        dlg.setVisible(true);

         returnapp.exec();

    }

    main.pro

    TEMPLATE=app

    SOURCES=main.cpp  dlgjfq.cpp

    HEADERS=frmjfq.h  dlgjfq.h

    CONFIG=release qt

    QT=core gui

    TARGET=main

    dlgjfq.h

    #ifndef DLG_JFQ_H

    #define DLG_JFQ_H

    #include “frmjfq.h”

    #include<QDialog>

    class DlgJFQ :public QDialog

    {

     Q_OBJECT

     private:

         Ui_Frmjfq  *ui;

     public:

          DlgJFQ(QWidget *parent=NULL);

          ~DlgJFQ();

      publicslots:

          void  add();   //+按钮槽函数

          

          

    };

    #endif

    dlgjfq.cpp

    #include “dlgjfq.h”

    DlgJFQ::DlgJFQ(QWidget * parent)

    {

    ui = newUi_Frmjfq;

    ui->setupUi(this);

    QObject::connect(ui->btnAdd,SIGNAL(clicked()),this,SLOT(add()));

    }

    DlgJFQ::~DlgJFQ()

    {

       delete ui;

    }

    void DlgJFQ::add()

    {

    //取字符串

    QString  strAdded=ui->txtAdded->text(); //txtAdded,txtAdd 为两个文本框的对象,在ui

    QString  strAdd = ui->txtAdd ->text();

    //转换为整数

    intia=strAdded.toInt();

    intib=strAdd.toInt();

    //计算和

    int   ic=ia+ib;  

    //把和转换为文本显示

    ui->lblResult->setText(QString::number(ic));

    }

                

  • 相关阅读:
    c# EPPlus读取Excel里面的时间字段时,1900-01-01转成了1899-12-31
    c# MongoDB分页辅助类,支持多条件查询
    c#比较器辅助类
    mysql创建存储过程动态SQL语句
    MySQL数据库之DML(数据操作语言)
    MySQL数据库之DDL(数据定义语言)
    MySQL数据库的基本语法
    MySQL入门基础知识
    scala入门基础学习
    推荐算法杂点
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3328972.html
Copyright © 2020-2023  润新知