QT DAY2

(QT中记得修改时保存代码,否则有些资源会加载失败,被坑很多次了.....)

一、加载资源文件

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

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

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

 二、信号与槽机制(重点)

是QT中用来实现多个组件之间互相通信的机制

2.1信号与槽

信号:就是信号函数,是一个信号函数,定义在类体内signals权限下,是一个不完整的函数,只有声明没有定义,你不能直接调用它,只能通过emit关键字来触发

槽:就是槽函数,定义在类体的slots权限下,是一个完整的函数,既有声明也有定义,可以被当做普通函数被使用

槽声明了就得定义,但是信号不用,声明了不触发也可以,二者返回值一般都是void,参数可以自定义(参数的目的为了传信息)

2.2信号与槽的连接

ui界面下信号与槽的连接方式只能发射系统提供的信号,可使用系统提供的槽函数接收

也可右键转到槽,选择信号,槽函数骡子自己书写 

而连接函数分为多种形式

  • qt4版本的连接函数(该版本是不友好的连接,因为它即使错了也不会给你报错)
[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");
      });

2.3断开连接

断开信号与槽的连接时使用disconect

参数可不变

void Widget::on_btn6_clicked()
{
 
 
    disconnect(btn3, SIGNAL(pressed()), ui->btn1, SLOT(hide()));
 
 
    disconnect(ui->btn4, &QPushButton::clicked, this, &Widget::my_slot);
 
 
}

2.3发射自定义信号

使用emit 加自定义信号名即可发射,在与槽函数连接后,槽函数会立即响应

2.4信号与槽的案例——语音播报

先在初始配置文件中,添加TextToSpeech库

 头文件中记得加头文件,及定义一个播报指针

#ifndef WIDGET_H
#define WIDGET_H
 
 
#include <QWidget>
#include<QDebug>
#include<QPushButton>
#include<QTextToSpeech>          //文本转语音的头文件
 
 
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 <QApplication>

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 <QWidget>
#include <QLineEdit>
#include <QPushButton>
#include <QDebug>
#include <QIcon>
#include <QLineEdit>
#include <QLabel>
#include <QGraphicsOpacityEffect>
#include <QPropertyAnimation>
#include <QTextToSpeech>
#include <QFont>
#include <QString>
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

 2.5信号函数与槽函数的总结

一个信号函数发射出,多个相连接的槽函数都可执行

一个槽函数也可以同时响应多个与他连接的信号,只要一个信号被发射,该槽函数就会被执行

一个信号函数可以连接到另一个信号函数,一个被发射后一个也会被发射

信号与槽函数参数表为了传参有以下准则

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

1.多态,虚函数,纯虚函数

多态:允许对象以多种方式存在,而多态分为静态和动态,

静态多态就是函数重载/运算符重载和模板,是编译时多态,通过相同的函数名,不同的参数列表实现重载,模板就是提前假定一个类型进行,通过需要的类型传递后达成。

动态多态是运行时多态,主要是通过虚函数实现函数重写,父类的指针或者引用,指向或初始化子类的对象,调用子类对父类重写的函数,进而展开子类的功能。

虚函数:在动态多态中使用到,在函数前加上virtual关键字,父类中该函数是虚函数的话,允许继承的子类同名同类型函数对父类虚函数进行函数重写

纯虚函数:当父类中虚函数被子类用来重写,且没有定义的意义,这个时候一般把父类的虚函数设置成纯虚函数,当子类对父类的虚函数重写时,且抽象类中无纯虚函数,即实例化成功,否则也是抽象类。

2.将“引用”作为函数参数有哪些特点

普通函数参数分为值传递和地址传递,值传递的参数值出了函数作用域后,空间收回无法影响实参值,地址传递是将地址传到函数中,能影响实参,但是需要额外申请指针大小的空间,所以在c++中引入的引用参数,由于引用与被引用的参数占同一片地址,所有既可以不另外申请空间,又能影响到原来的值,这样效率更高。当不想修改值时也可使用常引用。

3.结构体和联合体有什么区别

联合体中变量占据空间各不相同,但是联合体中共同占用一块空间

结构体中每个成员也有独立的值,而联合体中修改一个成员的值也会修改到其他成员

结构体计算大小时满足字节对齐原则,而联合体中不是,主要看最大元素大小

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值