【Qt | 入门】基础知识 day01

文章目录

  • Day01
    • Qt应用程序框架
      • 创建项目
      • 项目架构
      • 实例
    • 信号与槽
      • connect()函数
      • 自定义信号
      • 自定义槽函数
      • 使用Lamda表达式定义槽函数
    • 坐标系统
    • 内存回收机制
    • QMainWindow
    • 对话框
      • 标准对话框QMessageBox
      • 文件对话框QFileDialog

Day01

Qt应用程序框架

创建项目

创建项目时需要选择基类

【Qt | 入门】基础知识 day01_第1张图片

Qt窗口基类:QMainWindow、QWidget、QDialog。

QMainWindow是用于创建带菜单栏的PC端窗口的基类

QWidget是所有图形界面中控件的基类

QDialog是用于创建对话框的基类

 

项目架构

【Qt | 入门】基础知识 day01_第2张图片

.pro是项目文件。因为Qt选择的项目管理工具为qmake,qmake根据.pro文件存储的项目信息生成对应的Makefile,然后在使用make命令来编译项目文件

.pro是使用qmake语言编写的。每行#后的内容为注释;QT += core gui表示引入Qt库中的Core和Gui模块;greaterThan(QT_MAJOR_VERSION, 4): QT += widgets表示Qt版本大于4时引入Qt库中的Widgets模块**(在Qt5项目中添加了Widgets模块则无需再添加GUI模块)**;TARGET = test表示应用程序即生成的.exe文件名为test;TEMPLATE = app表示指定Makefile的类型可执行程序

指定源文件

SOURCES += \
    main.cpp \
    widget.cpp

指定头文件

HEADERS += \
    widget.h

Qt5的基本模块:Qt Widgets、Qt Webkit、Qt Test、Qt SQL、Qt Quick、Qt QML、Qt Mulitmedia Widgets、Qt Core、Qt GUI、Qt Network、Qt Mulitmedia、Qt Quick Controls、Qt Quick Dialogs

widget.h、widget.cpp、main.cpp都是项目自动生成的。其中widget.h和widget.cpp是实现控件的代码,继承于QWidget,创建时默认提供默认构造函数默认析构函数。main.cpp则同所有C++项目一样是程序的执行入口

widget.h文件创建时可能包括信号与槽的内容,等后面学习时再来理解

main.cpp

//引入头文件
#include "widget.h"	//窗口控件类
#include  //QApplication是Qt的应用程序类

int main(int argc, char *argv[])
{
    QApplication a(argc, argv); //QApplication应用程序类有且只能有一个实例化对象
    Widget w; //初始化窗口控件(默认隐藏)
    w.show(); //手动显示窗口控件
    return a.exec(); //a.exec()作用为使程序进入循环,等待事件发生。若为return 0,则程序只运行一次就直接结束
}

项目文件夹中可能还会存在.user文件,保存的是项目所有者用户的项目信息,包括项目编译的路径等。在使用他人的Qt项目或者更换编译环境时无法直接编译,需要先删除.user文件再进行编译

 

实例

新建一个空项目HelloQt,项目中只包含一个空的项目文件HelloQt.pro,添加内容QT += widgets

在项目中新建一个C++源文件main.cpp

#include 
#include  //窗口控件基类
#include  //按钮类

int main(int argc, char **argv)
{
    QApplication a(argc, argv);
    QWidget w;
    w.setWindowTitle("Hello QT Wolrd"); //设置窗口标题
    QPushButton b;
    b.setText("Hello~"); //设置按钮文本
    b.setParent(&w); //设置按钮的父对象
    b.move(100,100) //移动按钮到指定坐标,窗口左上角为零点
    QPushButton b1(&w); //通过构造函数传参指定父对象
    b1.setText("Wolrd~");
    w.show(); //显示窗口及子控件

    a.exec();
    return 0;
}

