QT入门到实战学习笔记

学习笔记 

最新QT从入门到实战完整版|传智教育_哔哩哔哩_bilibili

目录

 1.创建一个QT文件

1.1命名规范

1.2快捷键 

2QPushButton创建

2.1防止汉语乱码 

2.2对象树

 2.3Qt窗口坐标体系

 3信号和槽机制

 3.1自定义信号和槽

 3.1.1自定义信号:

3.1.2自定义槽:

3.2自定义信号和槽发生重载

 3.2.1重载:

 3.2.2连接解决办法:

3.2.3QString输出的内容带引号解决办法:

3.3信号槽的拓展

3.3.1无参信号和槽连接

3.3.2信号连接信号

3.3.3断开信号:disconnect

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

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

3.3.6信号和槽函数的参数必须一一对应

3.3.7信号的参数个数可以比槽函数参数个数多,但是需要一一对应,反之不可

3.4Lambda表达式 

3.5Open Close控制实现案例

4.QMainWindow

 4.1菜单栏:

4.2工具栏:

 4.3状态栏:

4.4铆接部件(浮动窗口):

4.5中心部件: 

4.6全部代码 

4.7资源文件添加

5.对话框

5.1自定义消息框 

5.1.1模态创建: 

 5.1.2非模态创建:

 5.2标准对话框

 5.2.1QMessageBox下的四种对话框:

5.3其他标准对话框

 5.3.1颜色对话框:

5.3.2文件对话框:

5.3.3字体对话框: 

5.4全部代码

6.界面布局

 7.控件

 7.1按钮组

 7.2QListWidget 列表容器

 7.3QTreeWidget 树控件

  7.4QTableWidget 表格控件

7.5自定义封装控件

1.添加新文件->QT->设计师界面类

 2.在新建的.ui文件中设置QSpinBox和QSlider两个控件

 3.在widget.ui中使用自定义的控件

 4.联动效果

5.提供接口,获取数字和设置数字

8.QT中的鼠标事件

8.1鼠标进入事件enterEvent

 8.1.1在mylabel.h头文件中添加声明

8.1.2在mylabel.cpp文件中设置函数体

8.2鼠标离开事件leaveEvent

8.2.1在mylabel.h中添加声明

8.2.2在mylabel.cpp文件中设置函数体

8.3.鼠标按下   鼠标释放  鼠标移动 

8.3.1 mylabel.h中声明

8.3.2  ev->x()  ev->y()       x坐标,y坐标

8.3.3  ev->button()        判断左右键 

8.3.4  ev->buttons()        判断组合按键   

判断move时候的左右键  结合与操作符

8.3.5 设置鼠标追踪 

8.3.6 mylabel.cpp中写函数体

8.3.7格式化字符串   

9.定时器、分发器、过滤器、绘图

9.1定时器的第一种方式 

9.1.1利用事件 void timerEvent(QTimerEvent *ev)

9.1.2启动定时器 startTimer() 毫秒单位

9.1.3timerEvent的返回值是定时器的唯一标识

9.2定时器的第二种方式

9.2.1利用定时器的类  QTimer 

 9.2.2创建定时器对象

 9.2.3启动定时器 timer->start

9.2.4信号槽连接 

9.2.5暂停  timer->stop

9.3 事件分发器event

9.3.1  bool event(QEvent * e)

9.3.2  返回值若是true,则代表用户处理这个时间,不向下分发了

9.3.3   e->type() 可以判断事件

9.4事件过滤器

9.4.1给控件安装事件过滤器

9.4.2重写eventFilter(obj,e)函数

9.5 QPainter绘图

 9.5.1绘图事件  void paintEvent

9.5.2声明一个画家对象

 9.5.3画图、画文字、设置风格等

9.6  QPainter 高级设置

9.6.1抗锯齿操作  (效率较低)

9.6.2对画家进行移动

 9.6.3保存画家状态

9.6.4还原状态

9.7手动调用绘图事件

9.7.1利用画家画图片

 9.7.2利用update手动调用绘图事件

9.8 QPaintDevice绘图设备

9.8.1QPixmap

9.8.2QImage

9.8.3QPicture

10 QFile 对文件进行读写操作

 10.1读文件

 10.1.1信号槽连接按钮与文件

10.1.2将路径放在lineEdit中 

10.1.3读取的文件格式

10.1.4只读方式打开文件

10.1.5读取文件

10.1.6文件尾部

10.1.7读到的数据放入文本框

10.1.8需要转格式读取

10.1.9对文件进行关闭

10.2写文件

10.3读写文件全部代码

 10.4 QFlieInfo读取文件信息

11翻金币的案例

11.1创建项目  添加资源配置

11.2项目配置设置背景 大小 标题 背景 图标 

11.2.1配置大小、图标、标题、退出按钮

11.2.2配置背景 

11.3创建开始按钮

       11.3.1 封装自定义的按钮 MyPushButton

        11.3.2构造函数(默认显示图片,按下后显示图片)

        11.3.3开始制作特效zoom1,zoom2

11.4创建选择关卡场景

        11.4.1点击开始按钮后延时进入到选择关卡场景

       11.4.2 配置选择关卡场景(设置背景 大小 标题 背景 图标) 

        11.4.3创建返回按钮

         11.4.4返回关卡的返回按钮特效切换

11.4.5 开始场景与选择关卡场景的切换

11.5选择关卡按钮创建

11.5.1单个for循环创建矩阵 

 11.5.2按钮上设置显示关卡数

11.6翻金币场景的基本配置

11.6.1配置游戏场景(设置背景 大小 标题 背景 图标) 

11.6.2实现返回按钮可以返回上一场景 

11.6.3实现显示关卡的label

 11.7创建金币类

 11.7.1先将金币的背景图案放入PlayScene中

11.7.2创建MyCoin自定义金币按钮类

11.7.3在playscene创建所有的金币按钮

11.8每个关卡的默认显示

11.9翻金币特效

 11.9.1给每个硬币加属性  posx  posy  bool flag

11.9.2给MyCoin加函数

11.9.3监听信号并翻转

11.9.4解决快速点击效果不好的问题

11.9.5点击硬币周围一起翻转

11.9.6判断胜利

11.9.7胜利图片设置

11.9.8音效设置

11.9.9每个场景保持一个位置

 11.10项目打包及游戏扩展


 1.创建一个QT文件

  •  点击创建项目,选择项目路径以及名称(不能含中文)
  •  默认创建有窗口类,基类有三种选择:Qwidget,QmyWindow,QDialog.main.cpp介绍
  • main函数:看注释
#include "widget.h"

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


