QT编程教程

1 Qt简介

跨平台图形界面引擎

优点:
a.跨平台
b.接口简单,容易上手
c.一定程度上简化了内存回收

2 创建第一个Qt程序

第一步:文件 --> New Project 或 创建项目

第二步: Application(Qt) --> Qt Widgets Application

 第三步:设置项目名称、保存路径

名称:不能有中文,不能有空格
路径:不能有中文路径

第四步:选择“qmake”

第五步:选择Bass Class,设置类名

默认创建有窗口类,基类有三种选择:QWidget、QMainWindow、QDialog

QWidget是父类,QMainWindow和QDialog继承QWidget;

QWidget创建完成后只有一个空窗口;

QMainWindow创建完成后有状态栏、菜单栏、工具、状态;

QWidget创建完成后是对话框;

第六步:选择默认Kit

第七步:编写代码

QApplication a 应用程序对象,有且仅有一个
myWidget w; 实例化窗口对象
w.show() 调用show函数,显示窗口
return a.exec() 让应用程序对象进入消息循环机制中,代码阻塞到当前行

3 按钮控件常用API

第一步:定位项目名右键“添加新文件”

第二步:C/C++ --> C++ Class

第三步:选择Bass Class,设置类名

第四步:完成

01_QtProject

第五步:编写代码

01_QtProject.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mypushbutton.cpp \
    mywidget.cpp

HEADERS += \
    mypushbutton.h \
    mywidget.h

FORMS += \
    mywidget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

mypushbutton.h

#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H

#include <QPushButton>

class MyPushButton : public QPushButton
{
    Q_OBJECT
public:
    //构造
    explicit MyPushButton(QWidget *parent = nullptr);
    //析构
    ~MyPushButton();
signals:
};

#endif // MYPUSHBUTTON_H

mypushbutton.cpp

#include "mypushbutton.h"
#include <QDebug>

MyPushButton::MyPushButton(QWidget *parent)
    : QPushButton{parent}
{
    qDebug() << "我的按钮类构造调用";
}

MyPushButton::~MyPushButton()
{
    qDebug() << "我的按钮类析构调用";
}

mywidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget> //包含头文件 QWidget 窗口类

QT_BEGIN_NAMESPACE
namespace Ui {
class MyWidget;
}
QT_END_NAMESPACE

class MyWidget : public QWidget
{
    Q_OBJECT //Q_OBJECT宏,允许类中使用信号和槽的机制

public:
    MyWidget(QWidget *parent = nullptr); //构造函数,有参构造
    ~MyWidget(); //析构函数

private:
    Ui::MyWidget *ui;
};
#endif // MYWIDGET_H

mywidget.cpp

#include "mywidget.h"
#include "ui_mywidget.h"
#include <QPushButton> //按钮控件的头文件
#include "mypushbutton.h"

//命名规范
//类名 首字母大写,单词和单词之间首字母大写
//函数名 变量名称 首字母小写,单词和单词之间首字母大写

//快捷键
//注释 ctrl+/
//运行 ctrl+r
//编译 ctrl+b
//字体缩放 ctrl+鼠标滚轮
//查找 ctrl+f
//整行移动 ctrl+shift+↑或者↓
//帮助文档 F1
//自动对齐 ctrl+i
//同名之间的.h和.cpp切换 F4

//

MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::MyWidget)
{
    ui->setupUi(this);
    //创建一个按钮
    QPushButton* btn = new QPushButton;
    //btn->show(); //show以循环方式弹出窗口控件
    //让btn对象 依赖在MyWidget窗口中
    btn->setParent(this);
    //显示文本
    btn->setText("第一个按钮");

    //创建第二个按钮 按照控件的大小创建窗口
    QPushButton* btn2 = new QPushButton("第二个按钮", this);
    //移动btn2按钮
    btn2->move(100,100);
    //设置按钮大小
    btn2->resize(200,200);


    //重置窗口大小
    resize(600,400); //可以拖动窗口改变大小
    //设置固定窗口大小
    setFixedSize(600,400); //设置后无法拖动窗口改变大小
    //设置窗口标题
    setWindowTitle("第一个窗口");



    //创建一个自己的按钮对象
    MyPushButton* myBtn = new MyPushButton;
    myBtn->setText("我自己的按钮");
    myBtn->move(300,0);
    myBtn->setParent(this);


    //需求 点击我的按钮 关闭窗口
    //connect(信号的发送者,发送的信号(函数的地址),信号的接收者,处理的槽函数)
    //connect(myBtn, &QPushButton::clicked, this, &MyWidget::close);
    connect(myBtn, &QPushButton::clicked, this, &QWidget::close);
}

MyWidget::~MyWidget()
{
    delete ui;
    qDebug() << "myWidget的析构调用";
}

main.cpp

#include "mywidget.h"

#include <QApplication> //包含一个应用程序类的头文件

//main程序入口  argc命令行变量的数量    argv命令行变量的数组
int main(int argc, char *argv[])
{
    //a应用程序对象,在Qt中,应用程序对象,有且仅有一个
    QApplication a(argc, argv);
    //窗口对象 MyWidget父类 -> QWidget
    MyWidget w;
    //窗口对象 默认不会显示,必须要调用show方法显示窗口
    w.show();

    //让应用程序对象进入消息循环
    //让代码阻塞到这行
    return a.exec();
}

运行结果

创建:QPushButton* btn = new QPushButton
设置父亲:setParent(this)
设置文本:setText("文字")
设置位置:move(宽,高)
重新指定窗口大小:resize(宽,高)
设置窗口标题:setWindowTitle("标题")
设置窗口固定大小:setFixedSize(宽,高)

4 对象树

当创建的对象在堆区间时候,如果指定的父亲是QObject派生下来的类或者QObject子类派生下来的类,可以不用管理释放的操作,将对象放入到对象树中

优点:一定程度上简化了内存回收机制

5 Qt中的坐标

左上角为0,0点
x以右为正方向
y以下为正方向

6 信号和槽

连接函数:connect(信号的发送者,发送的信号(函数地址),信号的接受者,处理的槽函数(函数地址))

松散耦合

点击按钮,关闭窗口:connect(btn, &QPushButton::click, this, &QWidget::close);

自定义信号:
普通函数,不需要实现(使用signals关键字声明)——只有函数声明
没有返回值,void类型函数
需要声明,不需要实现
可以有参数,可以重载

自定义槽函数:
返回void
需要声明,也需要实现
可以有参数,可以重载
写到public slot下,或者public,或者全局函数

当自定义信号和槽出现重载:
需要利用函数指针,明确指向函数的地址
void(Teacher::*tSignal)(QString)=&Teacher::hungry;
QString转成char*:.ToUtf8()转为QByteArray、.Data()转为char*
信号可以连接信号
断开信号disconnect

拓展:
信号可以连接信号
一个信号可以连接多个槽函数
多个信号可以连接同一个槽函数
信号和槽函数的参数,必须类型一一对应
信号的参数个数,可以多余槽函数的参数个数
信号槽可以断开连接disconnect

Qt4版本写法:
connect(信号的发送者,发送的信号 SIGNAL(信号),信号接受者,槽函数 SLOT(槽函数))
优点:参数直观
缺点:编译器不会检测参数类型


lambda表达式:
[]标识符 匿名函数、=值传递、&引用传递
()参数
{}实现体
mutable修饰值传递变量,可以修改拷贝出的数据,改变不了主体
返回值 []()->int{}

02_SignalAndSlot信号和槽

02_SignalAndSlot.por

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    student.cpp \
    teacher.cpp \
    widget.cpp

HEADERS += \
    student.h \
    teacher.h \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

student.h

#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

class Student : public QObject
{
    Q_OBJECT
public:
    explicit Student(QObject *parent = nullptr);

signals:

public slots:
    //自定义槽函数,写在public slots下
    //返回void
    //需要声明,也需要实现
    //可以有参数,可以重载
    void treat();
    //重载
    void treat(QString foodName);
};

#endif // STUDENT_H

student.cpp

#include "student.h"
#include <QDebug>

Student::Student(QObject *parent)
    : QObject{parent}
{}

void Student::treat()
{
    qDebug() << "请老师吃饭";
}

void Student::treat(QString foodName)
{
    //直接使用foodName,输出的foodName有双引号"",去除双引号QString->char*
    //QString->char*:先将QString转成QByteArray(.toUtf8()),再转char*()
    qDebug() << "请老师吃饭,老师要吃:" << foodName.toUtf8().data();
}

teacher.h

#ifndef TEACHER_H
#define TEACHER_H

#include <QObject>

class Teacher : public QObject
{
    Q_OBJECT
public:
    explicit Teacher(QObject *parent = nullptr);

signals:
    //自定义信号 写到signals下
    //返回值是void,只需要声明,不需要实现
    //可以有参数,可以重载
    void hungry();
    void hungry(QString foodName);

public slots:

};

#endif // TEACHER_H

teacher.cpp

#include "teacher.h"

Teacher::Teacher(QObject *parent)
    : QObject{parent}
{}

//重载不需要实现

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "teacher.h"
#include "student.h"

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    void classIsOver();
    void classIsOver(QString foodName);

private:
    Ui::Widget *ui;

    Teacher* zt;
    Student* st;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>

//Teacher 类 老师类
//Student 类 学生类
//下课后,老师会触发一个信号,饿了,学生响应信号,请客吃饭

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    
    //创建一个老师对象
    this->zt = new Teacher(this);
    //创建一个学生对象
    this->st = new Student(this);
    
    //老师饿了,学生请客的连接
    //connect(zt, &Teacher::hungry, st, &Student::treat);
    
    //调用下课函数
    //classIsOver();

    //连接不带参数的信号和槽
    void(Teacher::*teacherSignal1)(void) = &Teacher::hungry;
    void(Student::*studentSlot1)(void) = &Student::treat;
    connect(zt, teacherSignal1, st, studentSlot1);
    classIsOver();

    //连接带参数的 信号和槽
    void(Teacher::*teacherSignal2)(QString) = &Teacher::hungry;
    void(Student::*studentSlot2)(QString) = &Student::treat;
    connect(zt, teacherSignal2, st, studentSlot2);
    classIsOver("宫保鸡丁");

    //点击一个下课的按钮,再触发下课
    QPushButton* btn1 = new QPushButton("下课1", this);
    //点击按钮,触发下课
    void(Widget::*classIsOverSlot1)( ) = &Widget::classIsOver;
    connect(btn1, &QPushButton::clicked, this, classIsOverSlot1);

    //断开信号
    disconnect(zt, teacherSignal2, st, studentSlot2);
    disconnect(btn1, &QPushButton::clicked, this, classIsOverSlot1);

    //拓展
    //1、信号是可以连接信号
    //2、一个信号可以连接多个槽函数
    //3、多个信号 可以连接 同一个槽函数
    //4、信号和槽函数的参数必须类型一一对应
    //5、信号的参数个数 可以多余槽函数的参数个数


    //Qt4版本以前的信号和槽连接方式
    //利用Qt4信号槽 连接无参版本
    //Qt4版本 底层SIGNAL("hungry")  SLOT("treat")
    connect(zt, SIGNAL(hungry()), st, SLOT(treat()));
    //Qt4版本优点:参数直观;缺点:类型不做检测
    //Qt5以上支持Qt4的版本写法,反之不支持



    //lambda表达式
    mutable关键字,用于修饰值传递的变量,修改的是拷贝,而不是实体
    QPushButton* myBtn1 = new QPushButton("按钮1", this);
    QPushButton* myBtn2 = new QPushButton("按钮2", this);
    myBtn1->move(300,0);
    myBtn2->move(300,100);
    int m=10;
    connect(myBtn1, &QPushButton::clicked, this, [m]() mutable { m=100+10; qDebug()<<m;});
    qDebug()<<m;
    connect(myBtn2, &QPushButton::clicked, this, [=]() mutable { qDebug()<<m;});
    qDebug()<<m;

    QPushButton* closeBtn = new QPushButton("关闭",this);
    closeBtn->move(300,200);
    connect(closeBtn, &QPushButton::clicked, this, [](){
        this->close();
    });


    //重置窗口大小
    this->resize(600, 400);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::classIsOver()
{
    //下课函数,调用后触发老师饿了
    emit zt->hungry();
}

void Widget::classIsOver(QString foodName)
{
    emit zt->hungry(foodName);
}

main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}


7 QMainWindow