控件之间如果不指定父对象,则各个控件为独立的窗口,没有联系。指定父对象,子对象会显示在父对象的窗口内,当父对象执行show()函数时,子对象也会自动显示,不需要手动执行show()函数。

指定父对象的方法:

  1. 通过成员函数setParent(QWidget parent = nullptr)来指定控件的父对象
  2. 通过调用构造函数时传入父对象作为实参来指定控件的父对象

 

信号与槽

是Qt对象之间通信的接口

#include 
#include 

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QPushButton button("Quit");
    QObject::connect(&button, &QPushButton::clicked, &QApplication::quit);//连接函数
    button.show();

    return app.exec();
}

使用connect()函数来实现信号与槽的连接。在main函数中使用时,需要使用作用域限定符说明connect所属的类为QObject。QObject::connect();

connect()函数

原型:connect(sender, signal, receiver, slot);

作用:连接信号与槽,使指定的信号发生时,回调已连接的槽函数来处理信号

参数:

  • sender为QObject类型,是发送信号的控件指针。一般对发送者取引用来使用
  • signal发送信号指针,通过查询当前控件类的文档来得知有哪些信号类型,使用时需要作用域限定符指定所属的控件类。一般对信号取引用来使用
  • receiver为QObject类型,是接受信号的控件指针。一般对接受者取引用来使用
  • slot槽函数指针,也是需要查询文档选择槽函数,以及使用作用域限定符指定所属控件类。一般对槽函数取引用来使用

 

自定义信号

信号需要在类中用signals关键字来声明。signals是Qt的关键字,不是C++关键字

信号没有返回值,但可以有参数

信号可以重载

信号就是函数的声明,只需声明,无需定义

使用方法为emit mySignal();

 

相关代码实例

SubWidget.h

#include 
#include 

class SubWidget : public QWidget
{
public:
    void mySlot();
signals:
    void mySignal();
private:
    QPushButton b;
};

SubWidget.cpp

#include "SubWidget.h"

SubWidget::SubWidget(QWidget *parent) : QWidget(parent)
{
    b.setParent(this);
    connect(&b, &QPushButton::clicked, this, &SubWidget::mySlot);
}

SubWidget::mySlot()
{
    emit mySignal();//发送自定义信号
}

 

信号重载后,在使用connect函数时需要解决信号二义性的问题

conncet(&subWin, &SubWidget::mySignal, this, &MainWidget::mySlot1);
conncet(&subWin, &SubWidget::mySignal, this, &MainWidget::mySlot2);

解决方法:

  1. 使用函数指针代替信号作为实参

    void (SubWidget::*f1)() = &SubWidget::mySignal;
    connect(&subWin, f1, this, &MainWidget::mySlot1);
    void (SubWidget::*f2)(int, QString) = &SubWidget::mySignal;
    connect(&subWin, f2, this, &MainWidget::mySlot2);
    

    因为这里使用的是SubWidget类中定义的信号mySignal,所以函数指针需要添加SubWidget的作用域予以限定

  2. Qt4的信号连接

    class MainWidget : public QWidget
    {
    public slots:
        void mySlot1();
        void mySlot2(int, QString);
    };
    
    conncet(&subWin, SIGNAL(mySignal()), this, SLOT(mySLot1()));
    conncet(&subWin, SIGNAL(mySignal(int, QString)), this, SLOT(mySLot1(int, QString)));
    

    Qt4的槽函数必须用slots关键字修饰

    SIGNAL和SLOT两个宏会将信号和槽的函数名转换成字符串,不进行错误检查。当函数名出现错误时编译不会报错

 

自定义槽函数

自定义槽可以使用任意的成员函数、普通的全局函数、静态函数作为槽函数

槽函数的参数返回值需要和信号一致。因为信号没有返回值,所以槽函数也应该没有返回值。

一个信号可以绑定多个槽函数,多个信号也可以绑定一个槽函数

 

