学习资料:零基础入门六天学会QT完整版https://www.bilibili.com/video/BV1t64y1f7d1
Qt安装时,如果安装包带MSVC,那么这个Qt是不带编译器的,因为它用的编译器就是VS
如果是mingw,则是自带编译器的
QT就是一个框架,包含很多模块
1.帮助文件:F1 (对于类的成员变量,如果成员函数有参数,需要先设定个参数,在按F1,才能跳到相应位置)
2..h文件和对应.cpp文件切换:F4
3.编译并运行:Ctrl + R
4.函数声明和定义(调用和定义)切换:移动到函数上按F2
5.代码注释及取消:Ctrl + /
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); // 设定固定成大小
如果一个类是:
1. 从QObject派生的类 直接/间接
2. 指定父类
那么这个类会被自动析构,父类被析构的时候子类也会被析构(比如关闭窗口时,窗口上的东西也会被析构)
按按键关闭窗口
connect(&b1, &QPushButton::clicked, this, &MyWidget::close);
#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(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);
但是信号触发后,槽函数的调用顺序是随机的
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类会有一个ui文件,可以在Qt中的设计里编辑,.h文件中会多一个指针
Ui::MainWindow *ui
如果在菜单中加入选项,设置功能也是通过信号与槽,输入ui->action后,action后会出现你添加的选项名(action和选项名之间没有空格),这个就是信号发送信号的对象,信号可以选&QAction::triggered
下面是一个按键叫new,功能是点击后输出一堆加号的示例代码,槽函数用的lambda函数
connect(ui->actionnew, &QAction::triggered, this, []()
{
qDebug() << "++++++++++++++++++++++++++";
} );