对于图片等资源文件我们需要将其打包成文件夹,使用相对路径使得使用者能加载到对应路径文件

之后选择QT--》资源文件

之后添加前缀及添加对应文件

二、信号与槽机制(重点)是QT中用来实现多个组件之间互相通信的机制
信号:就是信号函数,是一个信号函数,定义在类体内signals权限下,是一个不完整的函数,只有声明没有定义,你不能直接调用它,只能通过emit关键字来触发
槽:就是槽函数,定义在类体的slots权限下,是一个完整的函数,既有声明也有定义,可以被当做普通函数被使用
槽声明了就得定义,但是信号不用,声明了不触发也可以,二者返回值一般都是void,参数可以自定义(参数的目的为了传信息)
ui界面下信号与槽的连接方式只能发射系统提供的信号,可使用系统提供的槽函数接收
也可右键转到槽,选择信号,槽函数骡子自己书写

而连接函数分为多种形式
- [static] QMetaObject::Connection //返回值是一个连接,并且该函数是一个静态成员函数
- QObject::connect( //函数名
- const QObject *sender, //信号的发射者,是组件的指针
- const char *signal, //要发射的信号是一个C语言风格的字符串,将信号函数传递进来时,需要使用SIGNAL宏进行转换
- const QObject *receiver, //信号的接受者,是组件的指针
- onst char *method) //处理信号的槽函数,是C风格字符串,将槽函数传递进来时,需要使用SLOT宏进行转换
- 注意:信号函数必须是信号的发射者所在的类中有的信号函数,而槽函数也必须是信号的接受者中有的槽函数
- 举个例子:
- QLabel *label = new QLabel;
- QScrollBar *scrollBar = new QScrollBar;
- QObject::connect(scrollBar, SIGNAL(valueChanged(int)),
- label, SLOT(setNum(int)));
qt5版本的连接函数
- [static] QMetaObject::Connection //返回值是一个连接,并且该函数是一个静态成员函数
- QObject::connect( //函数名
- const QObject *sender, //信号的发射者,是组件的指针
- PointerToMemberFunction signal, //信号函数的函数指针变量,直接填写函数名即可
- const QObject *receiver, //信号的接受者,是组件的指针
- PointerToMemberFunction method) //槽函数的函数指针变量,直接填写函数名即可
-
- 举个例子:
- QLabel *label = new QLabel;
- QLineEdit *lineEdit = new QLineEdit;
- QObject::connect(lineEdit, &QLineEdit::textChanged,
- label, &QLabel::setText);
信号也可连接lambda表达式或外部函数
- [static] QMetaObject::Connection //返回值是一个连接,并且该函数是一个静态成员函数
- QObject::connect( //函数名
- const QObject *sender, //信号的发射者,是组件的指针
- PointerToMemberFunction signal, //信号函数的函数指针变量,直接填写函数名即可
- Functor functor) //处理信号的功能函数,可以是全局函数,也可以是lambda表达式
-
- 举个例子:
- void someFunction();
- QPushButton *button = new QPushButton;
- QObject::connect(button, &QPushButton::clicked, someFunction);
-
-
- Lambda 表达式作为槽函数:
-
- QByteArray page = ...;
- QTcpSocket *socket = new QTcpSocket;
- socket->connectToHost("qt-project.org", 80);
- QObject::connect(socket, &QTcpSocket::connected, [=] () {
- socket->write("GET " + page + "\r\n");
- });
断开信号与槽的连接时使用disconect
参数可不变
- void Widget::on_btn6_clicked()
- {
-
-
- disconnect(btn3, SIGNAL(pressed()), ui->btn1, SLOT(hide()));
-
-
- disconnect(ui->btn4, &QPushButton::clicked, this, &Widget::my_slot);
-
-
- }
使用emit 加自定义信号名即可发射,在与槽函数连接后,槽函数会立即响应
先在初始配置文件中,添加TextToSpeech库

