QT_for_linux

第一个QT应用程序

  • 重点掌握开发流程

    (1)创建工程目录

    mkdir Hello #每个QT程序都要放在一个独立的工程目录下

    (2)进入工程目录编写源代码

    vi main.cpp  #语法和C++保持基本一致,但使用QT的类库不再是标准C++的库
    #include<QApplication>
    #include<QLabel>
    int main(int argc,char** argv)
    {
    //创建QT应用程序对象
    QApplication app(argc,argv);

    //创建标签控件
    QLabel label("Hello Qt!");

    //显示标签控件
    label.show();

    //让应用程序进入事件
    return app.exec();

    }

    (3)构建工程

    qmake -prohect #生成工程文件Hello.pro,并在文件中添加构建选项,QT += widgets

    (4)创建Makefile

    qmake  #可以根据上一步的工程文件自动生成Makefile

    (5)编译连接

    make  #执行即可完成编译与链接

    (6)测试

    ./Hello  #运行,默认名字与工程名字一致

QT中文编码

  • QT内部使用unicode编码,通常是UTF-16

  • QT的优化UTF-8转换为UTF-16

  • 通过QTextCodec编码转换

    QTextCodec *coder = QTextCodec::codeForName("GBK");
    QString string = codec->toUnicode("GBK编码的中文字符串");
    #include <QApplication>
    #include <QLabel>
    #include<QTextCodec>
    #include<QPushButton>

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);

    QTextCodec *coder = QTextCodec::codecForName("GBK");

    QLabel label(coder->toUnicode("我是标签"));

    label.show();

    QPushButton button(coder->toUnicode("我是按钮"));

    button.show();

    return a.exec();
    }

父窗口

  • 创建控件时,可以指定停靠再某个父窗口上面,这时控件将作为子窗口

  • Qwidget及其子类的对象可以作为其它控件的父窗口

  • 常用的父窗口类又如下三个:

  • QWidget

  • QMainWindow(主窗口) //QWidget的直接子类

  • QDialog(对话框) //QWidget的直接子类

  • 父窗口的析构函数回自动销毁其所有的子窗口对象,因此即使子窗口对象时通过new操作符动态创建的,可以不显示的执行delete,而且不用担心内存泄漏问题,只要保证父窗口对象被正确销毁,其子窗口也将随之被销毁。

  • 设置窗口的位置和大小

    void move(int x,int y);
    void resize(int w,int h);

例子

#include<QWidget>
#include<QDialog>
#include<QMainWindow>
#include<QLabel>
#include<QPushButton>
#include<QTextCodec>
#include<QApplication>

int main(int argc,char** argv){
QApplication app(argc,argv);
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
//父窗口定义
QDialog parent;
parent.move(50,50);
parent.resize(320,240);

//创建标签控件,停靠再父窗口上面
QLabel label((codec->toUnicode("我是标签")),&parent);
label.move(20,40);

//创建按钮控件,停靠在父窗口上边
QPushButton button((codec->toUnicode("我是标签")),&parent);
button.move(20,100);
button.resize(80,80);

parent.show();
return app.exec();
}
-------------------------------

#include<QWidget>
#include<QDialog>
#include<QMainWindow>
#include<QLabel>
#include<QPushButton>
#include<QTextCodec>
#include<QApplication>

int main(int argc,char** argv){
QApplication app(argc,argv);
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
//父窗口定义
QDialog parent;
parent.move(50,50);
parent.resize(320,240);

//创建标签控件,停靠再父窗口上面
QLabel label((codec->toUnicode("我是标签")),&parent);
label.move(20,40);

//创建按钮控件,停靠在父窗口上边
QPushButton button((codec->toUnicode("我是按钮")),&parent);
button.move(20,100);
button.resize(80,80);

//使用对象指针的形式
//new对象如果指定了父窗口指针,可以不写delete,在父窗口对象销毁时,它会自动被销毁。
QPushButton* button2 = new QPushButton((codec->toUnicode("我也是按钮")),&parent);
button2->move(170,100);
button2->resize(80,80);

parent.show();//父窗口显示,上面停靠的控件也将一起显示


return app.exec();
}