1.菜单栏,最多有一个
QMenuBar* bar = new MenuBar();
设置到窗口中 setMenuBar(bar)
QMenu* fileMenu = bar->addMenu("文件");    //创建菜单
QAction* newAction = fileMenu->addAction("新建");    //创建菜单项
添加分割线 fileMenu->addSeparator();

2.工具栏,可以有多个
QToolBar* toolBar = new QToolBar(this);
addToolBar(默认停靠区域,toolBar);        //Qt::LeftToolBarArea
设置后期停靠区域,设置浮动,设置移动
添加菜单项,或者添加小控件

3.状态栏,最多一个
QStatusBar* stBar = new QStatusBar();
设置到窗口中 setStatuasBar(stBar);
setBar->addWidget(label);        //放左侧信息
setBar->addPermanentWidget(label2);    //放右侧信息

4.铆接部件 浮动窗口 可以多个
QDockWidget
addDockWidget(默认停靠区域,浮动窗口指针)
设置后期停靠区域

5.设置核心部件 只能一个

03_MainWindow

03_MainWindow.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMenuBar>
#include <QToolBar>
#include <QPushButton>
#include <QStatusBar>
#include <QLabel>
#include <QDockWidget>
#include <QTextEdit>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //重置窗口大小
    resize(600,400);

    //菜单栏 最多只能有一个
    //菜单栏创建
    QMenuBar* bar = menuBar();
    //将菜单栏放入到窗口中
    setMenuBar(bar);
    //创建菜单
    QMenu* fileMenu = bar->addMenu("文件");
    QMenu* openMenu = bar->addMenu("编辑");

    //创建菜单项
    QAction* newAction = fileMenu->addAction("新建");
    QAction* openAction = fileMenu->addAction("打开");
    //添加分割线
    fileMenu->addSeparator();
    QAction* saveAction = fileMenu->addAction("保存");

    //工具栏,可以有多个,工具栏默认可以移动,上下左右都可以停靠;工具栏默认可以浮动
    QToolBar* toolBar = new QToolBar(this);
    //工具栏默认在上面
    //addToolBar(toolBar);
    //工具栏放在左侧
    addToolBar(Qt::LeftToolBarArea, toolBar);
    //只允许左右停靠
    toolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
    //设置浮动
    toolBar->setFloatable(false);
    //设置移动
    toolBar->setMovable(false);

    //工具栏中可以设置内容
    toolBar->addAction(newAction);
    toolBar->addAction(openAction);
    //添加分割线
    toolBar->addSeparator();
    toolBar->addAction(saveAction);

    //工具栏中添加控件
    QPushButton* btn = new QPushButton("aaa", this);
    toolBar->addWidget(btn);



    //状态栏,最多只有一个
    QStatusBar* staBar = new QStatusBar();
    //设置到窗口
    setStatusBar(staBar);
    //放标签控件
    QLabel* label1 = new QLabel("提示信息", this);
    staBar->addWidget(label1);
    QLabel* label2 = new QLabel("右侧提示信息", this);
    staBar->addPermanentWidget(label2);
    //浮动窗口 可以有多个
    QDockWidget* dockWidget = new QDockWidget("浮动窗口", this);
    this->addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
    //设置后期停靠区域,只允许上下
    dockWidget->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);




    //设置中心部件,最多只能有一个
    QTextEdit* edit = new QTextEdit(this);
    this->setCentralWidget(edit);
}

MainWindow::~MainWindow()
{
    delete ui;
}

main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

运行结果

8 资源文件

04_QtSource

04_QtSource.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

QAction无法在ui中直接输入中文,输入new后,会生成actionnew,可以在属性中修改text为“新建”;QAction右键可以“添加分隔符”,分隔符插入后可以拖拽;

可以拖动下窗口的action放到toolbar中;toolbar可以右键添加分隔符

铆接部件,可以设置是否浮动,设置停靠位置

action可以设置图标

第一步:将图片文件 拷贝到项目位置下

第二步:右键项目 --> 添加新文件

第三步:Qt --> Qt Resource File

第四步:给资源文件起别名,res生成 res.qrc

第六步:open in editor 编辑资源

第七步:添加前缀 添加文件

第八步:使用":+前缀名+文件名"

04_QtSource.pro

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>600</width>
    <height>400</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QTextEdit" name="textEdit">
    <property name="geometry">
     <rect>
      <x>0</x>
      <y>0</y>
      <width>501</width>
      <height>321</height>
     </rect>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>600</width>
     <height>25</height>
    </rect>
   </property>
   <widget class="QMenu" name="menu">
    <property name="title">
     <string>文件</string>
    </property>
    <addaction name="actionnew"/>
    <addaction name="separator"/>
    <addaction name="actionopen"/>
   </widget>
   <widget class="QMenu" name="menu_2">
    <property name="title">
     <string>编辑</string>
    </property>
   </widget>
   <addaction name="menu"/>
   <addaction name="menu_2"/>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
  <widget class="QToolBar" name="mainToolBar">
   <property name="windowTitle">
    <string>toolBar</string>
   </property>
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
   <addaction name="actionnew"/>
   <addaction name="separator"/>
   <addaction name="actionopen"/>
  </widget>
  <widget class="QDockWidget" name="dockWidget">
   <attribute name="dockWidgetArea">
    <number>1</number>
   </attribute>
   <widget class="QWidget" name="dockWidgetContents"/>
  </widget>
  <action name="actionnew">
   <property name="text">
    <string>新建</string>
   </property>
  </action>
  <action name="actionopen">
   <property name="text">
    <string>打开</string>
   </property>
  </action>
 </widget>
 <resources/>
 <connections/>
</ui>

mianwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //ui->actionNew->setIcon(QIcon("D://Image//actionNew.png"));

    //使用添加Qt资源 ":+前缀名+文件名"
    ui->actionnew->setIcon(QIcon(":/Image/new.jpg"));
    ui->actionopen->setIcon(QIcon(":/Image/open.jpg"));
}

MainWindow::~MainWindow()
{
    delete ui;
}

main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>600</width>
    <height>400</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QTextEdit" name="textEdit">
    <property name="geometry">
     <rect>
      <x>0</x>
      <y>0</y>
      <width>501</width>
      <height>321</height>
     </rect>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>600</width>
     <height>25</height>
    </rect>
   </property>
   <widget class="QMenu" name="menu">
    <property name="title">
     <string>文件</string>
    </property>
    <addaction name="actionnew"/>
    <addaction name="separator"/>
    <addaction name="actionopen"/>
   </widget>
   <widget class="QMenu" name="menu_2">
    <property name="title">
     <string>编辑</string>
    </property>
   </widget>
   <addaction name="menu"/>
   <addaction name="menu_2"/>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
  <widget class="QToolBar" name="mainToolBar">
   <property name="windowTitle">
    <string>toolBar</string>
   </property>
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
   <addaction name="actionnew"/>
   <addaction name="separator"/>
   <addaction name="actionopen"/>
  </widget>
  <widget class="QDockWidget" name="dockWidget">
   <attribute name="dockWidgetArea">
    <number>1</number>
   </attribute>
   <widget class="QWidget" name="dockWidgetContents"/>
  </widget>
  <action name="actionnew">
   <property name="text">
    <string>新建</string>
   </property>
  </action>
  <action name="actionopen">
   <property name="text">
    <string>打开</string>
   </property>
  </action>
 </widget>
 <resources/>
 <connections/>
</ui>

9 对话框

分类:模态对话框、非模态对话框

模态对话框:不可以对其他窗口进行操作,阻塞
QDialog dlg1(this);
dlg1.exec();

非模态对话框:可以对其他窗口进行操作
防止一闪而过,创建到堆区
QDialog* dlg2 = new QDialog(this);
dlg2->show();
dlg2->setAttribute(Qt::WA_DeleteOnClose);

消息对话框:
QMessageBox静态成员函数,创建对话框
错误、信息、提问、警告
提问对话框参数:参数1:父亲;参数2:标题;参数3:提示内容;参数4:按键类型;参数5:默认关联回车的按键
返回值也是StandardButton类型,利用返回值判断用户的输入

颜色对话框 QColorDialog::getColor

文件对话框 QFileDialog::getOpenFileName(父亲,标题,默认路径,过滤,文件)

字体对话框 QFontDialog::getFont

05_QDialog.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDialog>
#include <QDebug>
#include <QMessageBox>
#include <QColorDialog>
#include <QFileDialog>
#include <QFontDialog>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //点击新建按钮,弹出一个对话框
    connect(ui->actionnew, &QAction::triggered, [this](){
        //对话框分类:模态对话框(不可以对其他窗口进行操作)、非模态对话框(可以对其他窗口进行操作)

        //创建模态对话框
        //模态对话框有阻塞的功能
        QDialog dlg1(this);
        dlg1.resize(200,100);
        dlg1.exec();
        qDebug() << "模态对话框弹出了";

        //创建非模态对话框
        QDialog* dlg2 = new QDialog(this);
        dlg2->resize(100,100);
        dlg2->show();
        dlg2->setAttribute(Qt::WA_DeleteOnClose);
        qDebug() << "非模态对话框弹出来了";

        //消息对话框(错误)
        QMessageBox::critical(this, "critical", "错误");

        //消息对话框(信息)
        QMessageBox::information(this, "info", "信息");

        //消息对话框(提问)
        //参数1:父亲;参数2:标题;参数3:提示内容;参数4:按键类型;参数5:默认关联回车的按键
        int res = QMessageBox::question(this, "question", "提问", QMessageBox::Save|QMessageBox::Cancel, QMessageBox::Cancel);
        if (res == QMessageBox::Save){
            qDebug() << "选择的是保存";
        }
        else{
            qDebug() << "选择的是取消";
        }

        //消息对话框(警告)
        QMessageBox::warning(this, "warning", "警告");

        //颜色对话框
        QColor color = QColorDialog::getColor(QColor(255,0,0));
        qDebug() << "r = " << color.red() << " g = " << color.green()
                 << " b = " << color.blue();


        //文件对话框
        //参数1:父亲;参数2:标题;参数3:默认打开路径;参数4:过滤文件格式
        //返回值是 选取的路径
        QString sFile = QFileDialog::getOpenFileName(this, "打开文件", "D://Desktop", "(*.txt)");
        qDebug() << sFile;

        //字体对话框
        bool flag = false;
        QFont font = QFontDialog::getFont(&flag, QFont("宋体", 36), this, "选择字体");
        qDebug() << "字体:" << font.family().toUtf8().data() << ",字号:" << font.pointSize()
                 << ",是否加粗:" << font.bold() << ",是否倾斜:" << font.italic();

    });
}

MainWindow::~MainWindow()
{
    delete ui;
}

main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget"/>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>25</height>
    </rect>
   </property>
   <widget class="QMenu" name="menu">
    <property name="title">
     <string>文件</string>
    </property>
    <addaction name="actionnew"/>
    <addaction name="separator"/>
    <addaction name="actionopen"/>
   </widget>
   <widget class="QMenu" name="menu_2">
    <property name="title">
     <string>新建</string>
    </property>
   </widget>
   <addaction name="menu"/>
   <addaction name="menu_2"/>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
  <widget class="QToolBar" name="toolBar">
   <property name="windowTitle">
    <string>toolBar</string>
   </property>
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
   <addaction name="actionnew"/>
   <addaction name="separator"/>
   <addaction name="actionopen"/>
  </widget>
  <action name="actionnew">
   <property name="text">
    <string>新建</string>
   </property>
  </action>
  <action name="actionopen">
   <property name="text">
    <string>打开</string>
   </property>
  </action>
 </widget>
 <resources/>
 <connections/>
</ui>

10 界面布局

实现登陆窗口
利用布局方式给窗口进行美化
选取widget进行布局,水平布局、垂直布局、栅格布局
给用户名、密码、登陆、退出按钮进行布局
默认窗口和控件之间有9间隙,可以调整layoutLeftMargin
利用弹簧进行布局

弹簧默认是Expanding,可以设置默认值Fixed。