相关代码实例

MainWidget.h

#include 
#include 

class MainWidget : public QWidget
{
public:
    void mySlot();
private:
    QPushButton b;
}

MainWidget.cpp

#include "MainWidget.h"

MainWidget::MainWidget(QWidget *parent) : QWidget(parent)
{
    QPushButton b;
    b.setParent(this);
    connect(&b, &QPushButton::released, this, &MainWidget::mySlot);
}

void MainWodget::mySlot()
{
    b.setText("123");
}

 

使用Lamda表达式定义槽函数

因为Lamda表达式是C++11的新特性,所以需要才.pro项目文件中添加CONFIG += C++11

QPushButton *b = new QPushButton(this);
conncet(b4, &QPushButton::clicked, this,
        [](bool isChecked)
        {
            qDebug << isChecked;
        }
       );

信号QPushButton::clicked是有一个bool类型的参数checked的,且默认值为false,所以槽函数也需要有一个同样类型的参数isChecked传入Lamda表达式中

 

坐标系统

每个窗口或者控件的坐标是相对于父对象或者主屏幕而言的。对于没有父对象的窗口或者控件,其坐标位置是相对于主屏幕的;对于有父对象的窗口或者控件,其坐标位置是相对于父对象的

原点:主屏幕或父对象的左上角

x轴:以向右为正方向

y轴:以向下为正方向

 

内存回收机制

Qt维护着一个对象树,在程序结束时从下往上自动回收对象内存

在创建 QObject 对象时,可以提供一个其父对象,我们创建的这个QObject对象会自动添加到其父对象的children列表。当父对象析构的时候,这个列表中的所有对象也会被析构

在释放QObject对象时,如果该对象有父对象,则将该对象从其父对象中的children列表中删除;如果该对象有children列表,则自动释放列表中的所有对象

QWidget是能够在屏幕上显示的一切组件的父类。QWidget继承于QObject,因此也继承了这种对象树关系

 

QMainWindow

使用QMainWindow作为项目框架的基类进行开发

QMainWindow是Qt预设好的主窗口,QMainWindow继承于QWidget

一个QMainWindow窗口包括菜单栏工具栏停靠窗口状态栏中央窗口

#include "MyMainWindow.h"
#include 
#include 
#incldue <QAction>
#include 
#include 
#include 
#include 
#include 
#include 
#include 

MyMainWindow::MyMainWindow(QWidget *parent) : QMainWindow(parent)
{
    //菜单栏
    QMenuBar *mBar = menuBar();//获取菜单栏。QMainWindow自带菜单栏,不需要new新建 
    QMenu *pFile = mBar->addMenu("File");//添加菜单
    QAction *pNew = pFile->addAction("new");//添加菜单项,
    connect(pNew, &QAction::triggered, this,
           [=]()
           {
               qDebug() << "new done!";
           }
           );//通过信号将菜单项与具体实现连接起来
    pFile->addSeperator();//添加分割线
    
    //工具栏。是菜单项的快捷方式
    QToolBar *toolBar = addToolBar("toolBar");
    toolBar->addAction(pNew);//直接使用菜单项指针添加快捷键
    QPushButton *b = new QPushButton(this);//通过创建控件添加快捷键
    b->setText("^_^");//此行代码可以改为设置图片
    toolBar->addWidget(b);//将新建控件加入到工具栏中
    connect(b, &QPushButton::clicked, this
           [=]()
           {
               b->setText("123");
           }//通过信号将快捷键与具体实现连接起来
           );
    //状态栏
    QStatusBar *sBar = statusBar();//获取状态栏
    QLabel *label = new QLabel(this);//新建标签并指定父对象
    label->setText("Normal text file");//设置标签名字
    sBar->addWidget(label);//将标签添加到左下角状态栏,添加顺序为从左往后
    sBar->addPermanentWidget(label);//将标签添加到右下角状态栏,添加顺序为从左往后
    
    //中央窗口
    QTextEdit *textEdit = new QTextEdit(this);//新建文本窗口
    setCentralWidget(textEdit);//将文本窗口设置为中央窗口
    
    //停靠窗口(浮动窗口)
    QDockWidget *dock = new QDockWidget(this);//新建浮动窗口
    addDockWidget(Qt::RightDockWidgetArea, dock);//将浮动窗口添加到主窗口中。第一个参数是枚举类型,需要查看帮助文档,用于设置浮动窗口停靠的方向
    QTextEdit *tEdit = new QTextEdit(this);
    dock->setWidget(tEdit);
}

 