信号和槽

  • 信号和槽是QT自行定义的一种通信机制,实现对象之间的数据交互。

  • 当用户或系统触发了一个动作,导致某个控件的状态发生了改变,该控件就会发射一个信号,即调用其类中一个特定的成员函数(信号),同时还有可能携带有必要的参数。

  • 槽和普通的成员函数几乎没有太多区别,可以是公有的、保护的或私有的,可以被重载,也可以被覆盖,其参数可以是任意类型,并可以像普通成员函数一样调用

  • 槽函数与普通成员函数的差别并不在于其语法特性,而在于其功能。槽函数更多体现为对某种特定信号的处理,可以将槽和其他对象信号建立连接,这样当发射信号时,槽函数将被触发和执行,进而来完成具体功能。

  • 型号函数

    class XX:public QObject{
    Q_OBJECT//宏,moc
    signals:
    void signal_func(..); //信号函数
    };
    //信号函数只需声明,不能写定义
  • 槽函数

    class XX:public QObject{
    Q_OBJECT//moc原对象编译器
    public slots:
    void slot_func(..){..}//槽函数
    };
    //槽函数可以连接到某个信号上,当信号被发射时,槽函数将被触发和执行,另外槽函数也可以当作普通的成员函数直接调用。
  • 信号和槽的连接

    QObject::connect(const QOject *sender,const char * signal,const QObject * receiver,const char * method);
    //参数
    sender:信号发送对象指针
    signal:要发送的信号函数,可以使用"SIGNAL(..)"宏进行类型转换
    receiver:信号的接收对象指针
    method:接收信号要执行的槽函数,可以使用"SLOT(..)"宏进行类型转换

案例

创建Qt应用程序,包含标签和按钮两个控件,实现点击按钮关闭标签

  • 按钮点击时发送信号:clicked()
  • 实现标签关闭功能的槽:close()
#include<QApplication>
#include<QLabel>
#include<QPushButton>
#include<QDialog>
#include<QTextCodec>


int main(int argc,char **argv)
{
QApplication app(argc,argv);
QTextCodec *codec = QTextCodec::codecForName("UTF-8");

QDialog parent;
parent.resize(320,240);

QLabel label(codec->toUnicode("我是标签"),&parent);
label.move(50,40);

QPushButton button(codec->toUnicode("我是按钮"),&parent);
button.move(50,140);
QPushButton button1(codec->toUnicode("结束"),&parent);
button1.move(200,140);

//点击按钮关闭标签
QObject::connect(&button,SIGNAL(clicked(void)),&label,SLOT(close(void)));


//点击按钮关闭程序
//1. QObject::connect(&button1,SIGNAL(clicked(void)),&app,SLOT(closeAllWindows(void)));
//2. QObject::connect(&button1,SIGNAL(clicked(void)),&app,SLOT(quit(void)));
//3. QObject::connect(&button1,SIGNAL(clicked(void)),&parent,SLOT(close(void)));

parent.show();
return app.exec();
}

信号和槽连接的语法要求

  • 信号和槽参数要一致

    QObject::connect(A,SIGNAL(sigfun(int)),B,SLOT(slotfun(int)));  //OK
    QObject::connect(A,SIGNAL(sigfun(int)),B,SLOT(slotfun(int,int))); //error
  • 可以带有缺省参数

    QObject::connect(A,SIGNAL(sigfun(int)),B,SLOT(slotfun(int,int=0)));  //OK
  • 信号函数的参数可以多于槽函数

    QObject::connect(A,SIGNAL(sigfun(int,int)),B,SLOT(slotfun(int))));  //OK
  • 一个信号可以被连接到多个槽

    QObject::connect(A,SIGNAL(sigfun(int)),B1,SLOT(slotfun(int))));  //OK
    QObject::connect(A,SIGNAL(sigfun(int)),B2,SLOT(slotfun(int)))); //OK
    //触发的顺序不确定
  • 多个信号也可以连接到同一个槽

    QObject::connect(A1,SIGNAL(sigfun1(int)),B,SLOT(slotfun(int))));  //OK
    QObject::connect(A2,SIGNAL(sigfun2(int)),B,SLOT(slotfun(int)))); //OK
  • 两个信号可以直接连接(信号级联)

    QObject::connect(A1,SIGNAL(sigfun2(int)),A2,SLOT(sigfun2(int))));  //OK
  • 案例

    创建QT应用程序,包含滑块(QSlider)和选值框(QSpinBox),通过信号和槽的机制,保持同步运行

    #include<QApplication>
    #include<QLabel>
    #include<QPushButton>
    #include<QDialog>
    #include<QTextCodec>
    #include<QSlider>
    #include<QSpinBox>


    int main(int argc,char **argv)
    {
    QApplication app(argc,argv);
    QDialog parent;
    parent.resize(320,240);

    //创建水平滑块
    QSlider slider(Qt::Horizontal,&parent);
    slider.move(20,100);
    slider.setRange(0,200);

    //创建选值框
    QSpinBox spin(&parent);
    spin.move(220,100);
    spin.setRange(0,200);

    //滑块滑动,选值框随之改变
    QObject ::connect(&slider,SIGNAL(valueChanged(int)),&spin,SLOT(setValue(int)));

    //改变选值,滑块改变
    QObject ::connect(&spin,SIGNAL(valueChanged(int)),&slider,SLOT(setValue(int)));

    parent.show();
    return app.exec();
    }