//main程序入口,argc命令行变量的数量,argvming命令行变量的数组
int main(int argc, char *argv[])
{
    //a 应用程序对象,在Qt中,应用程序对象,有且只有一个
    QApplication a(argc, argv);

    QTranslator translator;
    const QStringList uiLanguages = QLocale::system().uiLanguages();
    for (const QString &locale : uiLanguages) {
        const QString baseName = "test01_" + QLocale(locale).name();
        if (translator.load(":/i18n/" + baseName)) {
            a.installTranslator(&translator);
            break;
        }
    }
    //窗口对象
    Widget w;
    //窗口对象,默认不会显示,必须要调用show方法显示窗口
    w.show();

    //让应用程序对象 a 进入消息循环机制,让代码停留在这行
    return a.exec();
}

1.1命名规范

类名:首字母大写,单词和单词之间首字母大写

函数名 变量名称:首字母小写,单词和单词之间首字母大写

1.2快捷键 

注释 :ctrl + /

运行: ctrl + r

编译: ctrl + b

字体缩放: ctrl + 鼠标滚轮

查找: ctrl + f

整行移动: ctrl + shift + ↑或↓

帮助文档:F1        

自动对齐:ctrl + i

同名之间的.h和.cpp切换:f4

2QPushButton创建

 创建QPushButtn *btn = new QPushButton

设置父亲  setParent(this)

设置文本   setText("文字")

设置位置   move(宽,高)

重新指定窗口大小  resize

设置窗口标题   setWindowTitle("窗口");

设置固定窗口大小   setFixedSize(600,600);

 mainwindow.cpp

#include "mainwindow.h"
#include<QPushButton>//按钮头文件
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    //创建一个按钮
    QPushButton *btn = new QPushButton;
    //btn->show();//show以顶层方式弹出控件
    btn->setParent(this);

    //重新制定按钮大小
    btn->resize(100,100);

    //显示文本
    btn->setText("first");

    //创建第二个按钮  按照控件大小创建窗口
    QPushButton *btn2=new QPushButton("second",this);

    //移动btn2按钮
    btn2->move(100,100);

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

    //设置窗口标题
    setWindowTitle("窗口");

    //设置固定窗口大小
    setFixedSize(600,600);
}

MainWindow::~MainWindow()
{
}

2.1防止汉语乱码 

哪个文件需要,就在哪个上面加这行代码 

#pragma execution_character_set("utf-8")//防止乱码

 打开选项->文本编辑器->行为,如图设置

 打开编辑->select enconding如图设置

 

2.2对象树

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

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

 2.3Qt窗口坐标体系

 以左上角为远点(0,0),X向右增加,Y向下增加

 3信号和槽机制

connect(发送者,信号(函数地址),接收者,槽函数)

connect(  mybtn  ,  &QPushButton::clicked  ,  this  ,  &MainWindow::close  );

 3.1自定义信号和槽

自定义老师->饿了->学生->请客吃饭(饿了是信号,吃饭是槽)

创建老师和学生的类(Teacher;Student)->头文件声明->源文件槽函数实现

头文件声明时:

 3.1.1自定义信号:

        自定义信号,写到signals下
        返回值是void,只需要声明,不需要实现
        可以有参数,可以重载

signals:
    void hungry();

3.1.2自定义槽:

        早期版本qt,必须写到public slots,高级版本可以下到public或者全局函数下

        返回值是void,需要声明,也需要实现

        可以有参数,可以发生重载

public slot:
    void treat();

 >源文件的槽函数实现: 

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

 Widget.cpp文件:

Widget::Widget(QWidget *parent): QWidget(parent)
{
 //创建一个老师的对象
    this->zt=new Teacher(this);
    //创建一个学生的对象
    this->st=new Student(this);
    //老师饿了 学生请客吃饭连接
    connect(zt,&Teacher::hungry,st,&Student::treat);
    //调用下课函数
    classIsOver();//有顺序的,需要先连接再调用
}

void Widget::classIsOver()
{
    //下课函数,调用后,老师饿了
    emit zt->hungry();//触发的关键字:emit
}
void Widget::classIsOver()
{
    //下课函数,调用后,老师饿了
    //emit zt->hungry();//触发的关键字:emit
    emit zt->hungry("烤腰子");
}

 触发信号的关键字:emit 

3.2自定义信号和槽发生重载

 3.2.1重载:

teacher.h文件中:

signals:
    void hungry();
    void hungry(QString foodNname);

 student.h文件中:

public slot:
    void treat();
    void treat(QString foodName);

 槽函数(学生请客吃饭)实现:

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

 3.2.2连接解决办法:

 需要利用函数指针,明确指向函数的地址

    void(Teacher::*teacherSignal)(QString)=&Teacher::hungry;
    void(Student::*studentSlot)(QString) = &Student::treat;
    connect(zt,teacherSignal,st,studentSlot);//有参

3.2.3QString输出的内容带引号解决办法:

qDebug()<<"请老师吃饭,老师要吃:"<<foodName;

 

解决方法: 

QString->char* 先转成QByerArray(.toUtf8())再转char*()
qDebug()<<"请老师吃饭,老师要吃:"<<foodName.toUtf8().data();

3.3信号槽的拓展

 设置一下:点击一个按钮,触发下课信号

QPushButton *btn=new QPushButton("下课",this);
connect(btn,&QPushButton::clicked,this,&Widget::classIsOver);//按钮->触发->下课

3.3.1无参信号和槽连接

    void(Teacher::*teacherSignal2)(void)=&Teacher::hungry;
    void(Student::*studentSlot2)(void) = &Student::treat;
    connect(zt,teacherSignal2,st,studentSlot2);

3.3.2信号连接信号

(按钮->老师饿了->学生请客)

    connect(zt,teacherSignal2,st,studentSlot2);
    connect(btn,&QPushButton::clicked,zt,teacherSignal2);

3.3.3断开信号:disconnect

disconnect(zt,teacherSignal2,st,studentSlot2);

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

    connect(btn,&QPushButton::clicked,zt,teacherSignal2);
    connect(btn,&QPushButton::clicked,this,&Widget::close);

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

3.3.6信号和槽函数的参数必须一一对应

3.3.7信号的参数个数可以比槽函数参数个数多,但是需要一一对应,反之不可

3.4Lambda表达式 

[](){};

    [=](){
        btn->setText("放学");
    }();

 []时Lambda的开始,必须存在,不能省略

中括号内:

=:值传递;        &:引用传递;        this:类似于=;        a:将a按值进行传递;

&a:将a按引用进行传递;                & ,a , b :除a,b值传递,其他都是引用传递;        

