QT学习笔记01:Qt Creator使用,一个Qt Widget程序,信号与槽,QMainWindow类

学习资料:零基础入门六天学会QT完整版https://www.bilibili.com/video/BV1t64y1f7d1

Qt安装时,如果安装包带MSVC,那么这个Qt是不带编译器的,因为它用的编译器就是VS

如果是mingw,则是自带编译器的

QT就是一个框架,包含很多模块

Qt Creator常用快捷键:

1.帮助文件:F1  (对于类的成员变量,如果成员函数有参数,需要先设定个参数,在按F1,才能跳到相应位置)

2..h文件和对应.cpp文件切换:F4

3.编译并运行:Ctrl + R

4.函数声明和定义(调用和定义)切换:移动到函数上按F2

5.代码注释及取消:Ctrl + /

Qt类命名规范

1.类名:单词首字母大写,单词和单词之间直接连接,无需连接字符

2.函数名字,变量名:第一个单词首字母小写,其余单词首字母大写,也没有连接符

3.Qt中内置的类型,头文件和类命名同名,如

#include 
QString str;

基类

弹出来的第一个窗口,顶层窗口

QWidget:

所有窗口的父类,QMainWindow,QDialog也是由QWidget派生的,内容也最少,也用的最多

QMainWindow:

如果需要菜单栏,状态栏,工具栏,则要使用QMainWindow

QDialog:

如果只是弹出一个提示,一般右上角只有关闭按钮,则使用QDialog

pro文件的注释是加“#”

其余的配合第一个工程看P:\Qtexercise\lesson-day01\HelloQt

pro文件大部分只需要修改下面这一行,也就是告诉Qt用到什么模块

QT       += core gui

 类和main函数代码:

class MyWidget : public QWidget
{
    Q_OBJECT  // 宏,如果使用新号和槽,必须添加这个宏,一般都会加

public:
    MyWidget(QWidget *parent = 0);
    ~MyWidget();
};

#endif // MYWIDGET_H

一个Qt程序,需要一个应用程序类,以及一个窗口类,窗口类,创建出来默认不显示,需要show

int main(int argc, char *argv[])
{
    // QApplication应用程序类,每一个qt程序中有且只有一个,负责捕捉消息事件(如鼠标键盘),然后做默认的处理操作。比如鼠标多拽窗口
    QApplication a(argc, argv);
    // MyWidget一个窗口类,创建出来默认不显示,需要show
    MyWidget w;  // w表示整个窗口,也是顶层窗口
    // 显示窗口
    w.show();

    return a.exec();  // a.exec()检测事件,并进行处理,为什么打开窗口不会自动关闭,因为.exec()相当于一个死循环,通过一些事件,比如点窗口的叉,来停止对事件的监听
}

子窗口

如果窗口需要依附另外一个窗口,需要给该窗口指定父类,有两种方式:

// 第一种(这里b2定义的是指针,b1不是,不过两种方式不是说针对指针和非指针的)
b2 = new QPushButton("hello qt", this); //按F1查看QPushButton说明文档,发现带有
    //QWidget *parent,这里this也就是指MyWidget就是QPushButton想要依附的QWidget窗口
b2->show();  //这个show其实也没必要,因为父窗口显示的时候,子窗口也随之显示
// 第二种
b1.setParent(this);  // 另一种设置父类的方法
b1.setText("我是");

另外父窗口显示的时候,子窗口也随之显示。但是如果没有父窗口,则需要show

设置位置

如果不设置位置,子窗口显示在默认位置,子窗口之间会覆盖

// 改变位置 -- 移动
b1.move(100,100);  // 左上角是(0,0),坐标分别向右和向下递增
b1.resize(50,50);    // 调整窗口大小w, h

// 设置窗口标题
widget->setWindowTitle("窗口标题");
widget->resize(200,300);
widget->setFixedSize(200,300);  // 设定固定成大小

Qt内存自动回收机制

如果一个类是:

1. 从QObject派生的类 直接/间接

2. 指定父类

那么这个类会被自动析构,父类被析构的时候子类也会被析构(比如关闭窗口时,窗口上的东西也会被析构)

按按键关闭窗口

connect(&b1, &QPushButton::clicked, this, &MyWidget::close); 

QDebug包

#include 
qDebug() << "hello" <<;  // 注意引用和使用时大小写的区别

注意QDebug传入的是char,如果传入的是Qstring,需要把Qstring转换成char,如

qDebug() << num << str.toUtf8().data();

信号和槽

项目代码在本地的P:\Qtexercise\lesson-day01\SignalAndSlot下

// 需求: 点击b1关闭窗口
// 信号与槽之间连接的实现
// connect(信号发出者, 发出的信号, 信号接受者, 处理信号的槽函数) 
// 注意必须通过类对象来调用非静态函数,也就是close前要写&MyWidget::
connect(&b1, &QPushButton::clicked, this, &MyWidget::close);  //&MyWidget::close
/*
     * b1:信号的发出者,此参数是一个指针
     * &QPushButton::clicked:信号发出者内部的一个信号
     *      格式: & + 信号发出者类的名字 + :: + 信号的名字
     * this:信号的接受者,也是一个指针
     * &MyWidget::close:信号的处理函数
     * 注意发出和处理都是类::函数的形式,也没写括号
*/