头文件中记得加头文件,及定义一个播报指针
- #ifndef WIDGET_H
- #define WIDGET_H
-
-
- #include
- #include
- #include
- #include
//文本转语音的头文件 -
-
- QT_BEGIN_NAMESPACE
- namespace Ui { class Widget; }
- QT_END_NAMESPACE
-
-
- class Widget : public QWidget
- {
- Q_OBJECT //信号与槽的元对象
-
-
- signals:
- void my_signal(); //自定义信号函数
-
-
- public slots:
- void my_slot(); //自定义的槽函数
-
-
- public:
- Widget(QWidget *parent = nullptr);
- ~Widget();
-
-
- private slots:
- void on_btn2_clicked();
-
-
- void on_btn6_clicked();
-
-
- private:
- Ui::Widget *ui;
-
-
- //自定义一个按钮
- QPushButton *btn3;
-
-
- //定义一个播报员指针
- QTextToSpeech *speecher;
-
-
-
-
- };
- #endif // WIDGET_H
源文件
- #include "widget.h"
- #include "ui_widget.h"
-
-
- void fun()
- {
- qDebug()<<"我是过路的";
- }
-
-
-
-
-
-
- Widget::Widget(QWidget *parent)
- : QWidget(parent)
- , ui(new Ui::Widget)
- {
- ui->setupUi(this);
-
-
- //给播报员实例化空间
- speecher = new QTextToSpeech(this);
-
-
- //给btn3实例化空间
- this->btn3 = new QPushButton("按钮3", this);
- this->btn3->move(ui->btn2->x(), ui->btn2->y()+50);
- this->btn3->resize(ui->btn2->size());
-
-
- //使用qt4版本的连接,将按钮3发射的pressed信号与按钮1的槽函数进行连接
- connect(btn3, SIGNAL(pressed()), ui->btn1, SLOT(hide()));
- //参数1:信号的发射者,按钮3的指针
- //参数2:要发射的信号,是在按钮所在类中拥有的信号函数,需要使用SIGNAL宏函数进行转换
- //参数3:信号的接受者,ui界面上的按钮1指针
- //参数4:处理信号的槽函数,是信号接收者所在类中拥有的槽函数
- //注意:该链接方式是不友好的链接,原因是 即使宏函数中写错,编译器不报错,但是没有现象
-
-
- //使用qt5版本的链接,将ui界面上的btn4按钮发射的clicked信号,与当前界面的自定义的槽函数连接
- connect(ui->btn4, &QPushButton::clicked, this, &Widget::my_slot);
-
-
- //将ui界面上的按钮5,发射的clicked信号,连接到全局函数中
- connect(ui->btn5, &QPushButton::clicked, fun);
-
-
- //将ui界面上的按钮5发射的clicked信号连接到lambda表达式中
- connect(ui->btn5, &QPushButton::clicked, [&](){
- // qDebug()<<"我是路人乙";
- speecher->say("我是路人乙");
- });
-
-
-
-
- //将当前界面的my_signal信号连接到自定义的槽函数中
- connect(this, &Widget::my_signal, [&](){
- speecher->say("已经成功断开按钮3和按钮4的连接");
- });
-
-
-
-
- }
-
-
- Widget::~Widget()
- {
- delete ui;
- }
-
-
- //自定义槽函数的实现
- void Widget::my_slot()
- {
- static int num = 0;
- if(num%2)
- {
- ui->btn2->setEnabled(false);
- }else
- {
- ui->btn2->setEnabled(true);
- }
-
-
- num++;
- }
-
-
-
-
-
-
- //该函数就是按钮2的clicked信号对应的槽函数
- void Widget::on_btn2_clicked()
- {
- static int num = 0;
-
-
- if(num % 3 == 0)
- {
- ui->btn2->setStyleSheet("background-color:red;");
- }else if(num % 3 == 1)
- {
- ui->btn2->setStyleSheet("background-color:yellow;");
- }else
- {
- ui->btn2->setStyleSheet("background-color:green;");
- }
-
-
- num++;
- }
-
-
- //断开按钮对应的槽函数
- void Widget::on_btn6_clicked()
- {
-
-
- disconnect(btn3, SIGNAL(pressed()), ui->btn1, SLOT(hide()));
-
-
- disconnect(ui->btn4, &QPushButton::clicked, this, &Widget::my_slot);
-
-
- //发射自定义的信号
- emit my_signal();
-
-
- }
练习:优化登录界面,当点击登录按钮后,在该按钮对应的槽函数中,判断账户和密码框内的数据是否为admin和123456,如果账户密码匹配成功,则提示登录成功并关闭登录界面,如果账户和密码匹配失败,则提示登录失败,并将密码框中的内容清空。
当点击取消按钮后,则关闭整个登录界面
要求:对登录按钮使用QT5版本的连接,对取消按钮使用qt4版本的连接
widget.cpp
- #include "widget.h"
-
- Widget::Widget(QWidget *parent)
- : QWidget(parent)
- {
- //设置页面
- this -> resize(540,410);
- this ->setFixedSize(540,410);
- this -> setWindowTitle("weifeng client");
- //this -> setStyleSheet("background-color:pink;");
- this -> setWindowIcon(QIcon(":/picture/ME.png"));
- //界面图
- lab1 = new QLabel(this);
- lab1 -> resize(540,150);
- lab1 -> setPixmap(QPixmap(":/picture/starcat.png"));
- lab1 -> setScaledContents(true);
- lab1->setStyleSheet("border-radius: 10px;");
-
- lab = new QLabel(this);
- lab -> resize(540,(410-150));
- lab -> move(0,lab1 -> height());
- lab -> setPixmap(QPixmap(":/picture/main-background.png"));
- lab -> setScaledContents(true);
- lab->setStyleSheet("border-radius: 10px;");
-
-
- effect = new QGraphicsOpacityEffect(); // 注意这里只影响 'lab'
- effect->setOpacity(0.4);
- lab->setGraphicsEffect(effect);
-
-
-
-
- //设置登录按键
- btn1 = new QPushButton("登录",this);
- btn1 -> move(145,300);
- btn1 -> resize(100,50);
- btn1 -> setIcon(QIcon(":/picture/16.gif"));
- connect(btn1,&QPushButton::clicked,this,&Widget::my_slot);
-
- //设置取消按键
- btn2 = new QPushButton("取消",this);
- btn2 -> move(btn1 -> x()+150,btn1 -> y());
- btn2 -> resize(100,50);
- btn2 -> setIcon(QIcon(":/picture/15.gif"));
- // btn2 -> connect(btn2,&QPushButton::clicked,this,&Widget::my_slot);//关闭
- btn2 -> connect(btn2,SIGNAL(clicked()),this,SLOT(close()));
-
-
-
-
- //账号前图片
- lab2 = new QLabel(this);
- lab2 -> resize(50,50);
- lab2 -> move(145,175);
- lab2 -> setPixmap(QPixmap(":/picture/08.gif"));
- lab2 -> setScaledContents(true);
- //密码前图片
- lab3 = new QLabel(this);
- lab3 -> resize(lab2 -> size());
- lab3 -> move(lab2 -> x(),lab2 -> y()+50);
- lab3 -> setPixmap(QPixmap(":/picture/12.gif"));
- lab3 -> setScaledContents(true);
-
- //账号
- font.setBold(true); //设置加粗
- lab4 = new QLabel("账号",this);
- lab4->setFixedHeight(30);
- lab4->setFont(font);
- lab4 -> move(lab2 -> x()+55,lab2 -> y()+20);
-
- //密码
- lab5 = new QLabel("密码",this);
- lab5 -> setFixedHeight(30);
- lab5 -> setFont(font);
- lab5 -> move(lab3 -> x()+55,lab3 -> y()+20);
-
-
- //账号栏
- edit1 = new QLineEdit(this);
- edit1 -> resize(140,lab4 -> height());
- edit1->setFixedHeight(30);
- edit1 -> move(lab4 -> x()+50,lab4 -> y());
- edit1 -> setPlaceholderText("QQ/手机/邮箱");
- //密码栏
- edit2 = new QLineEdit(this);
- edit2 -> resize(140,lab5 -> height());
- edit2->setFixedHeight(30);
- edit2 -> move(lab5 -> x()+50,lab5 -> y());
- edit2 -> setEchoMode(QLineEdit::Password);
- edit2 -> setPlaceholderText("密码");
-
-
- speecher = new QTextToSpeech(this);
-
-
-
- }
- void Widget::my_slot(){
- QString username = edit1 ->text();
- QString password = edit2 ->text();
- if(username == "admin"){
- if(password == "123456"){
- speecher -> say("登录成功");
- close();
- return;
- }
- }
- speecher -> say("登录失败");
- edit2->clear();
- }
- /*
- * 版本qt5
- void Widget::my_slot(){
- close();
- }
- */
- Widget::~Widget()
- {
- }
-
main
- #include "widget.h"
-
- #include
-
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- Widget w;
- w.show();
- return a.exec();
- }
widget.h
- #ifndef WIDGET_H
- #define WIDGET_H
-
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- class Widget : public QWidget
- {
- Q_OBJECT
-
- public:
- Widget(QWidget *parent = nullptr);
-
- ~Widget();
-
- signals:
- void my_signal();
-
- public slots:
- void my_slot();
-
- private:
- QLabel *lab1;
- QLabel *lab;
- QGraphicsOpacityEffect* effect;
- QPushButton *btn1;
- QPushButton *btn2;
- QLabel *lab2;
- QLabel *lab3;
- QFont font;
- QLabel *lab4;
- QLabel *lab5;
- QLineEdit *edit1;
- QLineEdit *edit2;
- QTextToSpeech *speecher;
- };
- #endif // WIDGET_H