= ,&a ,&b:除a,b引用传递,其他都是值传递

小括号内:

 标识重载的()操作符的参数,没有参数时可以不写

参数可以通过按值和按引用两种方式进行传递

可修改标识符:

 mutable:修改按值传递进来的拷贝的值,而非修改本体。这部分可以省略

 函数返回值:

 ->返回值类型,标识函数返回值的类型,但返回值为void时,或者函数体中只有一处return的地方(此时编译器可以自动推断除返回值类型)时,这部分可以省略

 函数体:

{},标识函数的实现,这部分不能省略,但函数体可以为空 

 lambda表达式的使用:

第三个表达式时this时,可以省略

    //利用lambda表达式实现点击按钮关闭窗口
    QPushButton *btn2=new QPushButton("关闭",this);
    btn2->move(300,0);

    connect(btn2,&QPushButton::clicked,this,[=](){
        this->close();
        emit zt->hungry("烤腰子");
        btn2->setText("aaa");
    });

3.5Open Close控制实现案例

#include "widget.h"
#include<QPushButton>
#pragma execution_character_set("utf-8")//防止乱码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    QWidget *New_Window = new QWidget;
    New_Window->setWindowTitle("点击open出现的");
    QPushButton *btn = new QPushButton("Open",this);
    btn->resize(100,50);
    btn->move(300,400);
    resize(800,800);
    setWindowTitle("黑马练习一");

    connect(btn,&QPushButton::clicked,New_Window,[=](){
        if(btn->text()=="Open")
        {
            New_Window->show();
            btn->setText("Close");
        }
        else
        {
            New_Window->close();
        }
    });
}

Widget::~Widget()
{
}

4.QMainWindow

 4.1菜单栏:

QMenuBar *bar = menuBar();//创建菜单栏,菜单栏只能有一个

setMenuBar(bar);//将菜单栏放入到窗口中


QMenu * fileMenu=bar->addMenu("文件");    //创建菜单
QMenu * editMenu=bar->addMenu("编辑");    //返回的是QMenu *

   
fileMenu->addAction("新建");//创建菜单项目,返回的是QAction *
fileMenu->addSeparator();//添加分隔线
fileMenu->addAction("打开");

4.2工具栏:


    QToolBar *toolBar = new QToolBar(this);  //工具栏 ,可以有多个

    //将工具栏放在窗口中addToolBar
    addToolBar(Qt::LeftToolBarArea,toolBar);//参数一:自定义工具栏默认位置

    //后期设置  只允许 左右停靠
    toolBar->setAllowedAreas(Qt::LeftToolBarArea|Qt::RightToolBarArea);

    //设置浮动操作
    toolBar->setFloatable(0);//bool类型,0代表不允许浮动

    //设置移动(总开关)
    toolBar->setMovable(0);//bool型,0-不允许移动,1-允许


    toolBar->addAction("新建");    //工具栏中可以 设置内容
    toolBar->addSeparator();//分割线
    toolBar->addAction("打开");

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

 4.3状态栏:

    QStatusBar *stBar= statusBar(); //状态栏  最多只能有一个

    setStatusBar(stBar);    //设置在窗口中

    QLabel *label = new QLabel("提示信息",this);    //放标签控件
    stBar->addWidget(label);//左侧

    QLabel *label2 = new QLabel("右侧提示信息",this);
    stBar->addPermanentWidget(label2);//右侧

4.4铆接部件(浮动窗口):


    QDockWidget *dockwidget = new QDockWidget("浮动",this);//铆接部件(浮动窗口) 可以有多个
    addDockWidget(Qt::BottomDockWidgetArea,dockwidget);

    //设置后期停靠区域,只允许上下
    dockwidget->setAllowedAreas(Qt::TopDockWidgetArea|Qt::BottomDockWidgetArea);

4.5中心部件: 


    //设置中心部件  只能有一个
    QTextEdit * edit = new QTextEdit(this);
    setCentralWidget(edit);

4.6全部代码 

#include "mainwindow.h"
#pragma execution_character_set("utf-8")//防止乱码
#include<QMenuBar>
#include<qtoolbar.h>
#include<QDebug>
#include<QPushButton>
#include<QStatusBar>
#include<QLabel>
#include<QDockWidget>
#include<QTextEdit>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    resize(600,600);//重置窗口

    //创建菜单栏,菜单栏只能有一个
    QMenuBar *bar = menuBar();
    //将菜单栏放入到窗口中
    setMenuBar(bar);

    //创建菜单
    QMenu * fileMenu=bar->addMenu("文件");
    QMenu * editMenu=bar->addMenu("编辑");

    //创建菜单项目
    fileMenu->addAction("新建");
    //添加分隔线
    fileMenu->addSeparator();
    fileMenu->addAction("打开");


    //工具栏 ,可以有多个
    QToolBar *toolBar = new QToolBar(this);
    //将工具栏放在窗口中addToolBar
    addToolBar(Qt::LeftToolBarArea,toolBar);//自定义工具栏默认位置

    //后期设置  只允许 左右停靠
    toolBar->setAllowedAreas(Qt::LeftToolBarArea|Qt::RightToolBarArea);

    //设置浮动操作
    toolBar->setFloatable(0);//bool类型,0代表不允许浮动
    //设置移动(总开关)
    toolBar->setMovable(0);//bool型,0-不允许移动,1-允许

    //工具栏中可以 设置内容
    toolBar->addAction("新建");
    toolBar->addSeparator();//分割线
    toolBar->addAction("打开");
    //工具栏中添加控件
    QPushButton *btn = new QPushButton("open",this);
    toolBar->addWidget(btn);

    //状态栏  最多只能有一个
    QStatusBar *stBar= statusBar();
    //设置在窗口中
    setStatusBar(stBar);
    //放标签控件
    QLabel *label = new QLabel("提示信息",this);
    stBar->addWidget(label);//左侧
    QLabel *label2 = new QLabel("右侧提示信息",this);
    stBar->addPermanentWidget(label2);//右侧

    //铆接部件(浮动窗口) 可以有多个
    QDockWidget *dockwidget = new QDockWidget("浮动",this);
    addDockWidget(Qt::BottomDockWidgetArea,dockwidget);
    //设置后期停靠区域,只允许上下
    dockwidget->setAllowedAreas(Qt::TopDockWidgetArea|Qt::BottomDockWidgetArea);



    //设置中心部件  只能有一个
    QTextEdit * edit = new QTextEdit(this);
    setCentralWidget(edit);

}

MainWindow::~MainWindow()
{
}

4.7资源文件添加