对话框

对话框分为模态对话框非模态对话框。模态对话框就是指除非对话框被关闭,否则不能和同一个应用程序的其他窗口及进行交互;非模态对话框就是指当对话框被打开时,用户既可以和对话框交互,也可以和同一应用程序中的其他窗口进行交互

显示一个对话框的方法:

  • 使用exec():它总是以模态来显示对话框。可以通过函数返回值判断用户退出对话框时点击的按钮

    QDialog dlg;
    dlg.exec();
    
  • 使用show():既能以模态显示,也能以非模态显示对话框。具体由对话框的modal属性决定

    QDialog dlg1, dlg2;
    //模态
    dlg1.setModal(true);
    dlg1.show();
    //非模态
    dlg2.setModal();
    dlg2.show();
    

对话框的modal属性:默认值为false,意思为非模态,此时show()函数显示的对话框是非模态的;若将值设置为true,意思为模态的,此时show()函数显示的对话框是模态的。modal属性的值可以通过对话框控件的成员函数setModal(bool)来改变,参数默认为false。

exec()阻塞的show()非阻塞的。当使用exec()显示对话框时,程序会阻塞在该函数直到返回;当使用show()显示对话框时,程序会按顺序继续执行下去。

由于show()是非阻塞的,如果将QDialog对象设置为局部变量,则会导致对话框生命周期太短,对话框只会闪烁一下即结束。所以需要使用new动态分配内存空间QDialog *dlg = new QDialog();。并且通过dlg->setAttribute(Qt::WA_DeleteOnClose);将对话框设置为关闭即释放内存,防止内存泄漏

 

标准对话框QMessageBox

需要头文件#include

标准对话框是模态对话框

可以通过QMessageBox的静态成员函数快速创建一个标准对话框:

  • QMessage::about(parent,title,text,);是关于对话框。参数parent指父对象,title指对话框的标题,text指对话框的文本内容,
  • QMessage::question(parent,title,text,buttons);是问题对话框。前三个参数同上,buttons想要使用的按钮集合,默认对话框上只有YES和NO两个按钮。返回值为StandButton类型,可以通过返回值判断用户退出对话框所按下的按钮

也可以手动配置对话框的各个属性:

QMessageBox msgBox;
msgBox.setWindowTitle("This is the Title");
msgBox.setText("This is the Text");
msgBox.setStandardButton(QMessageBox::OK | QMessageBox::Close);
msgBox.setDefaultButton(QMessageBox::OK);
msgBox.setAttribute(Qt::WA_DeleteOnClose);//避免内存泄漏
msg.exec();

 

文件对话框QFileDialog

需要头文件#include

文件对话框是用于操作文件的对话框

使用QFileDialog类的全局静态函数QFileDialog::getOpenFileName(parent,caption,dir,filter,selectedFilter,options);创建文件对话框。参数parent是指定父对象,caption是对话框标题,dir是打开对话框时的默认目录,filter是过滤器,selectedFilter是指定默认的过滤器,options是其他的一些枚举类型的参数。函数返回被选择文件的路径

其他静态函数QFileDialog::getSaveFileName();也可以创建文件对话框,返回值也是所选文件路径

你可能感兴趣的:(笔记总结,qt,开发语言,c++)