面向对象的Qt编程

  • 基于对象的Qt编程,有限制

  • 通过面向对象的编程思想实现加法计算器

  • 案例

    计算器实现

    calcuator.h

    #ifndef CALCULATOR_H
    #define CALCULATOR_H

    #include <QDialog>
    #include <QLabel>
    #include<QPushButton>
    #include<QLineEdit> //行编辑控件
    #include<QHBoxLayout> //水平布局器
    #include<QDoubleValidator> //验证器

    class Calculator : public QDialog
    {
    Q_OBJECT //mocQt语法扩展
    private:
    QLineEdit* m_editX;
    QLineEdit* m_editY;
    QLineEdit* m_editZ;
    QLabel* m_label;
    QPushButton* m_button;

    public:
    Calculator(void);
    ~Calculator();
    public slots:
    //使能的能耗按钮的槽操作数
    void enableButton(void);
    void calcClicked(void);
    };

    #endif // CALCULATOR_H

    calculator.cpp

    #include "calculator.h"

    Calculator::Calculator(void)
    {

    //界面初始化
    setWindowTitle("计算器");
    //左操作数,this即为当前父窗口指针
    m_editX = new QLineEdit(this);
    //设置文本对齐:右对齐
    m_editX->setAlignment(Qt::AlignRight);
    //设置数字验证器,只能输入数字形式内容
    m_editX->setValidator(new QDoubleValidator(this));

    //右操作数
    m_editY = new QLineEdit(this);
    //设置文本对齐:右对齐
    m_editY->setAlignment(Qt::AlignRight);
    //设置数字验证器,只能输入数字形式内容
    m_editY->setValidator(new QDoubleValidator(this));

    //显示结果
    m_editZ = new QLineEdit(this);
    m_editZ->setAlignment(Qt::AlignRight);
    m_editZ->setReadOnly(true);//设置为只读

    //"+"
    m_label = new QLabel("+",this);
    //"="
    m_button = new QPushButton("=",this);
    m_button->setEnabled(false); //设置禁用


    //创建布局器:自动调整每个控件的大小和位置
    QHBoxLayout* layout = new QHBoxLayout(this);
    //按水平方向,依次添加控件到布局器中
    layout->addWidget(m_editX);
    layout->addWidget(m_label);
    layout->addWidget(m_editY);
    layout->addWidget(m_button);
    layout->addWidget(m_editZ);
    //设置布局器
    setLayout(layout);

    //信号和槽函数连接
    //左右操作数文本改变时,发送信号textChanged()
    connect(m_editX,SIGNAL(textChanged(QString)),this,SLOT(enableButton(void)));
    connect(m_editY,SIGNAL(textChanged(QString)),this,SLOT(enableButton(void)));

    //点击按钮,发送信号clicked
    connect(m_button,SIGNAL(clicked(void)),this,SLOT(calcClicked(void)));

    }

    Calculator::~Calculator()
    {

    }

    void Calculator::enableButton(void){
    bool bX0k = 0,bY0k = 0;
    //text:获取输入文本(QString)
    //toDouble():QString转换为double,参数保存转换是否成功结果
    m_editX->text().toDouble(&bX0k);
    m_editY->text().toDouble(&bY0k);

    //左右操作数都为有效数字,则使能等号按钮,否则设置禁用
    m_button->setEnabled(bX0k && bY0k);

    }
    //计算结果和显示的槽函数
    void Calculator::calcClicked(void){

    double res = m_editX->text().toDouble()+m_editY->text().toDouble();

    //number():将double转换为QString
    QString str = QString::number(res);
    //显示字符串形式结果
    m_editZ->setText(str);
    }

    mian.cpp

    #include "calculator.h"
    #include <QApplication>

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    Calculator w;
    w.show();

    return a.exec();
    }

参考文献

。。