1.将图片文件拷贝到项目文件下

2.创建一个新文件,右键项目->添加新文件->Qt->Qt Resource File->起名

3.起名res->生成res.qrc

4.res.qrc打开方式:右键->open  in editor

5.添加前缀->添加文件

6.使用”:+前缀名+文件名“

    //一般
    ui->actionnew->setIcon(QIcon("D:\\photo\\a.jpg"));

    //使用添加QT资源  ":+前缀名+文件名"
    ui->actionnew->setIcon(QIcon(":/new/prefix1/photo/a.jpg"));

5.对话框

对话框  分类:模态对话框(不可以对其他窗口进行操作)和 非模态对话框(可以对其他窗口进行操作)

5.1自定义消息框 

5.1.1模态创建: 

        //模态创建  有阻塞功能
        QDialog dlg(this);
        dlg.resize(200,100);
        dlg.exec();

 5.1.2非模态创建:


        //非模态对话框创建,防止一闪而过,所以创建在堆区
        QDialog  *dlg2=new QDialog(this);
        dlg2->resize(500,100);
        dlg2->setAttribute(Qt::WA_DeleteOnClose);//关闭小对话框时会释放堆区数据
        dlg2->show();

 5.2标准对话框

 标准对话框是Qt内置的一系列对话框。

Qt的内置对话框大致分为以下基类:

QClorDialog:        选择颜色

QFileDialog:        选择文件或者目录

QFontDialog:        选择字体

QInputDialog:        允许用户输入一个值,并将其值返回

QMessageBox:        模态对话框,用于显示信息,询问问题等

QPageSetupDialog:        为打印机提供纸张相关的选项

QPrintPreviewDialog:        打印预览

QProngressDialog:        显示操作过程

 5.2.1QMessageBox下的四种对话框:

        //错误对话框
        QMessageBox::critical(this,"错误提示","出错了404");

        //信息对话框
        QMessageBox::information(this,"提示","5+3=8");
//问题对话框question(父亲,标题,内容,按键类型,默认按键)
        if(QMessageBox::Save==QMessageBox::question(this,"问题对话框","who is who?",QMessageBox::Save|QMessageBox::Cancel,QMessageBox::Cancel))
        {
                qDebug()<<"选择的是save";
        }
        else if(QMessageBox::Cancel==QMessageBox::question(this,"问题对话框","who is who?",QMessageBox::Save|QMessageBox::Cancel,QMessageBox::Cancel))
        {
            qDebug()<<"选择的是Cancel";
        }
        //警告对话框
        QMessageBox::warning(this,"警告","你小子今晚别睡太死!");

5.3其他标准对话框

 5.3.1颜色对话框:


        //其他标准对话框
        QColor  color =QColorDialog::getColor(QColor(255,0,0));//返回值是QColor类型
        qDebug()<<color.red();

5.3.2文件对话框:


        //文件对话框QFileDialog::getOpenFileName(父亲,标题,默认打开路径,过滤文件格式)
        //返回值是选取的路径
        QString str = QFileDialog::getOpenFileName(this,"打开文件","E:\\Project\\QT_project\\HeiMa_Class\\HeiMa_SecondDay_03","(*.txt)");//返回值QString
        qDebug()<<str;

5.3.3字体对话框: 

        //选择字体对话框
        bool flag;
        QFont font = QFontDialog::getFont(&flag,QFont("仿宋",36));
        qDebug()<<font.

5.4全部代码

#include "mainwindow.h"
#include "ui_mainwindow.h"
#pragma execution_character_set("utf-8")//防止乱码
#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,[=](){
//        //对话框  分类:模态对话框(不可以对其他窗口进行操作)和 非模态对话框(可以对其他窗口进行操作)
//        //模态创建  有阻塞功能
//        QDialog dlg(this);
//        dlg.resize(200,100);
//        dlg.exec();


//        qDebug()<<"模态对话框弹出了";

//        //非模态对话框创建,防止一闪而过,所以创建在堆区
//        QDialog  *dlg2=new QDialog(this);
//        dlg2->resize(500,100);
//        dlg2->setAttribute(Qt::WA_DeleteOnClose);//关闭小对话框时会释放堆区数据
//        dlg2->show();



        //消息对话框
        //错误对话框
        //QMessageBox::critical(this,"错误提示","出错了404");
        //信息对话框
        //QMessageBox::information(this,"提示","5+3=8");
        //问题对话框question(父亲,标题,内容,按键类型,默认按键)
//        if(QMessageBox::Save==QMessageBox::question(this,"问题对话框","who is who?",QMessageBox::Save|QMessageBox::Cancel,QMessageBox::Cancel))
//        {
//                qDebug()<<"选择的是save";
//        }
//        else if(QMessageBox::Cancel==QMessageBox::question(this,"问题对话框","who is who?",QMessageBox::Save|QMessageBox::Cancel,QMessageBox::Cancel))
//        {
//            qDebug()<<"选择的是Cancel";
//        }
        //警告对话框
        //QMessageBox::warning(this,"警告","你小子今晚别睡太死!");

        //其他标准对话框
        //QColor  color =QColorDialog::getColor(QColor(255,0,0));//返回值是QColor类型
        //qDebug()<<color.red();

        //文件对话框QFileDialog::getOpenFileName(父亲,标题,默认打开路径,过滤文件格式)
        //返回值是选取的路径
        //QString str = QFileDialog::getOpenFileName(this,"打开文件","E:\\Project\\QT_project\\HeiMa_Class\\HeiMa_SecondDay_03","(*.txt)");//返回值QString
        //qDebug()<<str;

        //选择字体对话框
        bool flag;
        QFont font = QFontDialog::getFont(&flag,QFont("仿宋",36));
        qDebug()<<font;
    });
}

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

6.界面布局

 ->实现登录窗口,利用布局方式对窗口进行美化

->选取widget进行布局,水平布局,垂直布局,栅格布局(几行几列的时候用)

->给用户名、密码、登录、退除按钮进行布局

->默认窗口和控件之间有9像素间隙,可以选中窗口,在layout中可以修改

->利用弹簧进行布局

 7.控件

 7.1按钮组

QPushButton  常用按钮

QToolButton 工具按钮,一般用于显示图片,如果想显示文字,修改风格toolbuttonStyle,突起风格:autoRaise

Radio Button  单选按钮,设置默认 setchecked(true)