06_Layout.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="minimumSize">
   <size>
    <width>400</width>
    <height>300</height>
   </size>
  </property>
  <property name="maximumSize">
   <size>
    <width>400</width>
    <height>300</height>
   </size>
  </property>
  <property name="windowTitle">
   <string>登陆窗口</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <spacer name="verticalSpacer">
      <property name="orientation">
       <enum>Qt::Orientation::Vertical</enum>
      </property>
      <property name="sizeHint" stdset="0">
       <size>
        <width>20</width>
        <height>40</height>
       </size>
      </property>
     </spacer>
    </item>
    <item>
     <widget class="QWidget" name="widget" native="true">
      <layout class="QHBoxLayout" name="horizontalLayout_3">
       <item>
        <spacer name="horizontalSpacer_5">
         <property name="orientation">
          <enum>Qt::Orientation::Horizontal</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>40</width>
           <height>20</height>
          </size>
         </property>
        </spacer>
       </item>
       <item>
        <widget class="QLabel" name="label">
         <property name="text">
          <string>用户名:</string>
         </property>
        </widget>
       </item>
       <item>
        <widget class="QLineEdit" name="lineEdit"/>
       </item>
       <item>
        <spacer name="horizontalSpacer_6">
         <property name="orientation">
          <enum>Qt::Orientation::Horizontal</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>40</width>
           <height>20</height>
          </size>
         </property>
        </spacer>
       </item>
      </layout>
     </widget>
    </item>
    <item>
     <widget class="QWidget" name="widget_2" native="true">
      <layout class="QHBoxLayout" name="horizontalLayout_4">
       <item>
        <spacer name="horizontalSpacer_3">
         <property name="orientation">
          <enum>Qt::Orientation::Horizontal</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>40</width>
           <height>20</height>
          </size>
         </property>
        </spacer>
       </item>
       <item>
        <widget class="QLabel" name="label_2">
         <property name="text">
          <string>密   码:</string>
         </property>
        </widget>
       </item>
       <item>
        <widget class="QLineEdit" name="lineEdit_2">
         <property name="echoMode">
          <enum>QLineEdit::EchoMode::Password</enum>
         </property>
        </widget>
       </item>
       <item>
        <spacer name="horizontalSpacer_4">
         <property name="orientation">
          <enum>Qt::Orientation::Horizontal</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>40</width>
           <height>20</height>
          </size>
         </property>
        </spacer>
       </item>
      </layout>
     </widget>
    </item>
    <item>
     <spacer name="verticalSpacer_3">
      <property name="orientation">
       <enum>Qt::Orientation::Vertical</enum>
      </property>
      <property name="sizeType">
       <enum>QSizePolicy::Policy::Fixed</enum>
      </property>
      <property name="sizeHint" stdset="0">
       <size>
        <width>20</width>
        <height>40</height>
       </size>
      </property>
     </spacer>
    </item>
    <item>
     <widget class="QWidget" name="widget_3" native="true">
      <layout class="QHBoxLayout" name="horizontalLayout_5">
       <item>
        <spacer name="horizontalSpacer">
         <property name="orientation">
          <enum>Qt::Orientation::Horizontal</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>40</width>
           <height>20</height>
          </size>
         </property>
        </spacer>
       </item>
       <item>
        <widget class="QPushButton" name="pushButton_2">
         <property name="text">
          <string>退出</string>
         </property>
        </widget>
       </item>
       <item>
        <spacer name="horizontalSpacer_7">
         <property name="orientation">
          <enum>Qt::Orientation::Horizontal</enum>
         </property>
         <property name="sizeType">
          <enum>QSizePolicy::Policy::Fixed</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>40</width>
           <height>20</height>
          </size>
         </property>
        </spacer>
       </item>
       <item>
        <widget class="QPushButton" name="pushButton">
         <property name="text">
          <string>登陆</string>
         </property>
        </widget>
       </item>
       <item>
        <spacer name="horizontalSpacer_2">
         <property name="orientation">
          <enum>Qt::Orientation::Horizontal</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>40</width>
           <height>20</height>
          </size>
         </property>
        </spacer>
       </item>
      </layout>
     </widget>
    </item>
    <item>
     <spacer name="verticalSpacer_2">
      <property name="orientation">
       <enum>Qt::Orientation::Vertical</enum>
      </property>
      <property name="sizeHint" stdset="0">
       <size>
        <width>20</width>
        <height>40</height>
       </size>
      </property>
     </spacer>
    </item>
   </layout>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

11 控件

1 按钮组

QPushButton 常用按钮;
QToolButton 工具按钮,用于显示图片,如想显示文字,需修改风格toolButtonStyle,凸起风格autoRaise;
radioButton 单选按钮,设置默认 ui->radioButton->setChecked(true);
checkbox多选按钮,监听状态,2是选中,1是半选,0是未选中

2 QListWidget 列表容器

QListWidgetItem *item = new QListWidgetItem("一行内容");
ui->listWidget->addItem(item);
设置居中方式 item->setTextAlignment(Qt::AlignHCenter);
可以利用addItems一次性添加多个item

3 QTreeWidget 树控件

设置头 ui->treeWidget->setHeaderLabels(QStringList() << "英雄" << "英雄介绍");
创建根节点 QTreeWidgetItem* liItem = new QTreeWidgetItem(QStringList() << "力量");
添加根节点到树控件上 ui->treeWidget->addTopLevelItem(liItem);
添加子节点 liItem->addChild(li1);

4 QTableWidget 表格控件

设置列数 ui->tableWidget->setColumnCount(3);
设置水平表头 ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "姓名" << "性别" << "年龄");
设置行数 ui->tableWidget->setRowCount(5);
设置正文 ui->tableWidget->setItem(i, 0, new QTableWidgetItem(nameList[i]));
 

07_Qt_Control

07_Qt_Control.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
    src.qrc

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //设置单选按钮,男 默认选中
    ui->radioButtonMan->setChecked(true);

    //选中 女 后,打印信息
    connect(ui->radioButtonWoman, &QRadioButton::clicked, [=](){
        qDebug() << "选中了女";
    });

    //多选按钮 2是选择 0是未选中 1是半选状态(需设置checkBox的tristate)
    connect(ui->checkBox, &QCheckBox::stateChanged, [=](int state){
        qDebug() << state;
    });


    //利用listWidget写诗
    QListWidgetItem* item1 = new QListWidgetItem("锄禾日当午");
    //将一行诗放入到listWidget控件中
    ui->listWidget->addItem(item1);
    //设置对齐方式
    item1->setTextAlignment(Qt::AlignHCenter);
    QListWidgetItem* item2 = new QListWidgetItem("汗滴禾下土");
    ui->listWidget->addItem(item2);
    QListWidgetItem* item3 = new QListWidgetItem("谁之盘中餐");
    ui->listWidget->addItem(item3);
    QListWidgetItem* item4 = new QListWidgetItem("粒粒皆辛苦");
    ui->listWidget->addItem(item4);

    //QStringList   QList<QString>
    QStringList list;
    list << "鹅鹅鹅" << "曲项向天歌" << "白毛浮绿水" << "红掌拨清波";
    ui->listWidget->addItems(list);


    //treeWidget树控件使用
    //设置水平头
    ui->treeWidget->setHeaderLabels(QStringList() << "英雄" << "英雄介绍");
    QTreeWidgetItem* liItem = new QTreeWidgetItem(QStringList() << "力量");
    //加载顶层的节点
    ui->treeWidget->addTopLevelItem(liItem);
    QTreeWidgetItem* minItem = new QTreeWidgetItem(QStringList() << "敏捷");
    ui->treeWidget->addTopLevelItem(minItem);
    QTreeWidgetItem* zhiItem = new QTreeWidgetItem(QStringList() << "智力");
    ui->treeWidget->addTopLevelItem(zhiItem);

    //追加子节点
    QTreeWidgetItem* li1 = new QTreeWidgetItem(QStringList() << "刚被猪" << "前排坦克,能在吸收伤害的同时造成可观的范围输出");
    liItem->addChild(li1);
    QTreeWidgetItem* li2 = new QTreeWidgetItem(QStringList() << "船长" << "前排坦克,能肉能控场的全能英雄");
    liItem->addChild(li2);
    QTreeWidgetItem* min1 = new QTreeWidgetItem(QStringList() << "月骑" << "中排物理输出,可以使用分裂利刃攻击多个目标");
    minItem->addChild(min1);
    QTreeWidgetItem* min2 = new QTreeWidgetItem(QStringList() << "小鱼人" << "前排战士,擅长偷取敌人的属性来增强自身战力");
    minItem->addChild(min2);
    QTreeWidgetItem* zhi1 = new QTreeWidgetItem(QStringList() << "死灵法师" << "前排法师坦克,魔法抗性较高,拥有治疗技能");
    zhiItem->addChild(zhi1);
    QTreeWidgetItem* zhi2 = new QTreeWidgetItem(QStringList() << "巫医" << "后排辅助法师,可以使用奇特的巫术诅咒敌人与治疗队友");
    zhiItem->addChild(zhi2);

    //TableWidget 表格控件
    //设置列数
    ui->tableWidget->setColumnCount(3);
    //设置水平表头
    ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "姓名" << "性别" << "年龄");
    //设置行数
    ui->tableWidget->setRowCount(5);
    //设置正文
    QStringList nameList;
    nameList << "张三" << "李四" << "王五";
    QStringList sexList;
    sexList << "男" << "女" << "男";
    for (int i=0;i<3;i++){
        ui->tableWidget->setItem(i, 0, new QTableWidgetItem(nameList[i]));
        ui->tableWidget->setItem(i, 1, new QTableWidgetItem(sexList[i]));
        //int 转 QString
        ui->tableWidget->setItem(i, 2, new QTableWidgetItem(QString::number(i+10)));
    }

}

Widget::~Widget()
{
    delete ui;
}

main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

widget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>794</width>
    <height>531</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <widget class="QPushButton" name="pushButton">
   <property name="geometry">
    <rect>
     <x>40</x>
     <y>30</y>
     <width>93</width>
     <height>28</height>
    </rect>
   </property>
   <property name="text">
    <string>登陆</string>
   </property>
  </widget>
  <widget class="QToolButton" name="toolButton">
   <property name="geometry">
    <rect>
     <x>50</x>
     <y>100</y>
     <width>71</width>
     <height>51</height>
    </rect>
   </property>
   <property name="text">
    <string>新建</string>
   </property>
   <property name="icon">
    <iconset resource="src.qrc">
     <normaloff>:/Image/new.jpg</normaloff>:/Image/new.jpg</iconset>
   </property>
   <property name="toolButtonStyle">
    <enum>Qt::ToolButtonStyle::ToolButtonTextUnderIcon</enum>
   </property>
  </widget>
  <widget class="QGroupBox" name="groupBox">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>180</y>
     <width>67</width>
     <height>96</height>
    </rect>
   </property>
   <property name="title">
    <string>性别</string>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <widget class="QRadioButton" name="radioButtonMan">
      <property name="text">
       <string>男</string>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QRadioButton" name="radioButtonWoman">
      <property name="text">
       <string>女</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QGroupBox" name="groupBox_2">
   <property name="geometry">
    <rect>
     <x>90</x>
     <y>180</y>
     <width>81</width>
     <height>96</height>
    </rect>
   </property>
   <property name="title">
    <string>婚否</string>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout_2">
    <item>
     <widget class="QRadioButton" name="radioButton_3">
      <property name="text">
       <string>已婚</string>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QRadioButton" name="radioButton_4">
      <property name="text">
       <string>未婚</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QGroupBox" name="groupBox_3">
   <property name="geometry">
    <rect>
     <x>190</x>
     <y>20</y>
     <width>122</width>
     <height>156</height>
    </rect>
   </property>
   <property name="title">
    <string>问卷调查</string>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout_3">
    <item>
     <widget class="QCheckBox" name="checkBox">
      <property name="text">
       <string>价格实惠</string>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QCheckBox" name="checkBox_2">
      <property name="text">
       <string>口感好</string>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QCheckBox" name="checkBox_3">
      <property name="text">
       <string>服务到位</string>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QCheckBox" name="checkBox_4">
      <property name="text">
       <string>老板娘好</string>
      </property>
      <property name="tristate">
       <bool>true</bool>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QDialogButtonBox" name="buttonBox">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>290</y>
     <width>193</width>
     <height>28</height>
    </rect>
   </property>
   <property name="standardButtons">
    <set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
   </property>
  </widget>
  <widget class="QListWidget" name="listWidget">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>330</y>
     <width>256</width>
     <height>192</height>
    </rect>
   </property>
  </widget>
  <widget class="QTreeWidget" name="treeWidget">
   <property name="geometry">
    <rect>
     <x>330</x>
     <y>10</y>
     <width>401</width>
     <height>211</height>
    </rect>
   </property>
   <column>
    <property name="text">
     <string notr="true">1</string>
    </property>
   </column>
  </widget>
  <widget class="QTableWidget" name="tableWidget">
   <property name="geometry">
    <rect>
     <x>330</x>
     <y>230</y>
     <width>401</width>
     <height>221</height>
    </rect>
   </property>
  </widget>
 </widget>
 <resources>
  <include location="src.qrc"/>
 </resources>
 <connections/>