qt 信号和槽他们都是函数

1.信号只有函数声明,不需要函数定义

2.槽函数需要声明,也需要定义,回调函数(并不是立即执行,而是需要条件,比如设置的点击)都是取函数的地址 

自定义槽函数

1.槽函数在Qt5中可以是任意类成员函数,全局函数,静态函数,lamda表达式(隐式函数,无函数名)

2.槽函数需要与信号对应(返回值,参数)

3.信号没有返回值,所以槽函数返回值:void

4.举例:

void mysig(int, double, QString);
void myslot(int, double, QString);

5.槽函数的参数是为了接受信号传过来的数据

6.槽函数的参数应该是不能够大于信号的参数个数,可以少于

7.信号可以连接信号,然后信号再连接槽函数,如信号A连接信号B(如果发送信号A,则由一个对象接收并发出信号B),信号B连接槽函数C,好比信号的转发

QPushButton类

QPushButton(const QIcon &icon, const QString &text, QWidget *parent = nullptr)

QPushButton(const QString &text, QWidget *parent = nullptr)

如果打算在当前继承自QWidget的窗口类下设置一个按钮,parent就是this

窗口之间如何嵌套

假如MainWidget是主窗口,现在有个窗口SubWidget,想让它作为主窗口的副窗口,就要把副窗口变成主窗口的成员变量

自定义信号

在类声明下的signals:中声明自定义信号函数以及在slots:中声明槽函数,可以通过在源文件中编写槽函数时,写入“emit 信号函数”来发送信号,也就是说自定义槽函数的作用就是发送信号

例子:P:\Qtexercise\lesson-day01\SignalAndSlot\SignalAndSlot\subwidget.h

signals:
    // 自定义信号,必须使用signals 声明
    void sigSub();
    /*
     * 自定义信号
     * 1.可以有参数
     * 2.可以重载
     * 3.返回值为void
     * 4.发送信号语法: emit + 信号名; 如emit sigSub
    */

public slots:
    // 自定义槽
    void myslot();
void SubWidget::myslot()
{
    // 发送信号
    emit sigSub();
}

重载的信号槽

信号,槽函数可以重载,但是connect时如何识别发过来的信号是哪个?通过函数指针

函数指针:

// 函数定义
int fn(int a, long b);
// 函数指针:函数返回值类型 (*指针名)(函数返回值) = 函数名
int (*fnnp)(int, long) = fn;
// 这样就构建了一个指向int fn(int a, long b)函数的指针fnnp

Qt例子

public:
    ...
    
    void slotShowMe();
    void slotSubMsg(int num, QString str);

// 调用时:
// 先定义了一个函数指针
void (SubWidget::*MySigSub)() = &SubWidget::sigSub;
// 使用函数指针作为信号
connect(&subW, MySigSub, this, &MainWidget::slotShowMe);
// 又定义了一个函数指针
void (SubWidget::*MySigplus)(int, QString) = &SubWidget::sigSub;
connect(&subW, MySigplus, this, &MainWidget::slotSubMsg);

一个信号可以连接多个槽函数

但是信号触发后,槽函数的调用顺序是随机的

Lambda表达式

C++11开始可以使用lambda表达式,需要在pro文件中加入

CONFIG += c++11

lambda 表达式的简单语法如下:[capture] (parameters) -> return value { body },只有 [capture] 捕获列表和 { body } 函数体是必选的,其他可选。

(如果要返回异常则要写成exception->返回值 {函数体})

变量捕获才是成就lambda卓越的秘方。

[] 不捕获任何变量,这种情况下lambda表达式内部不能访问外部的变量。只能用(parameters中的)
[&] 以引用方式捕获所有变量
[=] 用值的方式捕获所有变量(进行了拷贝)(可能被编译器优化为const &)
[=, &foo] 以引用捕获变量foo, 但其余变量都靠值捕获  // bar和foo都是对象名
[&, foo] 以值捕获foo, 但其余变量都靠引用捕获
[bar] 以值方式捕获bar; 不捕获其它变量
[this] 捕获所在类的this指针 (Qt中使用很多,如此lambda可以通过this访问界面控件的数据)

槽函数可以使用lambda表达式

QMainWindow类

创建QMainWindow类会有一个ui文件,可以在Qt中的设计里编辑,.h文件中会多一个指针

Ui::MainWindow *ui

如果在菜单中加入选项,设置功能也是通过信号与槽,输入ui->action后,action后会出现你添加的选项名(action和选项名之间没有空格),这个就是信号发送信号的对象,信号可以选&QAction::triggered

下面是一个按键叫new,功能是点击后输出一堆加号的示例代码,槽函数用的lambda函数

connect(ui->actionnew, &QAction::triggered, this, []()
{
    qDebug() << "++++++++++++++++++++++++++";
} );

你可能感兴趣的:(QT,qt,c++)