checkbox  多选按钮,监听状态,2是选中,1是半选,0是未选

 7.2QListWidget 列表容器

    //利用listwidget写诗
    QListWidgetItem * item = new QListWidgetItem("锄禾日当午");
    //将这行诗放到listwidget中
    ui->listWidget->addItem(item);
    item->setTextAlignment(Qt::AlignHCenter);//设置水平剧中

    //第二种方法,没办法居中,但是可以一次多行
    //QStringList   QList<QString>
    QStringList  list;
    list <<"锄禾日当午"<<"汗滴禾下土"<<"谁知盘中餐"<<"粒粒皆辛苦";
    ui->listWidget->addItems(list);

 7.3QTreeWidget 树控件

 //treewidget树控件使用

    //设置水平头
    ui->treeWidget->setHeaderLabels(QStringList()<<"英雄"<<"英雄介绍");
 //设置力量
    QTreeWidgetItem *poweritem = new QTreeWidgetItem(QStringList()<<"力量");
    //加载顶层的节点
    ui->treeWidget->addTopLevelItem(poweritem);
    //设置敏捷
    QTreeWidgetItem *minjieitem = new QTreeWidgetItem(QStringList()<<"敏捷");
    //
    ui->treeWidget->addTopLevelItem(minjieitem);
    //设置速度
    QTreeWidgetItem *zhiliitem = new QTreeWidgetItem(QStringList()<<"智力");
    //
    ui->treeWidget->addTopLevelItem(zhiliitem);
    //追加子节点
    QStringList list;
    list<<"四大金刚i上看到你告诉官方";
    QTreeWidgetItem *l1 = new QTreeWidgetItem(list);
    poweritem->addChild(l1);

  7.4QTableWidget 表格控件

    //设置列数
    ui->tableWidget->setColumnCount(3);//3列

    //设置水平表头
    ui->tableWidget->setHorizontalHeaderLabels(QStringList()<<"姓名"<<"性别"<<"年龄");
    //设置行数
    ui->tableWidget->setRowCount(5);

 QList<QString>nameList; == QStringList nameList;

    //设置正文
    //第一种可以这样写
    //ui->tableWidget->setItem(0,0,new QTableWidgetItem("亚瑟"));//0行0列

    //也可以for循环
    QList<QString>nameList;
    nameList<<"亚瑟"<<"安其拉"<<"赵云"<<"张飞"<<"孙悟空";

    QList<QString>sexList;
    sexList<<"男"<<"女"<<"男"<<"男"<<"未知";

    for(int i=0;i<5;i++)
    {
        int col=0;
        ui->tableWidget->setItem(i,col++,new QTableWidgetItem(nameList[i]));
        ui->tableWidget->setItem(i,col++,new QTableWidgetItem(sexList.at(i)));
        //int转QString
        ui->tableWidget->setItem(i,col++,new QTableWidgetItem(QString::number(i+18)));
    }

7.5自定义封装控件

1.添加新文件->QT->设计师界面类

 2.在新建的.ui文件中设置QSpinBox和QSlider两个控件

 3.在widget.ui中使用自定义的控件

 拖拽widget控件,右键提升窗口成刚才设置的ui文件名

 4.联动效果

在新建的.cpp文件中设置信号槽联动 

  //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);

5.提供接口,获取数字和设置数字

 在widget.ui中提供两个按钮

在新建的.h文件中添加声明

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

    int getNum();//获取 数字

然后在新建的.cpp文件中构建函数体

void SmallWidge::setNum(int num)//设置 数字
{
    ui->spinBox->setValue(num);
}

int SmallWidge::getNum()//获得  数字
{
    return ui->spinBox->value();
}