</ui>

运行结果:

12 其他控件

stackWidget 栈控件
ui->stackWidget->setCurrentIndex(1);

comboBox 下拉框
ui->comboBox->addItem("奔驰");

QLabel 显示图片
ui->lbl_Image->setPixmap(QPixmap(":/Image/butterfly.png"))

QLabel 显示动图 gif图片
ui->lbl_Image->setMove(movie);
movie->start();

08_OtherControl.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //栈控件使用

    //设置默认定位 scrollArea
    ui->stackedWidget->setCurrentIndex(0);

    //scrollArea按钮
    connect(ui->btn_scrollArea, &QPushButton::clicked, [=](){
        ui->stackedWidget->setCurrentIndex(0);
    });

    //toolBox按钮
    connect(ui->btn_toolBox, &QPushButton::clicked, [=](){
        ui->stackedWidget->setCurrentIndex(1);
    });

    //tabWidget按钮
    connect(ui->btn_tabWidget, &QPushButton::clicked, [=](){
        ui->stackedWidget->setCurrentIndex(2);
    });

    //下拉框
    ui->comboBox->addItem("奔驰");
    ui->comboBox->addItem("宝马");
    ui->comboBox->addItem("拖拉机");

    //点击按钮 comboBox选中拖拉机
    connect(ui->btn_select, &QPushButton::clicked, [=](){
        ui->comboBox->setCurrentIndex(2);
        //ui->comboBox->setCurrentText("拖拉机");
    });


}

Widget::~Widget()
{
    delete ui;
}

main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

widget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <widget class="QStackedWidget" name="stackedWidget">
   <property name="geometry">
    <rect>
     <x>20</x>
     <y>10</y>
     <width>271</width>
     <height>491</height>
    </rect>
   </property>
   <property name="currentIndex">
    <number>0</number>
   </property>
   <widget class="QWidget" name="page_4">
    <layout class="QVBoxLayout" name="verticalLayout_2">
     <item>
      <widget class="QScrollArea" name="scrollArea">
       <property name="widgetResizable">
        <bool>true</bool>
       </property>
       <widget class="QWidget" name="scrollAreaWidgetContents">
        <property name="geometry">
         <rect>
          <x>0</x>
          <y>-353</y>
          <width>230</width>
          <height>820</height>
         </rect>
        </property>
        <layout class="QVBoxLayout" name="verticalLayout">
         <item>
          <widget class="QPushButton" name="pushButton">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_2">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_3">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_4">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_5">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_6">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_7">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_23">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_22">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_21">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_20">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_19">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_18">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_17">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_16">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_15">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_14">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_13">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_12">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_11">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_10">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_9">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pushButton_8">
           <property name="text">
            <string>PushButton</string>
           </property>
          </widget>
         </item>
        </layout>
       </widget>
      </widget>
     </item>
    </layout>
   </widget>
   <widget class="QWidget" name="page_5">
    <layout class="QVBoxLayout" name="verticalLayout_3">
     <item>
      <widget class="QToolBox" name="toolBox">
       <property name="currentIndex">
        <number>0</number>
       </property>
       <widget class="QWidget" name="page">
        <property name="geometry">
         <rect>
          <x>0</x>
          <y>0</y>
          <width>319</width>
          <height>367</height>
         </rect>
        </property>
        <attribute name="label">
         <string>家人</string>
        </attribute>
        <widget class="QPushButton" name="pushButton_24">
         <property name="geometry">
          <rect>
           <x>50</x>
           <y>50</y>
           <width>93</width>
           <height>28</height>
          </rect>
         </property>
         <property name="text">
          <string>PushButton</string>
         </property>
        </widget>
       </widget>
       <widget class="QWidget" name="page_2">
        <property name="geometry">
         <rect>
          <x>0</x>
          <y>0</y>
          <width>319</width>
          <height>367</height>
         </rect>
        </property>
        <attribute name="label">
         <string>朋友</string>
        </attribute>
        <widget class="QCheckBox" name="checkBox">
         <property name="geometry">
          <rect>
           <x>20</x>
           <y>90</y>
           <width>98</width>
           <height>23</height>
          </rect>
         </property>
         <property name="text">
          <string>CheckBox</string>
         </property>
        </widget>
       </widget>
       <widget class="QWidget" name="page_3">
        <attribute name="label">
         <string>黑名单</string>
        </attribute>
        <widget class="QToolButton" name="toolButton">
         <property name="geometry">
          <rect>
           <x>40</x>
           <y>230</y>
           <width>51</width>
           <height>41</height>
          </rect>
         </property>
         <property name="text">
          <string>...</string>
         </property>
        </widget>
       </widget>
      </widget>
     </item>
    </layout>
   </widget>
   <widget class="QWidget" name="page_6">
    <layout class="QVBoxLayout" name="verticalLayout_5">
     <item>
      <widget class="QTabWidget" name="tabWidget">
       <property name="currentIndex">
        <number>0</number>
       </property>
       <widget class="QWidget" name="tab">
        <attribute name="title">
         <string>百度</string>
        </attribute>
        <layout class="QVBoxLayout" name="verticalLayout_4">
         <item>
          <widget class="QRadioButton" name="radioButton">
           <property name="text">
            <string>RadioButton</string>
           </property>
          </widget>
         </item>
        </layout>
       </widget>
       <widget class="QWidget" name="tab_2">
        <attribute name="title">
         <string>谷歌</string>
        </attribute>
        <widget class="QPushButton" name="pushButton_25">
         <property name="geometry">
          <rect>
           <x>40</x>
           <y>130</y>
           <width>93</width>
           <height>28</height>
          </rect>
         </property>
         <property name="text">
          <string>PushButton</string>
         </property>
        </widget>
       </widget>
      </widget>
     </item>
    </layout>
   </widget>
  </widget>
  <widget class="QPushButton" name="btn_scrollArea">
   <property name="geometry">
    <rect>
     <x>360</x>
     <y>20</y>
     <width>93</width>
     <height>28</height>
    </rect>
   </property>
   <property name="text">
    <string>scrollArea</string>
   </property>
  </widget>
  <widget class="QPushButton" name="btn_toolBox">
   <property name="geometry">
    <rect>
     <x>360</x>
     <y>60</y>
     <width>93</width>
     <height>28</height>
    </rect>
   </property>
   <property name="text">
    <string>toolBox</string>
   </property>
  </widget>
  <widget class="QPushButton" name="btn_tabWidget">
   <property name="geometry">
    <rect>
     <x>360</x>
     <y>100</y>
     <width>93</width>
     <height>28</height>
    </rect>
   </property>
   <property name="text">
    <string>tabWidget</string>
   </property>
  </widget>
  <widget class="QComboBox" name="comboBox">
   <property name="geometry">
    <rect>
     <x>370</x>
     <y>280</y>
     <width>83</width>
     <height>25</height>
    </rect>
   </property>
  </widget>
  <widget class="QPushButton" name="btn_select">
   <property name="geometry">
    <rect>
     <x>360</x>
     <y>340</y>
     <width>93</width>
     <height>28</height>
    </rect>
   </property>
   <property name="text">
    <string>select</string>
   </property>
  </widget>
  <widget class="QSpinBox" name="spinBox">
   <property name="geometry">
    <rect>
     <x>350</x>
     <y>400</y>
     <width>44</width>
     <height>25</height>
    </rect>
   </property>
  </widget>
  <widget class="QDoubleSpinBox" name="doubleSpinBox">
   <property name="geometry">
    <rect>
     <x>430</x>
     <y>400</y>
     <width>66</width>
     <height>25</height>
    </rect>
   </property>
  </widget>
  <widget class="QTimeEdit" name="timeEdit">
   <property name="geometry">
    <rect>
     <x>350</x>
     <y>450</y>
     <width>118</width>
     <height>25</height>
    </rect>
   </property>
  </widget>
  <widget class="QDateEdit" name="dateEdit">
   <property name="geometry">
    <rect>
     <x>350</x>
     <y>500</y>
     <width>110</width>
     <height>25</height>
    </rect>
   </property>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

运行结果:

13 自定义控件封装

添加新文件 Qt --> 设计师界面类(.h .cpp .ui)

.ui中 设计QSpinBox和QSlider 两个控件

widget中使用自定义控件,拖拽一个Widget,点击提升为,点击添加,点击提升

实现功能,改变数字,滑动条跟着移动,信号槽监听

提供 getNum 和 setNum 对外接口

勾选全局后,再次添加QWidget,右键“提升为”,会出现子菜单

09_smallWidget

09_smallWidget.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    smallwidget.cpp \
    widget.cpp

HEADERS += \
    smallwidget.h \
    widget.h

FORMS += \
    smallwidget.ui \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

smallWidget.h

#ifndef SMALLWIDGET_H
#define SMALLWIDGET_H

#include <QWidget>

namespace Ui {
class SmallWidget;
}

class SmallWidget : public QWidget
{
    Q_OBJECT

public:
    explicit SmallWidget(QWidget *parent = nullptr);
    ~SmallWidget();

    //设置数字
    void setNum(int num);
    //获取数字
    int getNum();

private:
    Ui::SmallWidget *ui;
};

#endif // SMALLWIDGET_H

smallWidget.cpp

#include "smallwidget.h"
#include "ui_smallwidget.h"

SmallWidget::SmallWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::SmallWidget)
{
    ui->setupUi(this);

    //QSpinBox移动 QSlider跟着移动
    void(QSpinBox::*spSignal)(int) = &QSpinBox::valueChanged;
    connect(ui->spinBox, spSignal, ui->horizontalSlider, &QSlider::setValue);

    //QSlider划动 QSpinBox数字跟着改变
    connect(ui->horizontalSlider, &QSlider::valueChanged, ui->spinBox, &QSpinBox::setValue);

}

SmallWidget::~SmallWidget()
{
    delete ui;
}

//设置数字
void SmallWidget::setNum(int num)
{
    ui->spinBox->setValue(num);
}
//获取数字
int SmallWidget::getNum()
{
    ui->spinBox->value();
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //点击获取当前值,获取当前控件当前的值
    connect(ui->btn_get, &QPushButton::clicked, [=](){
        qDebug() << ui->small_widget->getNum();
    });

    //设置到一半
    connect(ui->btn_set, &QPushButton::clicked, [=](){
        ui->small_widget->setNum(50);
    });
}

Widget::~Widget()
{
    delete ui;
}

main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

smallwidget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>SmallWidget</class>
 <widget class="QWidget" name="SmallWidget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>286</width>
    <height>47</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <layout class="QHBoxLayout" name="horizontalLayout">
   <item>
    <widget class="QSpinBox" name="spinBox"/>
   </item>
   <item>
    <widget class="QSlider" name="horizontalSlider">
     <property name="orientation">
      <enum>Qt::Orientation::Horizontal</enum>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>

widget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <widget class="SmallWidget" name="small_widget" native="true">
   <property name="geometry">
    <rect>
     <x>30</x>
     <y>30</y>
     <width>341</width>
     <height>51</height>
    </rect>
   </property>
  </widget>
  <widget class="SmallWidget" name="widget_2" native="true">
   <property name="geometry">
    <rect>
     <x>20</x>
     <y>60</y>
     <width>321</width>
     <height>51</height>
    </rect>
   </property>
  </widget>
  <widget class="QPushButton" name="btn_get">
   <property name="geometry">
    <rect>
     <x>140</x>
     <y>200</y>
     <width>93</width>
     <height>28</height>
    </rect>
   </property>
   <property name="text">
    <string>获取当前值</string>
   </property>
  </widget>
  <widget class="QPushButton" name="btn_set">
   <property name="geometry">
    <rect>
     <x>140</x>
     <y>280</y>
     <width>93</width>
     <height>28</height>
    </rect>
   </property>
   <property name="text">
    <string>设置到一半</string>
   </property>
  </widget>
 </widget>
 <customwidgets>
  <customwidget>
   <class>SmallWidget</class>
   <extends>QWidget</extends>
   <header location="global">smallwidget.h</header>
   <container>1</container>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

14 Qt事件

1 鼠标事件