一个信号函数发射出,多个相连接的槽函数都可执行
一个槽函数也可以同时响应多个与他连接的信号,只要一个信号被发射,该槽函数就会被执行
一个信号函数可以连接到另一个信号函数,一个被发射后一个也会被发射
信号与槽函数参数表为了传参有以下准则
- 1、信号函数和槽函数进行链接时,一般要求信号函数和槽函数的参数保持一致
- connect(信号发送者, SIGNAL(signalFun()),信号接收者, SLOT(slotFun())); //Ok
- connect(信号发送者, SIGNAL(signalFun(int)),信号接收者, SLOT(slotFun(int))); //Ok
- connect(信号发送者, SIGNAL(signalFun(int, char)),信号接收者, SLOT(slotFun(int, char))); //Ok
- connect(信号发送者, SIGNAL(signalFun(char, int)),信号接收者, SLOT(slotFun(int, char))); //False
- connect(信号发送者, SIGNAL(signalFun(int)),信号接收者, SLOT(slotFun(char))); //False
- 2、当信号函数的参数大于槽函数的参数时
- connect(信号发送者, SIGNAL(signalFun(int, char)),信号接收者, SLOT(slotFun())); //Ok
- connect(信号发送者, SIGNAL(signalFun(int, char)),信号接收者, SLOT(slotFun(int))); //Ok
- connect(信号发送者, SIGNAL(signalFun(int, char)),信号接收者, SLOT(slotFun(char))); //False
- 3、当信号函数的参数小于槽函数的参数时
- connect(信号发送者, SIGNAL(signalFun(int)),信号接收者, SLOT(slotFun(int, char))); //False
- connect(信号发送者, SIGNAL(signalFun(int)),信号接收者, SLOT(slotFun(int, char=0))); //Ok
多态:允许对象以多种方式存在,而多态分为静态和动态,
静态多态就是函数重载/运算符重载和模板,是编译时多态,通过相同的函数名,不同的参数列表实现重载,模板就是提前假定一个类型进行,通过需要的类型传递后达成。
动态多态是运行时多态,主要是通过虚函数实现函数重写,父类的指针或者引用,指向或初始化子类的对象,调用子类对父类重写的函数,进而展开子类的功能。
虚函数:在动态多态中使用到,在函数前加上virtual关键字,父类中该函数是虚函数的话,允许继承的子类同名同类型函数对父类虚函数进行函数重写
纯虚函数:当父类中虚函数被子类用来重写,且没有定义的意义,这个时候一般把父类的虚函数设置成纯虚函数,当子类对父类的虚函数重写时,且抽象类中无纯虚函数,即实例化成功,否则也是抽象类。
普通函数参数分为值传递和地址传递,值传递的参数值出了函数作用域后,空间收回无法影响实参值,地址传递是将地址传到函数中,能影响实参,但是需要额外申请指针大小的空间,所以在c++中引入的引用参数,由于引用与被引用的参数占同一片地址,所有既可以不另外申请空间,又能影响到原来的值,这样效率更高。当不想修改值时也可使用常引用。
联合体中变量占据空间各不相同,但是联合体中共同占用一块空间
结构体中每个成员也有独立的值,而联合体中修改一个成员的值也会修改到其他成员
结构体计算大小时满足字节对齐原则,而联合体中不是,主要看最大元素大小