然后在widget.cpp文件中添加信号槽的联动

 //点击获取  获取值
    connect(ui->btnGet,&QPushButton::clicked,[=](){
        qDebug()<<ui->widget->getNum();
    });
    //点击设置  设置到一半
    connect(ui->btnSet,&QPushButton::clicked,[=](){
        ui->widget->setNum(50);

8.QT中的鼠标事件

在widget.ui中设置一个label

然后新建一个C++类,名为mylabel(包含.h,.cpp) 

注意:mylabel类应继承QLabel

8.1鼠标进入事件enterEvent

 8.1.1在mylabel.h头文件中添加声明

    //鼠标进入
    void enterEvent(QEvent *event);

8.1.2在mylabel.cpp文件中设置函数体

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

8.2鼠标离开事件leaveEvent

8.2.1在mylabel.h中添加声明

    //鼠标离开
    void leaveEvent(QEvent *event);

8.2.2在mylabel.cpp文件中设置函数体

void myLabel::leaveEvent(QEvent *event)
{
    //qDebug()<<"鼠标退出了";
}

8.3.鼠标按下   鼠标释放  鼠标移动 

8.3.1 mylabel.h中声明

    virtual void mousePressEvent(QMouseEvent *ev);//鼠标按下

    virtual void mouseReleaseEvent(QMouseEvent *ev);//鼠标释放

    virtual void mouseMoveEvent(QMouseEvent *ev);//鼠标移动

8.3.2  ev->x()  ev->y()       x坐标,y坐标

QString("x=%1  y=%2  globalX=%3  globalY=%4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());

8.3.3  ev->button()        判断左右键 

左为Qt::LeftButton 右为Qt::RightButton 

void myLabel::mousePressEvent(QMouseEvent *ev)
{
    //鼠标左键按下  提示信息
    if(ev->button()==Qt::LeftButton)
    {
    }
}

8.3.4  ev->buttons()        判断组合按键   

判断move时候的左右键  结合与操作符

void myLabel::mouseMoveEvent(QMouseEvent *ev)
{
    if(ev->buttons()&Qt::LeftButton)//位与运算符 同真才为真
    {
    }
}

8.3.5 设置鼠标追踪 

    //设置鼠标追踪,鼠标放上去不需要点击即可打印
    setMouseTracking(true);

8.3.6 mylabel.cpp中写函数体

#include "mylabel.h"
#include<QDebug>
#include<QMouseEvent>
#pragma execution_character_set("utf-8")//防止乱码
myLabel::myLabel(QWidget *parent)
    : QLabel{parent}
{
    //设置鼠标追踪,鼠标放上去不需要点击即可打印
    setMouseTracking(true);
}

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

void myLabel::leaveEvent(QEvent *event)
{
    qDebug()<<"鼠标退出了";
}

void myLabel::mousePressEvent(QMouseEvent *ev)
{
    //鼠标左键按下  提示信息
    if(ev->button()==Qt::LeftButton)
    {
    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;
    }
}

void myLabel::mouseReleaseEvent(QMouseEvent *ev)
{
    if(ev->button()==Qt::LeftButton)
    {
    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;
    }
}

void myLabel::mouseMoveEvent(QMouseEvent *ev)
{
    if(ev->buttons()&Qt::LeftButton)//位与运算符 同真才为真
    {
        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;
    }
}

8.3.7格式化字符串   

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;

9.定时器、分发器、过滤器、绘图

9.1定时器的第一种方式 

9.1.1利用事件 void timerEvent(QTimerEvent *ev)

widget.h中写: 

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

9.1.2启动定时器 startTimer() 毫秒单位

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

9.1.3timerEvent的返回值是定时器的唯一标识

 timerEvent的返回值是定时器的唯一标识可以和ev->timerId做比较

 widget.h中写:

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

widget.cpp中写: 

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

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //启动定时器
    id1=startTimer(1000);//参数1:间隔,单位是毫秒ms

    id2=startTimer(2000);
}
void Widget::timerEvent(QTimerEvent *ev)
{
    if(ev->timerId()==id1)
    {static int num =1;
    //label_2每隔1秒+1
    ui->label_2->setText(QString::number(num++));}
     if(ev->timerId()==id2)
    {//label_3每隔2秒+1
    static int num2 =1;
    ui->label_3->setText(QString::number(num2++));}
}
Widget::~Widget()
{
    delete ui;
}

9.2定时器的第二种方式

9.2.1利用定时器的类  QTimer 

#include<QTimer>//定时器的类

 9.2.2创建定时器对象

    QTimer *timer = new QTimer(this);//创建定时器对象

 9.2.3启动定时器 timer->start

    //启动定时器
    timer->start(500);//0.5s

9.2.4信号槽连接 

    connect(timer,&QTimer::timeout,[=](){
        static int num =1;//信号:timeout,进行监听
        ui->label_4->setText(QString::number(num++));
    });

9.2.5暂停  timer->stop

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

9.3 事件分发器event

 用于事件分发,也可以做拦截操作,但是不建议

9.3.1  bool event(QEvent * e)


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

9.3.2  返回值若是true,则代表用户处理这个时间,不向下分发了

bool myLabel::event(QEvent *e)
{
    //如果是鼠标按下,事件分发器中做拦截操作
    if(e->type()==QEvent::MouseButtonPress)
    {
        QMouseEvent *ev=static_cast<QMouseEvent *>(e);//将e转换为ev
        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);
}

9.3.3   e->type() 可以判断事件

bool myLabel::event(QEvent *e)
{
    //如果是鼠标按下,事件分发器中做拦截操作
    if(e->type()==QEvent::MouseButtonPress)
    {}
}

9.4事件过滤器

 

 在程序将事件分发到事件分发器前,可以利用过滤器做拦截

9.4.1给控件安装事件过滤器

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

9.4.2重写eventFilter(obj,e)函数

    //重写事件过滤器的事件
    bool eventFilter(QObject *,QEvent *);
 //2.重写eventfilter事件
bool Widget::eventFilter(QObject *obj, QEvent *e)
{
    if(obj==ui->label)
    {
        if(e->type()==QEvent::MouseButtonPress)
        {
            QMouseEvent *ev=static_cast<QMouseEvent *>(e);//将e转换为ev
            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,e);
}

9.5 QPainter绘图

 9.5.1绘图事件  void paintEvent

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

9.5.2声明一个画家对象

    //实例化画家对象  this指定的是绘图的设备
    QPainter painter(this);

 9.5.3画图、画文字、设置风格等

void Widget::paintEvent(QPaintEvent *)
{
    //实例化画家对象  this指定的是绘图的设备
    QPainter painter(this);

    //设置画笔
    QPen pen(QColor(255,0,0));
    //设置画笔宽度
    pen.setWidth(3);
    //设置画笔风格
    pen.setStyle(Qt::DotLine);
    //使用画笔
    painter.setPen(pen);
    //设置画刷
    QBrush brush(Qt::cyan);
    //设置画刷风格
    brush.setStyle(Qt::Dense7Pattern);
    //使用画刷
    painter.setBrush(brush);
    //划线
    painter.drawLine(QPoint(0,0),QPoint(100,100));
    //画圆
    painter.drawEllipse(QPoint(100,100),50,50);
    //❀矩形
    painter.drawRect(QRect(200,200,200,50));
    //画文字
    painter.drawText(QRect(50,200,150,50),"好好学习,天天向上");

}

9.6  QPainter 高级设置

9.6.1抗锯齿操作  (效率较低)

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

9.6.2对画家进行移动

painter.translate(100,0);

 9.6.3保存画家状态

painter.save();

9.6.4还原状态

painter.restore();

高级设置: 

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

    //画矩形
    painter.drawRect(QRect(20,20,50,50));
    //让画家移动位置
    painter.translate(100,0);
    //保存画家状态
    painter.save();
    painter.drawRect(QRect(20,20,50,50));

    painter.translate(100,0);
    //还原画家保存状态
    painter.restore();
    painter.drawRect(QRect(20,20,50,50));

9.7手动调用绘图事件

9.7.1利用画家画图片

painter.drawPixmap(posX,0,QPixmap(":/xinglixiang1.jpg"));

 9.7.2利用update手动调用绘图事件

    //点击移动按钮  移动图片
    connect(ui->pushButton,&QPushButton::clicked,[=](){
    //如果手动调用绘图事件  用update更新
        posX+=20;
        update();
    /利用画家  画资源图片///
    QPainter painter(this);
    //如果超出屏幕 从0开始
    if(posX>this->width())
    {
        posX = 0;
    }
    painter.drawPixmap(posX,0,QPixmap(":/xinglixiang1.jpg"));

9.8 QPaintDevice绘图设备

 QPixmap,QBitmap(黑白色),QPicture,QWidget;QImage

9.8.1QPixmap

    /pixmap绘图设备  专门为平台做了显示的优化///
    QPixmap pix(500,500);

    //填充颜色
    pix.fill(Qt::red);
    //声明画家
    QPainter painter(&pix);
    painter.setPen(QPen(Qt::green));
    painter.drawEllipse(QPoint(250,250),100,100);

    //保存
    pix.save("E:\\pix.png");

9.8.2QImage

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

 可以对像素进行访问

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

    //修改像素点
    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);
}

9.8.3QPicture

    ///QPicture 绘图设备   可以记录和重现绘图指令///
    QPicture pic;
    QPainter painter;
    painter.begin(&pic);//开始往pic画

    painter.setPen(QPen(Qt::cyan));
    painter.drawEllipse(QPoint(250,250),100,100);

    painter.end();//结束画画
    //保存
    pic.save("E:\\pic.syh");

 可以记录和重现绘图指令

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

10 QFile 对文件进行读写操作

 设置一个ui界面如下

 准备一个txt文档

 10.1读文件

 10.1.1信号槽连接按钮与文件

 //点击选取文件按钮,弹出文件对话框
    connect(ui->pushButton,&QPushButton::clicked,[=](){
        QString path = QFileDialog::getOpenFileName(this,"打开文件","E:\\杂七杂八\\长恨歌.txt");

以下代码均在信号槽连接中: 

10.1.2将路径放在lineEdit中 

        //将路径放在lineEdit中
        ui->lineEdit->setText(path);

10.1.3读取的文件格式

QFile默认支持的格式是utf-8
        //编码格式类
        QTextCodec *codec = QTextCodec::codecForName("gbk");

10.1.4只读方式打开文件

        QFile file(path);//参数就是读取文件的路径
        //设置打开方式
        file.open(QIODevice::ReadOnly);//只读

10.1.5读取文件

全部读取 

QByteArray array = file.readAll();

一行一行读取 

        QByteArray array;
        while(!file.atEnd())//文件尾的条件
        {array += file.readLine();//按行读
        };

10.1.6文件尾部

file.atEnd()

10.1.7读到的数据放入文本框

         //将读到的数据放入textEdit
        ui->textEdit->setText(array);

10.1.8需要转格式读取

        //转格式
        ui->textEdit->setText(codec->toUnicode(array));
        file.open(QIODevice::Append);//用追加的方式进行写
        file.write("十多年佛山呢过分啊");
        file.close();

10.1.9对文件进行关闭

        file.close();

10.2写文件

        file.open(QIODevice::Append);//用追加的方式进行写
        file.write("十多年佛山呢过分啊");
        file.close();

10.3读写文件全部代码

#include "widget.h"
#include "ui_widget.h"
#pragma execution_character_set("utf-8")//防止乱码
#include<QFileDialog>
#include<QFile>
#include<QTextCodec>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //点击选取文件按钮,弹出文件对话框
    connect(ui->pushButton,&QPushButton::clicked,[=](){
        QString path = QFileDialog::getOpenFileName(this,"打开文件","E:\\杂七杂八\\长恨歌.txt");
        //将路径放在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();

        QByteArray array;
        while(!file.atEnd())//文件尾的条件
        {array += file.readLine();//按行读
        };


        //将读到的数据放入textEdit
        ui->textEdit->setText(array);
        //转格式
        //ui->textEdit->setText(codec->toUnicode(array));

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




        //进行写文件
        file.open(QIODevice::Append);//用追加的方式进行写
        file.write("十多年佛山呢过分啊");
        file.close();
    });
}

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

 10.4 QFlieInfo读取文件信息

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

11翻金币的案例

翻金币资源: https://pan.baidu.com/s/1EV-Wph01AKy69C3Orwqw2g#list/path=%2F

11.1创建项目  添加资源配置

        创建一个项目,然后将所需要的资源添加进文件内

11.2项目配置设置背景 大小 标题 背景 图标 

11.2.1配置大小、图标、标题、退出按钮

    //配置主场景

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

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

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

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

11.2.2配置背景 

    //重写paintEvent事件  画背景图
    void paintEvent(QPaintEvent *);
//重写paintEvent事件 画背景图
void MainScene::paintEvent(QPaintEvent *)
{
    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);
}

11.3创建开始按钮

       11.3.1 封装自定义的按钮 MyPushButton

                 新建一个类为MyPushButton

                主场景创建开始按钮 

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

        11.3.2构造函数(默认显示图片,按下后显示图片)

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

    //成员属性  保存用户传入的默认显示路径 以及按下后显示的图片路径
    QString normalImgPath;
    QString pressImgPath;
MyPushButton::MyPushButton(QString normalImg, QString perssImg)
{
    this->normalImgPath=normalImg;
    this->pressImgPath =pressImgPath;

    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()));

}

        11.3.3开始制作特效zoom1,zoom2

    //弹跳特效
    void zoom1();//向下跳
    void zoom2();//向上跳
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();

}