鼠标进入事件:enterEvent
鼠标离开事件:leaveEvent
鼠标按下事件:mousePressEvent
鼠标释放事件:mouseReleaseEvent
鼠标移动事件:mouseMoveEvent

event->x() ==> x坐标 event->y() ==> y坐标

event->button() 可以判断所有的按键 Qt::LeftButton(鼠标左键),Qt::RightButton(鼠标右键)

event->button() & Qt::LeftButton 判断组合按键 判断move时候的左右键 结合 & 操作符

格式化字符串 QString("%1 %2").arg(111).arg(222)

2 定时器

方式一:
利用事件 void timerEvent(QTimerEvent* evt)
启动定时器 startTimer(1000) 单位是毫秒
timerEvent的返回值是定时器的唯一标识,可以和evt->timerId做比较

方式二:
利用定时器类 QTimer
创建定时器对象 QTimer* timer1 = new QTimer(this)
启动定时器 timer1->startTimer(毫秒)
每隔一定毫秒,发送信号 timeout 进行监听
暂停 timer2->stop()

3 event事件

用途:用于事件的分发
也可以拦截操作,不建议
bool event(QEvent* e)
返回值 如果是true代表用户处理这个事件,不向下分发了
e->type() == 鼠标按下

4 事件过滤器

在程序将事件分发到事件分发器前,可以利用过滤器做拦截
步骤:1、给控件安装事件过滤器;2、重写eventFilter(obj, ev)

10_QtEvent

10_QtEvent.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mylabel.cpp \
    widget.cpp

HEADERS += \
    mylabel.h \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

myLabel.h

#ifndef MYLABEL_H
#define MYLABEL_H

#include <QLabel>

class myLabel : public QLabel
{
    Q_OBJECT
public:
    explicit myLabel(QWidget *parent = nullptr);

    //鼠标进入事件
    void enterEvent(QEvent* event);
    //鼠标离开事件
    void leaveEvent(QEvent* event);
    //鼠标按下
    virtual void mousePressEvent(QMouseEvent* event);
    //鼠标释放
    virtual void mouseReleaseEvent(QMouseEvent* event);
    //鼠标移动
    virtual void mouseMoveEvent(QMouseEvent* event);

    //通过event事件分发器 拦截 鼠标按下事件
    bool event(QEvent *e);
signals:
};

#endif // MYLABEL_H

myLabel.cpp

#include "mylabel.h"
#include <QDebug>
#include <QMouseEvent>

myLabel::myLabel(QWidget *parent)
    : QLabel{parent}
{
    //设置鼠标的追踪状态
    setTabletTracking(true);
}

//鼠标进入事件
void myLabel::enterEvent(QEvent* event)
{
    qDebug() << "鼠标进入了";
}

//鼠标离开事件
void myLabel::leaveEvent(QEvent* event)
{
    qDebug() << "鼠标离开了";
}

//鼠标按下
void myLabel::mousePressEvent(QMouseEvent* event)
{
    //当鼠标左键按下 提示信息
    if (event->button() == Qt::LeftButton){
        QString str = QString("鼠标按下了 x = %1  y = %2  globalX = %3  globalY = %4").arg(event->x()).arg(event->y()).arg(event->globalX()).arg(event->globalY());
        qDebug() << str;
    }
}

//鼠标释放
void myLabel::mouseReleaseEvent(QMouseEvent* event)
{
    if (event->button() == Qt::LeftButton)
    {
        QString str = QString("鼠标释放了 x = %1  y = %2  globalX = %3  globalY = %4").arg(event->x()).arg(event->y()).arg(event->globalX()).arg(event->globalY());
        qDebug() << str;
    }
}

//鼠标移动
void myLabel::mouseMoveEvent(QMouseEvent* event)
{
    //鼠标移动是连续,只有瞬间的才能判断鼠标左键;
    //可以使用 &
    //if (event->button() == Qt::LeftButton)
    if (event->button() & Qt::LeftButton)
    {
        QString str = QString("鼠标移动了 x = %1  y = %2  globalX = %3  globalY = %4").arg(event->x()).arg(event->y()).arg(event->globalX()).arg(event->globalY());
        qDebug() << str;
    }
}


//通过event事件分发器 拦截 鼠标按下事件
bool myLabel::event(QEvent *e)
{
    //如果是鼠标按下,在event事件分发中做拦截操作
    if (e->type() == QEvent::MouseButtonPress)
    {
        QMouseEvent* ev = static_cast<QMouseEvent*>(e);
        QString str = QString("Event函数中::鼠标按下了 x = %1  y = %2  globalX = %3  globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
        qDebug() << str;

        return true; //true代表用户自己处理这个事件,不向下分发
    }

    //其他事件 交给父类处理 默认处理
    return QLabel::event(e);
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    //重写定时器事件
    void timerEvent(QTimerEvent *event);

    int id1; //定时器1的唯一标识
    int id2; //定时器2的唯一标识

    //重写事件过滤器的事件
    bool eventFilter(QObject *watched, QEvent *event);

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QTimer> //定时器的类
#include <QMouseEvent>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //启动定时器
    id1 =startTimer(1000);//参数1:间隔(单位是毫秒)

    id2 = startTimer(2000);

    //定时器第二种方式
    QTimer* timer1 = new QTimer(this);
    //启动定时器
    timer1->start(500);
    connect(timer1, &QTimer::timeout, [=](){
        //label4 每隔0.5秒+1
        static int num = 1;
        ui->label_4->setText(QString::number(num++));
    });

    //点击暂停按钮,实现停止定时器
    connect(ui->btn, &QPushButton::clicked, [=](){
        timer1->stop();
    });

    //给label1 安装事件过滤器
    //步骤1 安装事件过滤器
    ui->label->installEventFilter(this);
}

Widget::~Widget()
{
    delete ui;
}

//重写定时器事件
void Widget::timerEvent(QTimerEvent *event)
{
    if (event->timerId() == id1)
    {
        //label2 每隔1秒+1
        static int num = 1;
        ui->label_2->setText(QString::number(num++));
    } else if (event->timerId() == id2){
        //label3 每隔2秒+1
        static int num = 1;
        ui->label_3->setText(QString::number(num++));
    }
}

//步骤2 重写eventFilter事件
bool Widget::eventFilter(QObject *obj, QEvent *event)
{
    if (obj == ui->label)
    {
        if (event->type() == QEvent::MouseButtonPress)
        {
            QMouseEvent* ev = static_cast<QMouseEvent*>(event);
            QString str = QString("事件过滤中::鼠标按下了 x = %1  y = %2  globalX = %3  globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
            qDebug() << str;

            return true; //true代表用户自己处理这个事件,不向下分发
        }
    }
    //其他默认处理
    return QWidget::eventFilter(obj, event);
}

main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

widget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <widget class="myLabel" name="label">
   <property name="geometry">
    <rect>
     <x>60</x>
     <y>40</y>
     <width>271</width>
     <height>51</height>
    </rect>
   </property>
   <property name="frameShape">
    <enum>QFrame::Shape::Box</enum>
   </property>
   <property name="text">
    <string>TextLabel</string>
   </property>
  </widget>
  <widget class="QLabel" name="label_2">
   <property name="geometry">
    <rect>
     <x>60</x>
     <y>120</y>
     <width>291</width>
     <height>81</height>
    </rect>
   </property>
   <property name="frameShape">
    <enum>QFrame::Shape::Panel</enum>
   </property>
   <property name="text">
    <string/>
   </property>
  </widget>
  <widget class="QLabel" name="label_3">
   <property name="geometry">
    <rect>
     <x>60</x>
     <y>220</y>
     <width>281</width>
     <height>51</height>
    </rect>
   </property>
   <property name="frameShape">
    <enum>QFrame::Shape::WinPanel</enum>
   </property>
   <property name="text">
    <string/>
   </property>
  </widget>
  <widget class="QLabel" name="label_4">
   <property name="geometry">
    <rect>
     <x>60</x>
     <y>310</y>
     <width>281</width>
     <height>41</height>
    </rect>
   </property>
   <property name="frameShape">
    <enum>QFrame::Shape::Panel</enum>
   </property>
   <property name="frameShadow">
    <enum>QFrame::Shadow::Sunken</enum>
   </property>
   <property name="text">
    <string>TextLabel</string>
   </property>
  </widget>
  <widget class="QPushButton" name="btn">
   <property name="geometry">
    <rect>
     <x>360</x>
     <y>320</y>
     <width>93</width>
     <height>28</height>
    </rect>
   </property>
   <property name="text">
    <string>暂停</string>
   </property>
  </widget>
 </widget>
 <customwidgets>
  <customwidget>
   <class>myLabel</class>
   <extends>QLabel</extends>
   <header location="global">mylabel.h</header>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

15 QPainter绘图

绘图事件 void paintEvent(QPaintEvent* evt)
声明一个画家对象 QPainter painter(this); //this指定绘画设备
画线、画圆、画椭圆、画文字
设置画笔 QPen 设置画笔宽度、风格
设置画刷 QBrush 设置画刷 风格

QPainter高级设置:
抗锯齿能力 效率低 painter.setRenderHint(QPainter::Antialiasing);
对画家进行移动 painter.translate(100, 0);
保存画家状态 painter.save();
还原画家保存状态 painter.restore();
如果想手动调用绘图事件 利用update
利用画家画图片 painter.drawPixmap(x,y,QPixmap(":/image/image1.jpg"))

11_QPainter

11_QPainter.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
    res.qrc

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void paintEvent(QPaintEvent* evt);

private:
    Ui::Widget *ui;
    int posX = 0;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QPainter> //画家类

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //点击移动按钮 图片向右移动
    connect(ui->pushButton, &QPushButton::clicked, [=]{
        posX +=20;
        //如果要手动调用绘图事件,用update更新
        update();
    });
}

Widget::~Widget()
{
    delete ui;
}

void Widget::paintEvent(QPaintEvent* evt)
{

    /*
    ///普通设置///
    //实例化画家对象 this指定的是绘画的设备
    QPainter painter(this);
    //画线
    painter.drawLine(QPoint(0, 0), QPoint(100, 100));
    //画圆
    painter.drawEllipse(QPoint(100, 100), 50, 50);
    //设置画笔
    QPen pen(QColor(255, 0, 0));
    //设置画笔宽度
    pen.setWidth(10);
    //设置画笔风格
    pen.setStyle(Qt::DotLine);
    //让画家 使用这个笔
    painter.setPen(pen);
    //画椭圆
    painter.drawEllipse(QPoint(100, 100), 100, 50);

    //设置画刷——填充封闭图像内部
    QBrush brush(QColor(Qt::green));
    //设置画刷风格
    brush.setStyle(Qt::Dense2Pattern);
    //让画家使用画刷
    painter.setBrush(brush);
    //画矩形
    painter.drawRect(QRect(300, 100, 100, 50));
    //画文字
    painter.drawText(QRect(10, 200, 100, 50), "好好学习");
    */


    /*
    ///高级设置///
    QPainter painter(this);
    painter.drawEllipse(QPoint(100, 50), 50, 50);
    //设置 抗锯齿能力 效率低
    painter.setRenderHint(QPainter::Antialiasing);
    painter.drawEllipse(QPoint(200, 50), 50, 50);

    //画矩形
    painter.drawRect(QRect(120, 150, 50, 50));
    //移动画家 坐标轴移动到(100,0)
    painter.translate(100, 0);
    //保存画家状态
    painter.save();
    painter.drawRect(QRect(120, 150, 50, 50));
    //移动画家 坐标轴移动到(200,0)
    painter.translate(100, 0);
    //还原画家保存状态
    painter.restore();
    painter.drawRect(QRect(120, 150, 50, 50));
    */


    利用画家 画资源图片//
    QPainter painter(this);
    //如果超出屏幕 从0开始
    if (posX > this->width())
    {
        posX = 0;
    }
    painter.drawPixmap(posX, 20, QPixmap(":/Image/image1.jpg"));

}

main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

 widget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>481</width>
    <height>444</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <widget class="QPushButton" name="pushButton">
   <property name="geometry">
    <rect>
     <x>370</x>
     <y>380</y>
     <width>93</width>
     <height>28</height>
    </rect>
   </property>
   <property name="text">
    <string>移动</string>
   </property>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

16 QPaintDevice 绘图设备

QPixmap QImage QBttmap(黑白色) QPicture QWidget

QPixmap 对不同平台做了显示的优化
QPixmap pix(300, 300)
背景默认是黑色,设置背景颜色 pix.fill(Qt::green)
利用画家 往pix上画画 QPainter painter(&pix)
保存 pix.save("路径")

QImage 可以对像素进行访问
使用和QPixmap差不多 QImage img(300, 300, QImage::Format_RGB32)
其他流程和QPixmap一样
可以对像素进行修改img.setPixel(i, j, value),设置像素QRgb value = qRgb(255, 0, 0)

QPicture 记录和重现绘图指令
QPicture pic;
开始绘画 painter.begin(&pic);
保存 pic.save("任意后缀名");
绘画结束 painter.end();
重现QPicture的绘图指令 painter.drawPicture(0, 0, pic);

12_QtPaintDevice

12_QtPaintDevice.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
    res.qrc

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    //绘图事件
    void paintEvent(QPaintEvent* evt);

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QPixmap>
#include <QPainter>
#include <QImage>
#include <QPicture>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    /*
    //Pixmap绘图设备 专门为平台做了显示的优化
    QPixmap pix(300, 300);
    //填充颜色
    pix.fill(Qt::white);
    //声明画家
    QPainter painter(&pix);
    painter.setPen(QPen(Qt::green));
    painter.drawEllipse(QPoint(150, 150), 100, 100);
    //保存
    pix.save("E:\\pix.png");
    */

    /*
    //QImage 绘图设备 可以对像素进行访问
    QImage img(300, 300, QImage::Format_RGB32);
    img.fill(Qt::white);
    QPainter painter(&img);
    painter.setPen(QPen(Qt::green));
    painter.drawEllipse(QPoint(150, 150), 100, 100);
    //保存
    img.save("E:\\img.png");
    */


    //QPicture 绘图设备 可以记录和重现绘图指令
    QPicture pic;
    QPainter painter;
    //开始绘画
    painter.begin(&pic);
    painter.setPen(QPen(Qt::red));
    painter.drawEllipse(QPoint(150, 150), 100, 100);
    //绘画结束
    painter.end();
    //保存
    pic.save("E:\\pic.zt");

}