11.4创建选择关卡场景

 创建一个选择关卡场景类

        11.4.1点击开始按钮后延时进入到选择关卡场景

                主场景添加: 

    ClooseLevelScene * chooseScene = NULL;
    connect(startBtn,&MyPushButton::clicked,[=](){
        qDebug()<<"点击了开始";
        //做一个弹起的特效
        startBtn->zoom1();
        //做一个回弹特效
        startBtn->zoom2();

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

       11.4.2 配置选择关卡场景(设置背景 大小 标题 背景 图标) 

                配置选择关卡场景的相关设置 

  //配置选择关卡场景

    this->setFixedSize(320,588);

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

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

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

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

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

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

配置背景图: 

    //重写paintEvent事件  画背景图
    void paintEvent(QPaintEvent *);
//重写paintEvent事件 画背景图
void ClooseLevelScene::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    QPixmap pix;
    pix.load(":/res/OtherSceneBg.png");
    painter.drawPixmap(0,0,this->width(),this->height(),pix);//背景拉伸满屏

    //画背景上的图标
    pix.load(":/res/Title.png");
    pix = pix.scaled(pix.width(),pix.height());//缩放图标
    painter.drawPixmap(40,30,pix);
}

        11.4.3创建返回按钮

    //返回按钮
    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()<<"点击了返回按钮";
    });

         11.4.4返回关卡的返回按钮特效切换

    //重写按钮 按下  释放 事件
    void mousePressEvent(QMouseEvent *e);
    void mouseReleaseEvent(QMouseEvent *e);
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->normalImgPath!="")//传入摁下图片非空,说明需要有按下状态,切为初始图片
    {
        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);
}

11.4.5 开始场景与选择关卡场景的切换

signals:
    //写一个自定义的信号,告诉主场景,点击了返回
    void chooseSceneBack();
    //点击返回
    connect(backBtn,&MyPushButton::clicked,[=](){
        //qDebug()<<"点击了返回按钮";
        //告诉主场景  我返回了  主场景监听ChooseLevelScene的返回按钮

        //做一个延时的返回
        QTimer::singleShot(200,this,[=](){
            emit this->chooseSceneBack();
        });
    //监听选择关卡的返回按钮的信号
    connect(chooseScene,&ClooseLevelScene::chooseSceneBack,this,[=](){
        chooseScene->hide();
        this->show();//重新显示主场景

11.5选择关卡按钮创建

11.5.1单个for循环创建矩阵 

 //创建选择关卡的按钮
    for(int i=0;i<20;i++)//单个for循环写矩阵
    {
        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;
        });   

 11.5.2按钮上设置显示关卡数


        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);
    }

11.6翻金币场景的基本配置

新建类PlayScene,注意选择QmainWindow

11.6.1配置游戏场景(设置背景 大小 标题 背景 图标) 

与之前相同 

11.6.2实现返回按钮可以返回上一场景 

与之前相同 

11.6.3实现显示关卡的label

    //显示当前关卡数
    QLabel *label = new QLabel;
    label->setParent(this);
    QFont font;
    font.setFamily("仿宋");
    font.setPointSize(20);
    QString str1 = QString("Level:%1").arg(this->levelIndex);
    //将字体设置到标签控件中
    label->setFont(font);
    label->setText(str1);
    label->setGeometry(30,this->height()-50,120,50);

 11.7创建金币类

 11.7.1先将金币的背景图案放入PlayScene中


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

11.7.2创建MyCoin自定义金币按钮类

    //参数代表传入的金币路径 还是银币路径
    MyCoin(QString btnImg);
MyCoin::MyCoin(QString btnImg)
{
    QPixmap pix;
    bool ret =pix.load(btnImg);
    if(!ret)
    {
        QString str = QString("图片 %1 加载失败").arg(btnImg);
        qDebug()<<str;
    }

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

构造函数中那个传入默认显示的图片金币

11.7.3在playscene创建所有的金币按钮

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

            //创建金币
            MyCoin * coin = new MyCoin(":/res/Coin0001.png");
            coin->setParent(this);
            coin->move(59+i*50,204+j*50);
        }
    }

11.8每个关卡的默认显示

引入dataConfig.h和dataConfig.cpp文件到项目中

在PlayScene中写了int gameArray[4][4]的数组  维护每个关卡的金币状态

初始化每个关卡的显示

11.9翻金币特效

 11.9.1给每个硬币加属性  posx  posy  bool flag

    //金币的属性
    int posX;//X坐标位置
    int posY;//Y坐标位置
    bool flag;//正反标识
  //给金币的属性赋值
            coin->posX=i;
            coin->posY=j;
            coin->flag=this->gameARRAY[i][j];//1正面 0反面

11.9.2给MyCoin加函数

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

    //执行动画的标志
    bool isAnimation = false;
    //初始化定时器对象
    timer1 = new QTimer(this);
    timer2 = new QTimer(this);
void MyCoin::changeFlag()
{
    //如果是正面翻转反面
    if(this->flag)
    {
        //开始正面翻反面的定时器
        timer1->start(30);
        isAnimation = true;//开始做动画
        this->flag =false;
    }
    else//相反
    {
        timer2->start(30);
        isAnimation = true;//开始做动画
        this->flag = true;
    }
}

11.9.3监听信号并翻转



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

        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;
        QString str = QString(":/res/Coin000%1.png").arg(this->max--);
        pix.load(str);

        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->max = 8;
            isAnimation = false;
            timer2->stop();
        }
    });

 //点击金币  进行翻转
            connect(coin,&MyCoin::clicked,[=](){
                coin->changeFlag();
                this->gameARRAY[i][j] = this->gameARRAY[i][j]==0?1:0;
            });

11.9.4解决快速点击效果不好的问题



    //重写 按下 和  释放
    void mousePressEvent(QMouseEvent *e);
void MyCoin::mousePressEvent(QMouseEvent *e)
{
    if(this->isAnimation==true)
    {
        return;
    }
    else
    {
        QPushButton::mousePressEvent(e);
    }
}

11.9.5点击硬币周围一起翻转

    MyCoin *coinBtn[4][4];
            
            //将金币放入到 金币的二维数组中 以便以后的维护
            coinBtn[i][j]=coin;
            //点击金币  进行翻转
            connect(coin,&MyCoin::clicked,[=](){
                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>=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;
                    }
                    //下侧硬币翻转条件
                    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;
                    }
                });
            });

11.9.6判断胜利

playsence中 添加iswin标志判断是否胜利 

    //是否胜利的标志
    bool isWin;
  //判断是否胜利
                    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)
                    {
                        //胜利了
                        qDebug()<<"游戏胜利";
                        //将所有按钮的胜利标志改为true,再次点击,直接return
                        for(int i = 0 ; i < 4 ; i++)
                        {
                            for(int j = 0 ; j < 4 ; j++)
                            {
                                coinBtn[i][j]->isWin=true;
                            }
                        }
                    }

将iswin的判断添加进来,如果全部为true,直接return 

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

11.9.7胜利图片设置

    //胜利图片的显示
    QLabel* winLable = new QLabel;
    QPixmap tmpPix;
    tmpPix.load(":/res/LevelCompletedDialogBg.png");
    winLable->setGeometry(0,0,tmpPix.width(),tmpPix.height());
    winLable->setPixmap(tmpPix);
    winLable->setParent(this);
    winLable->move((this->width()-tmpPix.width())*0.5,-tmpPix.height());
 if(this->isWin == true)
                    {
                        //胜利了
                        qDebug()<<"游戏胜利";
                        //将所有按钮的胜利标志改为true,再次点击,直接return
                        for(int i = 0 ; i < 4 ; i++)
                        {
                            for(int j = 0 ; j < 4 ; j++)
                            {
                                coinBtn[i][j]->isWin=true;
                            }
                        }
                        //将胜利的图片砸下来
                        QPropertyAnimation * animation = new QPropertyAnimation(winLable,"geometry");
                        //设置时间间隔
                        animation->setDuration(1000);
                        //设置开始位置
                        animation->setStartValue(QRect(winLable->x(),winLable->y(),winLable->width(),winLable->height()));
                        //设置结束位置
                        animation->setEndValue(QRect(winLable->x(),winLable->y()+114,winLable->width(),winLable->height()));
                        //设置缓和曲线
                        animation->setEasingCurve(QEasingCurve::OutBounce);
                        //执行动画
                        animation->start();
                    }

11.9.8音效设置

 QSound所属模块 multimedia 需要加载.pro文件中

    QSound *startSound = new QSound(":/res/TapButtonSound.wav",this);


    startSound->setLoops(-1);//设置循环,-1为无限循环
    startSound->play();

11.9.9每个场景保持一个位置

 开始进入下一个场景:

            //设置choosescene场景的位置
            chooseScene->setGeometry(this->geometry());

 返回上一个场景,show之前写

        this->setGeometry(chooseScene->geometry());

 11.10项目打包及游戏扩展

 debug改为release并运行

找到.exe,放在文件夹里,打开该位置命令符

找到QT里的bin里的windeployqt

在命令行输入windeployqt 文件名.exe运行

猜你喜欢

转载自blog.csdn.net/weixin_58176527/article/details/127492141