Widget::~Widget()
{
    delete ui;
}

//绘图事件
void Widget::paintEvent(QPaintEvent* evt)
{
    /*
    //利用QImage 对像素进行修改
    QImage img;
    img.load(":/Image/image1.jpg");

    QPainter painter(this);
    //修改像素点
    for (int i = 50; i < 100; i++)
    {
        for (int j = 50; j < 100; j++)
        {
            QRgb value = qRgb(255, 0, 0);
            img.setPixel(i, j, value);
        }
    }
    painter.drawImage(0, 0, img);
    */


    //重现QPicture的绘图指令
    QPicture pic;
    pic.load("E://pic.zt");
    QPainter painter(this);
    painter.drawPicture(0, 0, pic);
}

main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

widget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
 </widget>
 <resources/>
 <connections/>
</ui>

17 QFile 对文件进行读写操作

QFile 进行读写操作:QFile file(path 文件路径)

读:
file.open(打开方式)    QIODevice::ReadOnly
全部读取 file.readAll();按行读取 file.readLine();判断是否读到文件尾 file.atEnd()
默认支持编码格式 utf-8
利用编码格式类 指定格式QTextCodec(若QTextCodec 编译失败,在pro文件中添加greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat)
QTextCodec* codec = QTextCodec::codecForName("gbk");
ui->textEdit->setText(codec->toUnicode(array));
文件对象关闭 file.close();

写:
file.open(QIODevice::Append);   //用追加的方式进行写
file.write(内容)
file.close() 关闭

读取文件信息:
大小:info.size()
后缀名:info.suffix()
文件名称:info.fileName()
文件路径:info.path()
创建日期:info.birthTime().toString("yyyy/MM/dd hh:mm:ss")
最后修改日期:info.lastModified().toString("yyyy-MM-dd hh:mm:ss");

13_Qt_QFile

13_Qt_QFile.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QFile>
#include <QTextCodec>
#include <QDebug>
#include <QDateTime>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //点击选取文件,弹出文件对话框
    connect(ui->pushButton, &QPushButton::clicked, [=](){
        QString path = QFileDialog::getOpenFileName(this, "打开文件", "D:\\Desktop");
        //将路径放入到LineEdit中
        ui->lineEdit->setText(path);

        //编码格式类
        //QTextCodec* codec = QTextCodec::codecForName("gbk");

        //将读取到的内容 放到textEdit中
        //QFile默认支持的格式 utf-8
        QFile file(path);   //参数就是读取文件的路径
        //设置打开方式
        file.open(QIODevice::ReadOnly);
        //QByteArray array = file.readAll();
        //将读取到的数据 放到textEdit中
        //ui->textEdit->setText(array);
        //ui->textEdit->setText(codec->toUnicode(array));

        //按行读
        QByteArray array;
        while (!file.atEnd())
        {
            array += file.readLine();
        }
        ui->textEdit->setText(array);

        //对文件对象进行关闭
        file.close();


        //进行写文件
        file.open(QIODevice::Append);   //用追加的方式进行写
        file.write("aaaaaaaaaaa");
        file.close();


        //QFileInfo 文件信息类
        QFileInfo info(path);
        qDebug() << "大小:" << info.size()
                 << "  后缀名:" << info.suffix()
                 << "  文件名称:" << info.fileName()
                 << "  文件路径:" << info.path()
                 << "  创建日期:" << info.birthTime().toString("yyyy/MM/dd hh:mm:ss")
                 << "  最后修改日期:" << info.lastModified().toString("yyyy-MM-dd hh:mm:ss");

    });
}

Widget::~Widget()
{
    delete ui;
}

main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

widget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>538</width>
    <height>450</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <item>
    <widget class="QWidget" name="widget" native="true">
     <layout class="QHBoxLayout" name="horizontalLayout">
      <item>
       <widget class="QLineEdit" name="lineEdit"/>
      </item>
      <item>
       <widget class="QPushButton" name="pushButton">
        <property name="text">
         <string>选取文件</string>
        </property>
       </widget>
      </item>
     </layout>
    </widget>
   </item>
   <item>
    <widget class="QTextEdit" name="textEdit"/>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>

18 案例-翻金币

打包发布

新建文件夹,把CoinFlip.exe拷贝到文件夹下

打开cmd

CoinFlip

CoinFlip.pro

QT       += core gui
QT += multimedia

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    chooselevelscene.cpp \
    dataconfig.cpp \
    main.cpp \
    mainscene.cpp \
    mycoin.cpp \
    mypushbutton.cpp \
    playscene.cpp

HEADERS += \
    chooselevelscene.h \
    dataconfig.h \
    mainscene.h \
    mycoin.h \
    mypushbutton.h \
    playscene.h

FORMS += \
    mainscene.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
    res.qrc

chooselevelscene.h

#ifndef CHOOSELEVELSCENE_H
#define CHOOSELEVELSCENE_H

#include <QMainWindow>
#include "playscene.h"

class ChooseLevelScene : public QMainWindow
{
    Q_OBJECT
public:
    explicit ChooseLevelScene(QWidget *parent = nullptr);

    //重写绘图事件
    void paintEvent(QPaintEvent *event);

    //游戏场景对象指针
    PlayScene* play = NULL;

signals:
    //写一个自定义信号,告诉主场景 点击了返回
    //自定义信号只需要声明,不需要实现
    void chooseSceneBack();
};

#endif // CHOOSELEVELSCENE_H

chooselevelscene.cpp

#include "chooselevelscene.h"
#include <QPixmap>
#include <QMenuBar>
#include <QPainter>
#include <QPixmap>
#include "mypushbutton.h"
#include <QDebug>
#include <QTimer>
#include <QLabel>
#include <QSoundEffect>

ChooseLevelScene::ChooseLevelScene(QWidget *parent)
    : QMainWindow{parent}
{
    //配置选择关卡场景
    this->setFixedSize(320, 588);

    //设置图标
    this->setWindowIcon(QPixmap(":/res/Coin0001.png"));

    //设置标题
    this->setWindowTitle("选择关卡场景");

    //创建菜单栏
    QMenuBar* bar = menuBar();
    this->setMenuBar(bar);

    //创建开始菜单
    QMenu* startMenu = bar->addMenu("开始");

    //创建退出 菜单项
    QAction* quitAction = startMenu->addAction("退出");

    //点击退出 实现退出游戏
    connect(quitAction, &QAction::triggered, [=](){
        this->close();
    });

    //选择关卡的音效
    QSoundEffect* chooseSound = new QSoundEffect();
    chooseSound->setSource(QUrl::fromLocalFile(":/res/TapButtonSound.wav"));
    //返回按钮的音效
    QSoundEffect* backSound = new QSoundEffect();
    backSound->setSource(QUrl::fromLocalFile(":/res/BackButtonSound.wav"));


    //返回按钮
    MyPushButton* backBtn = new MyPushButton(":/res/BackButton.png", ":/res/BackButtonSelected.png");;
    backBtn->setParent(this);
    backBtn->move(this->width()-backBtn->width(), this->height()-backBtn->height());

    //点击返回
    connect(backBtn, &MyPushButton::clicked, [=](){
        qDebug() << "点击了返回按钮";

        //播放返回按钮的音效
        backSound->play();

        //延时返回
        QTimer::singleShot(500, this, [=](){
            //告诉主场景,我返回了,主场景监听ChooseLevelScene的返回按钮
            emit this->chooseSceneBack();
        });

    });

    //创建选择关卡的按钮
    for (int i = 0; i < 20; i++)
    {
        MyPushButton* menuBtn = new MyPushButton(":/res/LevelIcon.png");
        menuBtn->setParent(this);
        menuBtn->move(25+i%4*70, 130+i/4*70);

        //监听每个按钮的点击事件
        connect(menuBtn, &MyPushButton::clicked, [=](){
            QString str = QString("您选择的是第 %1 关").arg(i+1);
            qDebug() << str;

            //播放选择关卡的音效
            chooseSound->play();

            play = new PlayScene(i+1);  //创建游戏场景
            //设置游戏场景的初始位置
            play->setGeometry(this->geometry());

            //进入到游戏场景
            this->hide();   //将选关场景隐藏掉
            play->show();   //显示游戏场景

            connect(play, &PlayScene::chooseSceneBack, [=](){
                this->setGeometry(play->geometry());
                this->show();
                delete play;
                play = NULL;
            });
        });

        QLabel* label = new QLabel;
        label->setParent(this);
        label->setFixedSize(menuBtn->width(), menuBtn->height());
        label->setText(QString::number(i+1));
        label->move(25+i%4*70, 130+i/4*70);
        //设置label上的文字对齐方式 水平居中 和 垂直居中
        label->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
        //设置让鼠标进行穿透 51号属性
        label->setAttribute(Qt::WA_TransparentForMouseEvents);
    }
}

//重写绘图事件
void ChooseLevelScene::paintEvent(QPaintEvent *event)
{
    //加载背景
    QPainter painter(this);
    QPixmap pix;
    pix.load(":/res/OtherSceneBg.png");
    painter.drawPixmap(0, 0, this->width(), this->height(), pix);

    //画背景上图标
    pix.load(":/res/Title.png");
    painter.drawPixmap((this->width()-pix.width())*0.5, 30, pix.width(), pix.height(), pix);


}

dataconfig.h

#ifndef DATACONFIG_H
#define DATACONFIG_H

#include <QObject>
#include <QMap>
#include <QVector>

class dataConfig : public QObject
{
    Q_OBJECT
public:
    explicit dataConfig(QObject *parent = 0);

public:

    QMap<int, QVector< QVector<int> > >mData;



signals:

public slots:
};

#endif // DATACONFIG_H

dataconfig.cpp

#include "dataconfig.h"
#include <QDebug>
dataConfig::dataConfig(QObject *parent) : QObject(parent)
{

     int array1[4][4] = {{1, 1, 1, 1},
                        {1, 1, 0, 1},
                        {1, 0, 0, 0},
                        {1, 1, 0, 1} } ;

     QVector< QVector<int>> v;
     for(int i = 0 ; i < 4;i++)
     {
         QVector<int>v1;
         for(int j = 0 ; j < 4;j++)
         {

            v1.push_back(array1[i][j]);
         }
         v.push_back(v1);
     }

     mData.insert(1,v);


     int array2[4][4] = { {1, 0, 1, 1},
                          {0, 0, 1, 1},
                          {1, 1, 0, 0},
                          {1, 1, 0, 1}} ;

     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array2[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(2,v);



     int array3[4][4] = {  {0, 0, 0, 0},
                           {0, 1, 1, 0},
                           {0, 1, 1, 0},
                           {0, 0, 0, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array3[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(3,v);


     int array4[4][4] = {   {0, 1, 1, 1},
                            {1, 0, 0, 1},
                            {1, 0, 1, 1},
                            {1, 1, 1, 1}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array4[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(4,v);


     int array5[4][4] = {  {1, 0, 0, 1},
                           {0, 0, 0, 0},
                           {0, 0, 0, 0},
                           {1, 0, 0, 1}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array5[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(5,v);


     int array6[4][4] = {   {1, 0, 0, 1},
                            {0, 1, 1, 0},
                            {0, 1, 1, 0},
                            {1, 0, 0, 1}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array6[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(6,v);


     int array7[4][4] = {   {0, 1, 1, 1},
                            {1, 0, 1, 1},
                            {1, 1, 0, 1},
                            {1, 1, 1, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array7[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(7,v);

     int array8[4][4] = {  {0, 1, 0, 1},
                           {1, 0, 0, 0},
                           {0, 0, 0, 1},
                           {1, 0, 1, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array8[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(8,v);

     int array9[4][4] = {   {1, 0, 1, 0},
                            {1, 0, 1, 0},
                            {0, 0, 1, 0},
                            {1, 0, 0, 1}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array9[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(9,v);



     int array10[4][4] = {  {1, 0, 1, 1},
                            {1, 1, 0, 0},
                            {0, 0, 1, 1},
                            {1, 1, 0, 1}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array10[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(10,v);


     int array11[4][4] = {  {0, 1, 1, 0},
                            {1, 0, 0, 1},
                            {1, 0, 0, 1},
                            {0, 1, 1, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array11[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(11,v);

     int array12[4][4] = {  {0, 1, 1, 0},
                            {0, 0, 0, 0},
                            {1, 1, 1, 1},
                            {0, 0, 0, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array12[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(12,v);


     int array13[4][4] = {    {0, 1, 1, 0},
                              {0, 0, 0, 0},
                              {0, 0, 0, 0},
                              {0, 1, 1, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array13[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(13,v);

     int array14[4][4] = {    {1, 0, 1, 1},
                              {0, 1, 0, 1},
                              {1, 0, 1, 0},
                              {1, 1, 0, 1}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array14[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(14,v);


     int array15[4][4] = {   {0, 1, 0, 1},
                             {1, 0, 0, 0},
                             {1, 0, 0, 0},
                             {0, 1, 0, 1}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array15[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(15,v);


     int array16[4][4] = {   {0, 1, 1, 0},
                             {1, 1, 1, 1},
                             {1, 1, 1, 1},
                             {0, 1, 1, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array16[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(16,v);

     int array17[4][4] = {  {0, 1, 1, 1},
                            {0, 1, 0, 0},
                            {0, 0, 1, 0},
                            {1, 1, 1, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array17[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(17,v);


     int array18[4][4] = { {0, 0, 0, 1},
                           {0, 0, 1, 0},
                           {0, 1, 0, 0},
                           {1, 0, 0, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array18[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(18,v);

     int array19[4][4] = {   {0, 1, 0, 0},
                             {0, 1, 1, 0},
                             {0, 0, 1, 1},
                             {0, 0, 0, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array19[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(19,v);

     int array20[4][4] = {  {0, 0, 0, 0},
                            {0, 0, 0, 0},
                            {0, 0, 0, 0},
                            {0, 0, 0, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array20[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(20,v);


     //测试数据
//    for( QMap<int, QVector< QVector<int> > >::iterator it = mData.begin();it != mData.end();it++ )
//    {
//         for(QVector< QVector<int> >::iterator it2 = (*it).begin(); it2!= (*it).end();it2++)
//         {
//            for(QVector<int>::iterator it3 = (*it2).begin(); it3 != (*it2).end(); it3++ )
//            {
//                qDebug() << *it3 ;
//            }
//         }
//         qDebug() << endl;
//    }


}

mainscene.h

#ifndef MAINSCENE_H
#define MAINSCENE_H

#include <QMainWindow>
#include "chooselevelscene.h"

QT_BEGIN_NAMESPACE
namespace Ui {
class MainScene;
}
QT_END_NAMESPACE

class MainScene : public QMainWindow
{
    Q_OBJECT

public:
    MainScene(QWidget *parent = nullptr);
    ~MainScene();

    //重写paintEvent事件 画背景图片
    void paintEvent(QPaintEvent* evt);

    ChooseLevelScene* chooseScene = NULL;

private:
    Ui::MainScene *ui;
};
#endif // MAINSCENE_H

mainscene.cpp

#include "mainscene.h"
#include "ui_mainscene.h"
#include <QPainter>
#include <QPixmap>
#include "mypushbutton.h"
#include <QDebug>
#include <QTimer>
#include <QSoundEffect> //多媒体模块下 的音效头文件

MainScene::MainScene(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainScene)
{
    ui->setupUi(this);

    //配置主场景

    //设置固定大小
    this->setFixedSize(320, 588);

    //设置图标
    this->setWindowIcon(QIcon(":/res/Coin0001.png"));

    //设置标题
    this->setWindowTitle("翻金币主场景");

    //退出按钮实现
    connect(ui->actionQuit, &QAction::triggered, [=](){
        this->close();
    });

    //准备开始按钮的音效
    QSoundEffect* startSound = new QSoundEffect();
    startSound->setSource(QUrl::fromLocalFile(":/res/TapButtonSound.wav"));
    //设置循环次数(-1代表无限循环)
    //startSound->setLoopCount(10);

    //开始按钮
    MyPushButton* startBtn = new MyPushButton(":/res/MenuSceneStartButton.png");
    startBtn->setParent(this);
    startBtn->move(this->width()*0.5 - startBtn->width()*0.5, this->height()*0.7);

    //实例化选择关卡场景
    chooseScene = new ChooseLevelScene;

    //监听选择关卡的返回按钮的信号
    connect(chooseScene, &ChooseLevelScene::chooseSceneBack, [=](){
        this->setGeometry(chooseScene->geometry());
        //隐藏选择场景
        chooseScene->hide();
        //重新显示主场景
        this->show();
    });

    connect(startBtn, &MyPushButton::clicked, [=](){
        qDebug() << "点击了开始";

        //播放开始的音效
        startSound->play();

        //做弹起特效
        startBtn->zoom1();
        startBtn->zoom2();

        //延时进入到选择关卡场景中
        QTimer::singleShot(500, this, [=](){
            //设置chooseScene场景的位置
            chooseScene->setGeometry(this->geometry());
            //自身隐藏
            this->hide();
            //显示选择关卡场景
            chooseScene->show();
        });
    });

}

MainScene::~MainScene()
{
    delete ui;
}

//重写paintEvent事件 画背景图片
void MainScene::paintEvent(QPaintEvent* evt)
{
    QPainter painter(this);
    QPixmap pix;
    pix.load(":/res/PlayLevelSceneBg.png");
    painter.drawPixmap(0, 0, this->width(), this->height(), pix);

    //画背景上图标
    pix.load(":/res/Title.png");
    pix = pix.scaled(pix.width()*0.5, pix.height()*0.5);
    painter.drawPixmap(10, 30, pix);

}

mycoin.h

#ifndef MYCOIN_H
#define MYCOIN_H

#include <QPushButton>
#include <QTimer>

class MyCoin : public QPushButton
{
    Q_OBJECT
public:
    //explicit MyCoin(QWidget *parent = nullptr);

    //参数代表传入金币路径,还是银币路径
    MyCoin(QString btnImg);

    //金币的属性
    int posX;   //x坐标位置
    int posY;   //y坐标位置
    bool flag;  //正反标识

    //改变标志的方法
    void changeFlag();
    QTimer* timer1;  //正面翻反面的定时器
    QTimer* timer2;  //反面翻正面的定时器
    int min = 1;
    int max = 8;

    //执行动画 标志
    bool isAnimation = false;

    //重写 按下
    void mousePressEvent(QMouseEvent *e);

    //是否胜利的标志
    bool isWin;

signals:
};

#endif // MYCOIN_H

mycoin.cpp

#include "mycoin.h"
#include <QPixmap>
#include <QDebug>

// MyCoin::MyCoin(QWidget *parent)
//     : QPushButton{parent}
// {}

MyCoin::MyCoin(QString btnImg)
{
    QPixmap pix;
    bool ret = pix.load(btnImg);
    if (!ret)
    {
        qDebug() << QString("图片%1加载失败").arg(btnImg);
        return;
    }

    this->setFixedSize(pix.width(), pix.height());
    this->setStyleSheet("QPushButton{border:0px;}");
    this->setIcon(pix);
    this->setIconSize(QSize(pix.width(), pix.height()));

    //初始化定时器对象
    timer1 = new QTimer(this);
    timer2 = new QTimer(this);

    //监听正面翻反面的信号,并且翻转金币
    connect(timer1, &QTimer::timeout, [=](){
        QPixmap pix;
        pix.load(QString(":/res/Coin000%1.png").arg(this->min++));

        this->setFixedSize(pix.width(), pix.height());
        this->setStyleSheet("QPushButton{border:0px;}");
        this->setIcon(pix);
        this->setIconSize(QSize(pix.width(), pix.height()));

        //判断 如果翻完了,将min重置为1
        if (this->min > this->max)
        {
            this->min = 1;
            isAnimation = false;
            timer1->stop();
        }
    });

    //监听反面翻正面的信号,并且翻转金币
    connect(timer2, &QTimer::timeout, [=](){
        QPixmap pix;
        pix.load(QString(":/res/Coin000%1.png").arg(this->max--));

        this->setFixedSize(pix.width(), pix.height());
        this->setStyleSheet("QPushButton{border:0px;}");
        this->setIcon(pix);
        this->setIconSize(QSize(pix.width(), pix.height()));

        //判断 如果翻完了,将min重置为1
        if (this->max < this->min)
        {
            this->max = 8;
            timer2->stop();
            isAnimation = false;
        }
    });

}

//改变正反面标志的方法
void MyCoin::changeFlag()
{
    //如果是正面 翻成反面
    if (this->flag)
    {
        //开始正面翻反面的定时器
        timer1->start(30);
        isAnimation = true; //开始做动画
        this->flag = false;
    }
    //反面翻正面
    else
    {
        timer2->start(30);
        isAnimation = true; //开始做动画
        this->flag = true;
    }
}

void MyCoin::mousePressEvent(QMouseEvent *e)
{
    if (this->isAnimation || this->isWin)
    {
        return;
    }

    QPushButton::mousePressEvent(e);
}

mypushbutton.h

#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H

#include <QPushButton>

class MyPushButton : public QPushButton
{
    Q_OBJECT
public:
    //explicit MyPushButton(QWidget *parent = nullptr);

    //构造函数 参数1:正常显示的图片路径;参数2:按下后显示的图片路径
    MyPushButton(QString normalImg, QString pressImg = "");

    //成员属性
    //保存用户传入的默认显示路径
    QString normalImgPath;
    //按下后显示的图片路径
    QString pressImgPath;

    //弹跳特效
    void zoom1();   //向下跳
    void zoom2();   //向上跳

    //重写按钮 按下 和 释放 事件
    void mousePressEvent(QMouseEvent *e);
    void mouseReleaseEvent(QMouseEvent *e);
signals:
};

#endif // MYPUSHBUTTON_H

mypushbutton.cpp

#include "mypushbutton.h"
#include <QPixmap>
#include <QPainter>
#include <QDebug>
#include <QSize>
#include <QPropertyAnimation>

// MyPushButton::MyPushButton(QWidget *parent)
//     : QPushButton{parent}
// {}

MyPushButton::MyPushButton(QString normalImg, QString pressImg)
{
    this->normalImgPath = normalImg;
    this->pressImgPath = pressImg;

    QPixmap pix;
    bool ret = pix.load(normalImg);
    if (!ret)
    {
        qDebug() << "图片加载失败";
        return;
    }

    //设置图片固定大小
    this->setFixedSize(pix.width(), pix.height());

    //设置不规则图片样式
    this->setStyleSheet("QPushButton{border:0px;}");

    //设置图标
    this->setIcon(pix);

    //设置图标大小
    this->setIconSize(QSize(pix.width(), pix.height()));

}

//弹跳特效 向下跳
void MyPushButton::zoom1()
{
    //创建动态对象
    QPropertyAnimation* animation = new QPropertyAnimation(this, "geometry");
    //设置动画时间间隔
    animation->setDuration(200);

    //起始位置
    animation->setStartValue(QRect(this->x(), this->y(), this->width(), this->height()));
    //结束位置
    animation->setEndValue(QRect(this->x(), this->y()+10, this->width(), this->height()));

    //设置弹跳曲线
    animation->setEasingCurve(QEasingCurve::OutBounce);

    //执行动画
    animation->start();

}

//弹跳特效 向上跳
void MyPushButton::zoom2()
{
    //创建动态对象
    QPropertyAnimation* animation = new QPropertyAnimation(this, "geometry");
    //设置动画时间间隔
    animation->setDuration(200);

    //起始位置
    animation->setStartValue(QRect(this->x(), this->y()+10, this->width(), this->height()));
    //结束位置
    animation->setEndValue(QRect(this->x(), this->y(), this->width(), this->height()));

    //设置弹跳曲线
    animation->setEasingCurve(QEasingCurve::OutBounce);

    //执行动画
    animation->start();

}


//重写按钮 按下 和 释放 事件
void MyPushButton::mousePressEvent(QMouseEvent *e)
{
    if (this->pressImgPath != "")   //传入的按下图片不为空:说明需要有按下状态,切换图片
    {
        QPixmap pix;
        bool ret = pix.load(this->pressImgPath);
        if (!ret)
        {
            qDebug() << "图片加载失败";
            return;
        }

        //设置图片固定大小
        this->setFixedSize(pix.width(), pix.height());

        //设置不规则图片样式
        this->setStyleSheet("QPushButton{border:0px;}");

        //设置图标
        this->setIcon(pix);

        //设置图标大小
        this->setIconSize(QSize(pix.width(), pix.height()));
    }

    //让父类执行其他内容
    return QPushButton::mousePressEvent(e);
}

void MyPushButton::mouseReleaseEvent(QMouseEvent *e)
{
    if (this->pressImgPath != "")   //传入的按下图片不为空:说明需要有按下状态,切换成初始图片
    {
        QPixmap pix;
        bool ret = pix.load(this->normalImgPath);
        if (!ret)
        {
            qDebug() << "图片加载失败";
            return;
        }

        //设置图片固定大小
        this->setFixedSize(pix.width(), pix.height());

        //设置不规则图片样式
        this->setStyleSheet("QPushButton{border:0px;}");

        //设置图标
        this->setIcon(pix);

        //设置图标大小
        this->setIconSize(QSize(pix.width(), pix.height()));
    }

    //让父类执行其他内容
    return QPushButton::mouseReleaseEvent(e);
}

playscene.h

#ifndef PLAYSCENE_H
#define PLAYSCENE_H

#include <QMainWindow>
#include "mycoin.h"

class PlayScene : public QMainWindow
{
    Q_OBJECT
public:
    //explicit PlayScene(QWidget *parent = nullptr);

    PlayScene(int levelNum);

    //内部成员函数 记录所选的关卡
    int levelIndex;

    //重新paintEvent事件
    void paintEvent(QPaintEvent *event);

    int gameArray[4][4];    //二维数组,维护每个关卡的具体数据

    MyCoin* coinBtn[4][4];

    //是否胜利的标志
    bool isWin;

signals:
    void chooseSceneBack();
};

#endif // PLAYSCENE_H

playscene.cpp

#include "playscene.h"
#include <QDebug>
#include <QPixmap>
#include <QMenuBar>
#include <QMenu>
#include <QPainter>
#include <QPixmap>
#include <QTimer>
#include "mypushbutton.h"
#include <QLabel>
#include <QFont>
#include "mycoin.h"
#include "dataconfig.h"
#include <QPropertyAnimation>
#include <QSoundEffect>

// PlayScene::PlayScene(QWidget *parent)
//     : QMainWindow{parent}
// {}

PlayScene::PlayScene(int levelNum)
{
    qDebug() << QString("进入了第 %1 关").arg(levelNum);
    this->levelIndex = levelNum;

    //初始化游戏场景
    //设置固定大小
    this->setFixedSize(320, 588);
    //设置图标
    this->setWindowIcon(QPixmap(":/res/Coin0001.png"));
    //设置标题
    this->setWindowTitle("翻金币场景");

    //创建菜单栏
    QMenuBar* bar = menuBar();
    this->setMenuBar(bar);

    //创建开始菜单
    QMenu* startMenu = bar->addMenu("开始");

    //创建退出 菜单项
    QAction* quitAction = startMenu->addAction("退出");

    //点击退出 实现退出游戏
    connect(quitAction, &QAction::triggered, [=](){
        this->close();
    });

    //翻金币的音效
    QSoundEffect* flipSound = new QSoundEffect();
    flipSound->setSource(QUrl::fromLocalFile(":/res/CoinFlipSound.wav"));
    //胜利的音效
    QSoundEffect* winSound = new QSoundEffect();
    winSound->setSource(QUrl::fromLocalFile(":/res/LevelWinSound.wav"));
    //返回按钮的音效
    QSoundEffect* backSound = new QSoundEffect();
    backSound->setSource(QUrl::fromLocalFile(":/res/BackButtonSound.wav"));

    //返回按钮
    MyPushButton* backBtn = new MyPushButton(":/res/BackButton.png", ":/res/BackButtonSelected.png");;
    backBtn->setParent(this);
    backBtn->move(this->width()-backBtn->width(), this->height()-backBtn->height());

    //点击返回
    connect(backBtn, &MyPushButton::clicked, [=](){
        qDebug() << "翻金币场景中:点击了返回按钮";

        //播放返回按钮的音效
        backSound->play();

        //延时返回
        QTimer::singleShot(500, this, [=](){
            //告诉主场景,我返回了,主场景监听ChooseLevelScene的返回按钮
            emit this->chooseSceneBack();
        });
    });

    //显示当前关卡号
    QLabel* label = new QLabel;
    label->setParent(this);
    QFont font;
    font.setFamily("华文新魏");
    font.setPointSize(20);
    //将字体设置到标签中
    label->setFont(font);
    label->setText(QString("Leavel: %1").arg(this->levelIndex));
    label->setGeometry(QRect(30, this->height()-50, 120, 50));

    dataConfig config;
    //初始化每个关卡的二维数组
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            this->gameArray[i][j] = config.mData[this->levelIndex][i][j];

        }
    }

    //胜利图片显示
    QLabel* winLabel = new QLabel;
    winLabel->setParent(this);
    QPixmap tmpPix;
    tmpPix.load(":/res/LevelCompletedDialogBg.png");
    winLabel->setGeometry(0, 0, tmpPix.width(), tmpPix.height());
    winLabel->setPixmap(tmpPix);
    winLabel->move((this->width()-tmpPix.width())*0.5, -tmpPix.height());


    //显示金币背景图片
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            //绘制背景图片
            QPixmap pix = QPixmap(":/res/BoardNode.png");
            QLabel* label = new QLabel;
            label->setParent(this);
            label->setGeometry(0, 0, pix.width(), pix.height());
            label->setPixmap(pix);
            label->move(57+i*50, 200+j*50);

            //创建金币
            QString str;
            if (this->gameArray[i][j] == 1)
            {
                //显示金币
                str = ":/res/Coin0001.png";
            }
            else
            {
                str = ":/res/Coin0008.png";
            }
            MyCoin* coin = new MyCoin(str);
            coin->setParent(this);
            coin->move(59+i*50, 204+j*50);

            //给金币属性赋值
            coin->posX = i;
            coin->posY = j;
            coin->flag = this->gameArray[i][j]; //1:正面,0:反面

            //将金币放入到 金币的二位数组中 以便以后的维护
            coinBtn[i][j] = coin;

            //点击金币 进行翻转
            connect(coin, &MyCoin::clicked, [=](){

                //播放翻金币的音效
                flipSound->play();

                //点击按钮 将所有的金币都先禁用
                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        this->coinBtn[i][j]->isWin = true;
                    }
                }

                coin->changeFlag();
                this->gameArray[i][j] = this->gameArray[i][j] == 0 ? 1 : 0;

                //翻转周围的金币
                //周围的金币延时翻转
                QTimer::singleShot(300, this, [=](){
                    if (coin->posX+1 <= 3)  //周围的右侧金币翻转的条件
                    {
                        coinBtn[coin->posX+1][coin->posY]->changeFlag();
                        this->gameArray[coin->posX+1][coin->posY] = this->gameArray[coin->posX+1][coin->posY] == 0 ? 1 : 0;
                    }
                    if (coin->posX-1 >= 0)  //周围的左侧金币翻转的条件
                    {
                        coinBtn[coin->posX-1][coin->posY]->changeFlag();
                        this->gameArray[coin->posX-1][coin->posY] = this->gameArray[coin->posX-1][coin->posY] == 0 ? 1 : 0;
                    }
                    if (coin->posY+1 <= 3)  //周围的上侧金币翻转的条件
                    {
                        coinBtn[coin->posX][coin->posY+1]->changeFlag();
                        this->gameArray[coin->posX][coin->posY+1] = this->gameArray[coin->posX][coin->posY+1] == 0 ? 1 : 0;
                    }
                    if (coin->posY-1 >= 0)  //周围的下侧金币翻转的条件
                    {
                        coinBtn[coin->posX][coin->posY-1]->changeFlag();
                        this->gameArray[coin->posX][coin->posY-1] = this->gameArray[coin->posX][coin->posY-1] == 0 ? 1 : 0;
                    }

                    //翻完周围金币后,将所有金币解开禁用
                    for (int i = 0; i < 4; i++)
                    {
                        for (int j = 0; j < 4; j++)
                        {
                            this->coinBtn[i][j]->isWin = false;
                        }
                    }

                    //判断是否胜利
                    this->isWin = true;
                    for (int i = 0; i < 4; i++)
                    {
                        for (int j = 0; j < 4; j++)
                        {
                            if (coinBtn[i][j]->flag == false)
                            {
                                this->isWin = false;
                                break;
                            }
                        }
                    }
                    if (this->isWin == true)
                    {
                        //添加胜利的音效
                        winSound->play();

                        qDebug() << "游戏胜利";
                        //将所有按钮的胜利标志改为true
                        for (int i = 0; i < 4; i++)
                        {
                            for (int j = 0; j < 4; j++)
                            {
                                coinBtn[i][j]->isWin = true;
                            }
                        }

                        //将胜利的图片移动下来
                        QPropertyAnimation* animation = new QPropertyAnimation(winLabel, "geometry");
                        //设置时间间隔
                        animation->setDuration(1000);
                        //设置开始位置
                        animation->setStartValue(QRect(winLabel->x(), winLabel->y(), winLabel->width(), winLabel->height()));
                        //设置结束位置
                        animation->setEndValue(QRect(winLabel->x(), winLabel->y()+114, winLabel->width(), winLabel->height()));
                        //设置缓和曲线
                        animation->setEasingCurve(QEasingCurve::OutBounce);
                        //执行动画
                        animation->start();
                    }
                });


            });
        }
    }

}

void PlayScene::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QPixmap pix;
    pix.load(":/res/PlayLevelSceneBg.png");
    painter.drawPixmap(0, 0, this->width(), this->height(), pix);

    //加载标题
    pix.load(":/res/Title.png");
    pix = pix.scaled(pix.width()*0.5, pix.height()*0.5);
    painter.drawPixmap(10, 30, pix.width(), pix.height(), pix);
}

main.cpp

#include "mainscene.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainScene w;
    w.show();
    return a.exec();
}

mainscene.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainScene</class>
 <widget class="QMainWindow" name="MainScene">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainScene</string>
  </property>
  <widget class="QWidget" name="centralwidget"/>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>25</height>
    </rect>
   </property>
   <widget class="QMenu" name="menu">
    <property name="title">
     <string>开始</string>
    </property>
    <addaction name="actionQuit"/>
   </widget>
   <addaction name="menu"/>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
  <action name="actionQuit">
   <property name="text">
    <string>退出</string>
   </property>
  </action>
 </widget>
 <resources/>
 <connections/>
</ui>

19 代码

通过网盘分享的文件:Qt.zip
链接: https://pan.baidu.com/s/1WdHz54L7LlpHU1I3jOaieg?pwd=gd8w 提取码: gd8w

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值