Qt学习笔记

Qt学习笔记

文章目录

  • Qt学习笔记
  • Qt界面
  • 对象树
  • Qt中的坐标系
  • 第一个Qt程序
  • 信号与槽
    • 库函数
    • 自定义的信号与槽
    • 解决重载问题
    • 信号与槽的连接方式
  • Lambda表达式
  • Day1 作业
  • Main_Window菜单栏和工具栏
    • 使用案例
    • 结果显示
    • 资源文件
    • 对话框的创建
    • 消息对话框
  • 界面布局
    • 登陆界面
    • Tree Widget
    • Table Widget
    • 其它控件的使用
  • 自定义框架
  • 事件
    • 鼠标事件
    • 定时器
      • 第一种方法使用
      • 第二种方法
    • 事件分发器
    • 事件过滤器
  • QPainter绘图
    • 高级设置
  • 利用定时器对图片移动进行控制
    • 绘图设备
    • QFile
  • 金币反转项目
  • 项目文件
    • pro文件
    • h文件
    • cpp文件

Qt界面

Qt学习笔记_第1张图片

对象树

我们在创建 QObject 对象时,提供一个父对象,那么我们创建的这个 QObject 对象会自动添加到其父对象的 children() 列表。当父对象析构的时候,这个子对象列表中的所有对象都会被析构,当析构子对象的时候,会自动从父对象的子对象列表中删除。

这种机制在 GUI 程序开发过程中是相当实用的。有一个很明显的现象就是我们会在窗口中new很多控件,但是却没有delete,因为在父控件销毁时这些子控件以及布局管理器对象会一并销毁。

更加方便内存管理
Qt学习笔记_第2张图片

Qt中的坐标系

左上角为坐标原点,X向右增大,Y向下增大
Qt学习笔记_第3张图片

第一个Qt程序

#include "mywidget.h"
#include "ui_mywidget.h"
#include "qpushbutton.h"
#include "mypushbotton.h"
#include "QDebug"
//命名规范
//类名 首字母大写 单词间大写
//函数与变量 首字母小写  单词间大写

//快捷键
//注释 ctrl + /
//运行 ctrl + r
//编译 ctrl + b
//查找 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对象依赖于widget窗口 设置到对象树中
       btn->setParent(this);
       //显示文本
       btn->setText("First Winodw");
       //创建第二个按钮
       QPushButton* btn2 = new QPushButton("Second Window", this);
       resize(600, 400);

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

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

       //固定窗口大小
       setFixedSize(600, 400);
       
       MyPushBotton* mybtn = new MyPushBotton;
       mybtn->setParent(this);  //设置到对象树中
       mybtn->move(200, 0);
       mybtn->setText("自己的按钮(关闭)");
   }

信号与槽

connect(信号的发送者, 发送的具体信号, 信号的接收者, 信号的处理(槽))

库函数

       //需求 点击按钮 把窗口关闭
       //参数1 信号的发送者 参数2 发送的信号 参数3 信号的接收者 参数4 处理的槽函数
       connect(mybtn, &QPushBotton::clicked, this, &QWidget::close);

自定义的信号与槽

信号:返回void;需要声明,不需要实现;可以有参数;卸载signals下;
槽:返回void;需要声明;也需要实现;可以有参数,可以重载;写在public slots下或者public和全局函数下
触发自定义的信号:emit自定义信号

案例:下课后,老师触发了饿了信号,学生响应信号,请客吃饭

#ifndef STUDENT_H
#define STUDENT_H

#include 

class Student : public QObject
{
    Q_OBJECT
public:
    explicit Student(QObject *parent = nullptr);
    //早期Qt必须要写在public slots下,高级版本可以写在public或者全局下
    //返回值为void 需要声明 也需要实现
    //可以有参数也可以重载
    void treat();
    

signals:

};

#endif // STUDENT_H


#ifndef TEACHER_H
#define TEACHER_H

#include 

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

signals:
    //自定义信号 写道signals下
    //返回值是void 只需要声明 不需要事先
    //可以有参数 可以重载
    void hungry();

};

#endif // TEACHER_H


#ifndef WIDGET_H
#define WIDGET_H

#include 
#include "student.h"
#include "teacher.h"

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;
    
    Teacher* tea;
    Student* stu;
    
    void classIsOver();
};
#endif // WIDGET_H


#include "student.h"
#include "QDebug"
Student::Student(QObject *parent) : QObject(parent)
{

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

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

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //创建老师对象
    this->tea = new Teacher(this);
    //创建学生对象
    this->stu = new Student(this);
    
    
    //老师饿了 学生请客吃饭
    connect(tea, &Teacher::hungry, stu, &Student::treat);
    //先做好连接 再触发下课这件事 才会响应
    classIsOver();
}
void Widget::classIsOver(){
    //下课函数 调用后 触发老师饿了的信号
    emit tea->hungry();  
}
Widget::~Widget()
{
    delete ui;
}

#include "widget.h"

#include 

//Teacher 类 老师类
//Student 类 学生类
//
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

解决重载问题

利用函数指针:

    //指针->地址  函数指针->函数地址
    void (Teacher::*teachaerSignal)(QString) = &Teacher::hungry;
    void(Student::*studentSlot)(QString) = &Student::treat;
    connect(tea, teachaerSignal, stu, studentSlot);
    classIsOver();

QString -> char *的转换

    //QString -> char *
    //QString -> QByteAray -> char *
    //  toUtf8()         data()
    qDebug() << "请老师吃饭, 老师要吃:" << foodName.toUtf8().data();

信号与槽的连接方式

信号与槽的连接
信号与信号的连接
disconnect用于解除连接

    //点击按钮 触发下课
    //connect(btn, &QPushButton::clicked, this, &Widget::classIsOver);

    //无参信号和槽的连接
    void (Teacher::*teachaerSignal2)(void) = &Teacher::hungry;
    void(Student::*studentSlot2)(void) = &Student::treat;
    connect(tea, teachaerSignal2, stu, studentSlot2);

    //信号与信号的连接
    connect(btn, &QPushButton::clicked, tea, teachaerSignal2);

    //解除连接
    disconnect(tea, teachaerSignal2, stu, studentSlot2);
**//拓展
//1.信号可以连接信号
//2.一个信号可以连接多个槽函数
//3.多个信号可以连接同一个槽函数
//4.信号和槽函数参数必须一一对应
//5.信号和槽的参数个数问题 信号的参数可以比槽函数多 但是类型仍然是一一对应**

Lambda表达式

C++11中的Lambda表达式用于定义并创建匿名的函数对象,以简化编程工作。首先看一下Lambda表达式的基本构成:
Qt学习笔记_第4张图片函数对象参数mutable或exception ->返回值{函数体}

利用表达式关闭窗口:

    QPushButton* btn2 = new QPushButton;
    btn2->setParent(this);
    btn2->setText("关闭");
    btn2->move(100, 0);
    connect(btn2, &QPushButton::clicked, this, [=](){
        this->close();
    });

同时也能做一些其他的事情,在表达式里进行操作。

Day1 作业

通过窗口按钮实现对另一个窗口的打开与关闭:

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

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
//    QPushButton* btn1 = new QPushButton;
//    btn1->setText("open");
//    btn1->setParent(this);
//    btn1->move(100, 100);

//    QPushButton* btn2 = new QPushButton;
//    btn2->setText("close");
//    btn2->setParent(this);
//    btn2->move(100, 200);

//    resize(600, 400);

//    QWidget* newone = new QWidget();
//    newone->setWindowTitle("作业");


//    connect(btn1, &QPushButton::clicked, this, [=](){
//        newone->show();
//    });

//    connect(btn2, &QPushButton::clicked, this, [=](){
//        newone->close();
//    });

    QWidget* newone = new QWidget();
    newone->setWindowTitle("作业");
    QPushButton* btn1 = new QPushButton;
    btn1->setText("open");
    btn1->setParent(this);
    btn1->move(100, 100);
    connect(btn1, &QPushButton::clicked, this, [=](){
        if(btn1->text() == "open"){
            btn1->setText("close");
            newone->show();
        }
        else{
            btn1->setText("open");
            newone->close();
        }
    });



}

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

Main_Window菜单栏和工具栏

框架:
Qt学习笔记_第5张图片

使用案例

.cpp文件

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

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

    resize(600, 400);
    //菜单栏最多只有一个
    //菜单栏创建
    QMenuBar *bar = new QMenuBar();
    //将菜单栏放到窗口中
    setMenuBar(bar);

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

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

    //工具栏 可以有多个
    QToolBar* toolbar = new QToolBar(this);
    //addToolBar(toolbar);
    //显示在左侧
    addToolBar(Qt::LeftToolBarArea, toolbar);

    //只允许在左右两侧停靠
    toolbar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
    //设置浮动
    toolbar->setFloatable(true);
    //设置移动(总开关)
    toolbar->setMovable(false);

    //工具栏中的内容
    toolbar->addAction(newAction);
    //添加分割线
    toolbar->addSeparator();
    toolbar->addAction(openAction);


    //添加控件
    QPushButton* btn = new QPushButton("aaa", this);
    toolbar->addWidget(btn);

    //状态栏 做多只能有一个
    QStatusBar* stBar = new QStatusBar;
    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()
{
    delete ui;
}


结果显示

Qt学习笔记_第6张图片
菜单栏
最多只有一个

QMenuBar * bar = new QMenuBar();
setMenuBar(bar);
QMenu * fileMenu = bar->addMenu("文件"); 创建菜单
QAction* newAction = fileMenu->addAction("新建");

工具栏
可以有多个

 QToolBar* toolbar = new QToolBar(this);
 addToolBar(默认停靠区域, toolbar);
 设置后期停靠区域 浮动 移动
 添加菜单项 或者 添加 小控件

状态栏
最多有一个

QStatusBar* stBar = new QStatusBar();
setStatusBar(stBar); //设置到窗口中
stBar->addWidget(label)放左侧信息
stBar->addPermanentWidget(label2); //放置右侧信息

铆接部件(浮动窗口)
可以有多个

QDockWidget;
addDockWidget(默认停靠区域, 浮动窗口指针);
设置后期的停靠区域

核心部件
只能有一个

 QTextEdit* edit = new QTextEdit(this);
setCentralWidget(edit);

资源文件

将图片文件拷贝到项目位置下
右键项目 ->添加新文件->Qt->Qt resource file ->给资源文件起名字
res 生成 res.qrc
open in editor 编辑资源
添加前缀 添加文件
使用 ” : + 前缀名 + 文件名“

#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:/QtCode/thumb-1920-982252.JPG"));

    //使用Qt资源 " : + 前缀名 + 文件名"
    ui->actionnew->setIcon(QIcon(":/n/Image/thumb-1920-982252.jpg"));
    ui->actionopen->setIcon(QIcon(":/n/Image/20150527082023557.png.source.jpg"));
}

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

对话框的创建

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

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

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(200, 100);
        dlg2->show();
        dlg2->setAttribute(Qt::WA_DeleteOnClose); //55 号属性  防止内存泄漏
        qDebug() << "非模态对话框弹出" ;
    });
}

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


消息对话框

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

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

        //提问对话框
        //参数1 父亲 参数2 标题 参数3 提示内容 参数4 按键类型 参数5 默认关联回车按键
        if(QMessageBox::Save == QMessageBox::question(this, "ques", "提问", QMessageBox::Save | QMessageBox::Cancel, QMessageBox::Cancel)){
            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 str = QFileDialog::getOpenFileName(this, "打开文件", "C:\\Users\\ZSY\\Desktop","(*.txt)");
        qDebug() << str;

       bool flag;
       QFont font = QFontDialog::getFont(&flag, QFont("华文彩云", 36));
       qDebug() << "字体:" << font.family().toUtf8().data() << "字号:" << font.pointSize() << "是否倾斜" << font.italic();

界面布局

登陆界面

利用ui界面设计
Qt学习笔记_第7张图片

Tree Widget

    //设置水平头
    ui->treeWidget->setHeaderLabels({"英雄", "英雄简介"});

    QTreeWidgetItem * liItem = new QTreeWidgetItem(QStringList() << "力量");
    QTreeWidgetItem * minItem = new QTreeWidgetItem(QStringList() << "敏捷");
    QTreeWidgetItem * zhiItem = new QTreeWidgetItem(QStringList() << "智力");

    //加载顶层节点
    ui->treeWidget->addTopLevelItem(liItem);
    ui->treeWidget->addTopLevelItem(minItem);
    ui->treeWidget->addTopLevelItem(zhiItem);

    //追加子节点

    QTreeWidgetItem * l1 = new QTreeWidgetItem(QStringList() << "刚猪"  << "坦克英雄,吸收伤害并输出");
    liItem->addChild(l1);

Qt学习笔记_第8张图片

Table Widget

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

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

    //设置行数
    ui->tableWidget->setRowCount(5);

    //设置正文
    ui->tableWidget->setItem(0, 0, new QTableWidgetItem("亚瑟"));

    QStringList namelist;
    namelist << "亚瑟" << "赵云" <<"张飞" <<"关羽" <<"花木兰";

    QStringList sexlist;
    sexlist << "男" << "男" <<"女" <<"男" <<"男";

    QStringList agelist;
    agelist << "18" << "20" <<"35" <<"84" <<"22";

    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[i]));
        ui->tableWidget->setItem(i, col++, new QTableWidgetItem(agelist[i]));
    }

Qt学习笔记_第9张图片

其它控件的使用

    ui->setupUi(this);
    //栈控件的使用
    //设置默认值
    ui->stackedWidget->setCurrentIndex(0);

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

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

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

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

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

    //利用Qlable显示图片
    ui->label_image->setPixmap(QPixmap(":/Image/thumb-1920-982252.jpg"));

    //利用Qlabel显示gif动态图片
    QMovie* movie = new QMovie(":/Image/0127c0577e00620000012e7e12da0e.jpg");
    ui->label_movie->setMovie(movie);
    //播放动图
    movie->start();

stackWidget
setCurrentIndex();设置当前显示
下拉框
ui->comboBox->addItem(“奔驰”);
QLabel显示图片
ui->label_image->setPixmap(QPixmap(":/Image/thumb-1920-982252.jpg"));
QLabel显示动图
ui->label_movie->setMovie(movie);
movie->start();

自定义框架

1.创建新文件(Qt设计师界面类(包含了ui h cpp文件))
2.ui设计QSpinBox和QSlider控件
3.Widget中使用自定义控件,拖拽一个Widget,点击提升为
4.实现功能,改变数字,滑动条跟着移动,信号槽监听
5.提供getNum和setNum对外接口
6.测试接口
wigdet.cpp

#include "widget.h"
#include "ui_widget.h"
#include 
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

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

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

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

smallWidget

#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(){
    return ui->spinBox->value();
}

事件

鼠标事件

复写鼠标进入、鼠标按下、鼠标释放、鼠标释放和鼠标离开等
ev->x(), ev->globalX()获得坐标
ev->button()判断按键Qt::leftButton Qt::rightButton
ev->buttons()判断组合按键 判断move的左右键 结合& 运算符
setMouseTracking(true); 鼠标追踪
myLabel.cpp

#include "mylabel.h"
#include "qdebug.h"
#include "QMouseEvent"
myLabel::myLabel(QWidget *parent) : QLabel(parent)
{
    //设置鼠标追踪
    setMouseTracking(true);
}
//鼠标进入事件
void myLabel::enterEvent(QEvent *event){
    qDebug() << "鼠标进入了";
}
//鼠标离开
void myLabel::leaveEvent(QEvent *event){
    qDebug() << "鼠标离开了";
}
//鼠标移动
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;
//    }
}
//鼠标按下
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.toUtf8().data();
    }
}
//鼠标释放
void myLabel::mouseReleaseEvent(QMouseEvent *ev) {
    if(ev->button() == Qt::LeftButton){
        qDebug() << "鼠标释放";
    }
}

定时器

第一种方法使用

利用时间 void timeEvent(QTimerEvent* ev);
启动定时器 startTimer(1000); 单位 ms
startTimer的返回值是定时器的唯一标识,可以和ev->timerId进行比较

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

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

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

}


第二种方法

创建QTimer对象,利用timeout信号,更加方便独立

    //定时器的第二种方式
    QTimer* timer = new QTimer(this);

    //启动计时器
    timer->start(500);
    connect(timer, &QTimer::timeout, [=](){
        static int num = 1;
        //label4 每隔0.5秒 + 1
        ui->label_4->setText(QString::number(num++));
    });
        //点击停止按钮 停止计时
    connect(ui->btn, &QPushButton::clicked, [=](){
        timer->stop();
    });
    //点击停止按钮 开始计时
    connect(ui->btn1, &QPushButton::clicked, [=](){
        timer->start(500);
    });

事件分发器

Qt学习笔记_第10张图片
用于时间的分发,也可以做拦截操作

事件过滤器

Qt学习笔记_第11张图片

在程序将事件分发到事件分发器中,可以利用过滤器拦截
步骤1:给控件安装事件过滤器
步骤2:重写eventFilter函数

QPainter绘图

绘图事件:void paintEvent
声明画家对象QPainter painter(this); this指定绘图设备
画线、画图、画矩形、画文字
设置画笔Qpen 宽度 颜色 风格等
设置画刷QBrush 设置风格
Widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include "qpainter.h" //画家类
#include "qbrush.h"
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}
void Widget::paintEvent(QPaintEvent *event){
    //实例化画家对象  this指定绘图的设备
    QPainter painter(this);
    //设置笔画 颜色
    QPen pen(QColor(255, 0, 0));
    //设置宽度
    pen.setWidth(1);
    //设置风格
    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(20, 20, 50, 50));

    //画文字
    painter.drawText(QRect(10, 200, 200, 50), "天天学习,天天向上");
}
Widget::~Widget()
{
    delete ui;
}


高级设置

抗锯齿能力 效率会变低
对画家移动 translate
保存状态 save
还原状态 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));

利用画家绘画图片

    QPainter painter(this);
    if(posX > this->width()){
        posX = 0;
    }
    painter.drawPixmap(posX, 0, QPixmap(":/Image/2013425141231944.jpg"));

利用定时器对图片移动进行控制

    QTimer* time = new QTimer(this);

    time->start(500);

    connect(time, &QTimer::timeout, [=](){
       posX += 5;
       update();
    });

绘图设备

QPixmap QImage QBitmap(黑白色) QPicture QWidget
QPixmap对不同平台显示做了优化
1.QPixmap pix(300, 300) //图纸大小
2.pix.fill(Qt::white); //背景为白色
3.利用画家上面画画
4.保存 pix.save
QImage可以对像素点进行操作
使用流程和QPixmap差不多,Qimage img(300, 300, QImage::Format_RGB32);
其他流程基本一样
可以对像素点进行修改 img->setPixel(x,y,value);
QPicture可以重现绘图指令
Qpicture pic
panter.begin(&pic);
保存pic.save(“位置 + 任意后缀名字”)
重现利用画家 .drawPicture(0,0,pic);

#include "widget.h"
#include "ui_widget.h"
#include "qpixmap.h"
#include "qpainter.h"
#include "qimage.h"
#include "qpicture.h"
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), 50, 50);

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

    //QImage绘图设备
    QImage img(300, 300, QImage::Format_RGB32);
    img.fill(Qt::white);
    QPainter painter0(&img);
    painter0.setPen(QPen(Qt::green));

    painter0.drawEllipse(QPoint(150, 150), 50, 50);
    //保存
    img.save("E:\\img.png");

    //QPicture 绘图设备 可以记录和重新绘图指令
    QPicture pic;
    QPainter painter1;
    painter1.begin(&pic);   //开始在pic上画画
    painter1.setPen(QPen(Qt::cyan));
    painter1.drawEllipse(QPoint(150, 150), 50, 50);
    painter1.end(); //结束画画
    //保存到磁盘
    pic.save("E:\\pic.zt");



}
//绘图事件
void Widget::paintEvent(QPaintEvent* ev){
    QPainter painter(this);

    //利用QImage对像素进行修改
    QImage img;
    img.load(":/Image/thumb-1920-982252.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);

    //重现QPicture的绘图指令
    QPicture pic;
    pic.load("E:\\pic.zt");
    painter.drawPicture(0,0,pic);
}
Widget::~Widget()
{
    delete ui;
}

QFile

利用QFile进行读写操作
QFile file(path 文件路径);
file.open(Qt::QIODevice::readOnly);
全部读取 file.readAll; 也可以按行读取file.readline
默认支持utf-8的格式,必要的时候可以进行格式转换
操作完毕后要记得关闭文件

#include "widget.h"
#include "ui_widget.h"
#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, "打开文件", "C:\\Users\\ZSY\\Desktop");
       //将路径放在lineedit中
       ui->lineEdit->setText(path);

       //编码格式类
     //  QTextCodec* codec = QTextCodec::codecForName("gbk");
       //将内容显示到textedit中
       //QFile默认支持格式utf-8
       QFile file(path);
       //设置打开方式
       file.open(QIODevice::ReadOnly);
       QByteArray array;
//       QByteArray array = file.readAll();
       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;
}

QFileInfo读取信息
调用API接口
后缀名:suffix()
文件名字:fileName
文件路径:filePath
等等

 //QFileInfo 文件信息类
 QFileInfo info(path);

 qDebug() << "大小:" << info.size() << "后缀名:" << info.suffix()
          <<"文件名称:"<<info.fileName() << "文件路径" << info.filePath();

 qDebug() << "创建日期" << info.created().toString("yyyy/MM/dd hh:mm:ss");

 qDebug() << "最后修改日期:" << info.lastModified().toString("yyyy/MM/dd hh:mm:ss");
       

金币反转项目

1.项目简介
2.创建项目,添加项目资源
3.项目基本配置
  设置北京图标
  设置固定大小
  设置项目标题
  设置背景
  设置北京标题
  设置菜单栏
4.创建开始按钮
  封装自定义按钮MyPushButton
  构造函数(默认显示图片,按下后的显示图片)
  测试开始按钮
  开始制作特效
  zoom1向下跳
  zoom2向上跳
5.创建选择关卡场景
  点击开始按钮 延时进入另一个场景
  配置选择关卡场景(图标、标题、大小)
  设置背景图片,设置标题图片
  创建返回按钮
6.选择关卡的返回按钮特效制作
  点击后切换另一个图片
  重写 void mousePressEvent
  重写void mouseReleaseEvent
7.开始场景与选择关卡场景的切换
  点击选择关卡场景的返回按钮,发送一个自定义信号
  在主场景中监听这个信号,并且当触发信号以后,重新显示主场景,隐藏选择关卡场景
7.开始场景与选择关卡场景的切换
  点击选择关卡场景的返回按钮,发送一个自定义信号
  在主场景中监听这个信号,并且当触发信号以后,重新显示主场景,隐藏选择关卡场景
8.选择关卡中的按钮对象
  利用一个for循环将所有按钮布局到场景中
  在按钮上面设置QLabel显示关卡
    QLabel设置大小、显示数字、对齐方式、鼠标穿透
  给每个按钮监听点击事件
9.翻金币的场景切换
  点击选择管卡按钮后,进入到翻紧闭的场景
  配置翻金币游戏场景,设置标题、图标、大小,设置背景
  设置返回按钮,可以返回到上一个场景中
  实现三个场景之间的切换
10.实现显示关卡标签
  在左下角显示玩家具体的关卡标签
  QLabel创建设置大小和位置
  给QFont设置字体以及字号
  给QLabel设置字体setFont
11.创建金币类
  先将金币的背景图片放在PlayScene中
  创建MyCoin自定义金币按钮类
  MyCoin::MyCoin(QString btnImg)的构造函数中传入默认显示的图片金币
  在PlayScene中创建金币按钮
12.关卡默认显示
  引入dataConfig.h和cpp文件
  在PlayScene中创建二维数据维护关卡的状态
  初始化每个位置的显示状态
13.金币翻转特效
  给每个硬币加属性 posX 坐标X posY 坐标Y bool flag 正反标志
  给MyCoin加函数,changeFlag改变标志
    如果flag为true,开启定时器1
    如果flag为false,开启定时器2
    实现定时器中的内容
14.解决快速点击效果不好
  在MyCoin中加入了isAnimation 判断是否正在进行动画
  当按下MyCoin判断是否正在做动画,如果为真,直接返回,保证动态切换的效果
15.翻转周围金币
  点击金币以后,延时翻转周围金币
16.判断胜利
  PlayScene中添加了isWin标志来判断是否胜利
  如果胜利了,打印胜利信息
  将所有按钮屏蔽,不让进行点击
17.胜利图片特效
  将胜利图片放入到游戏场景外
  当游戏胜利的时候利用动画移动到屏幕中央
18.添加音效资源
  QSound所属模块multimedia,需要在pro文件中加入模块
  爱三个场景中加入QSound* s = QSound("资源“);
  播放
  s->setLoop(-1);表示无限循环
18.添加音效资源
  QSound所属模块multimedia,需要在pro文件中加入模块
  爱三个场景中加入QSound* s = QSound("资源“);
  播放
  s->setLoop(-1);表示无限循环
19.项目优化
  将三个场景的切换位置保持一致
20.项目打包发布以及扩展

项目文件

pro文件

.pro文件

QT       += core gui multimedia

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    chooselevelsense.cpp \
    dataconfig.cpp \
    main.cpp \
    mainwindow.cpp \
    mycoin.cpp \
    mypushbotton.cpp \
    playscene.cpp

HEADERS += \
    chooselevelsense.h \
    dataconfig.h \
    mainwindow.h \
    mycoin.h \
    mypushbotton.h \
    playscene.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

RESOURCES += \
    res.qrc

h文件

chooseLevelsense.h

#ifndef CHOOSELEVELSENSE_H
#define CHOOSELEVELSENSE_H

#include 
#include "playscene.h"

class chooseLevelSense : public QMainWindow
{
    Q_OBJECT
public:
    explicit chooseLevelSense(QWidget *parent = nullptr);
    //重写绘图事件
    void paintEvent(QPaintEvent*);

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

signals:
    //写一个自定义信号 告诉场景
    void chooseSenseBack();
};

#endif // CHOOSELEVELSENSE_H

dataconfig.h

#ifndef DATACONFIG_H
#define DATACONFIG_H

#include 
#include 
#include 

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

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include 
#include "chooselevelsense.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

    //重写paintEvent事件 画背景图
    void paintEvent(QPaintEvent *);
    chooseLevelSense* chooseSense = NULL;
private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mycoin.h

#ifndef MYCOIN_H
#define MYCOIN_H

#include 
#include "qtimer.h"
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;

    bool isWin = false;

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

};

#endif // MYCOIN_H

mypushbutton.h

#ifndef MYPUSHBOTTON_H
#define MYPUSHBOTTON_H

#include 
#include 

class MyPushBotton : public QPushButton
{
    Q_OBJECT
public:
    explicit MyPushBotton(QWidget *parent = nullptr);
    //构造函数 参数1 正常显示的图片路径 参数2 按下后显示的图片路径
    MyPushBotton(QString normalImg, QString pressImg = "");

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


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


    //重写按钮的按下 与 释放
     void mousePressEvent(QMouseEvent *e);
     void mouseReleaseEvent(QMouseEvent* e);
signals:

};

#endif // MYPUSHBOTTON_H

playscene.h

#ifndef PLAYSCENE_H
#define PLAYSCENE_H

#include 
#include "mycoin.h"
class PlayScene : public QMainWindow
{
    Q_OBJECT
public:
    //explicit PlayScene(QWidget *parent = nullptr);
   PlayScene(int levelNum);

   int levelIndex; //记录所选的关卡

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

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

   MyCoin* coinBtn[4][4];
   bool isWin;

signals:
   void chooseSceneBack();
};

#endif // PLAYSCENE_H

cpp文件

chooseLevelsense.cpp

#include "chooselevelsense.h"
#include "qmenubar.h"
#include "qmenu.h"
#include "qtimer.h"
#include "qpainter.h"
#include "mypushbotton.h"
#include "qlabel.h"
#include "qstring.h"
#include "qsound.h"
chooseLevelSense::chooseLevelSense(QWidget *parent) : QMainWindow(parent)
{
     //配置选择关卡的场景
    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();
    });

    //选择关卡音效
    QSound* chooseSound = new QSound(":/res/TapButtonSound.wav", this);
    //返回按钮音效
    QSound* backSound = new QSound(":/res/BackButtonSound.wav");

    //返回按钮
    MyPushBotton * backBtn = new MyPushBotton(":/res/BackButton.png", ":/res/BackButtonSelected.png");
    backBtn->setParent(this);
    backBtn->move(this->width() - backBtn->width(), this->height() - backBtn->height());
    //点击返回
    connect(backBtn,&MyPushBotton::clicked, [=](){
        qDebug() << "点击返回";
        //播放返回按钮音效
        backSound->play();
        //告诉主场景 返回了 监听ChooseLevelSense的返回按钮
        QTimer::singleShot(200, this, [=](){
            emit chooseSenseBack();
        });

    });

    //创建关卡按钮
    for(int i = 0; i < 20; ++i){
        MyPushBotton* menubtn = new MyPushBotton(":/res/LevelIcon.png");
        menubtn->setParent(this);
        menubtn->move(25 + i % 4 * 70, 130 + i / 4 * 70);
        //监听每个按钮的点击事件
        connect(menubtn, &QPushButton::clicked,[=](){
            QString str = QString("您选的是第 %1 关").arg(i + 1);
            qDebug() << str;
            //播放音效
            chooseSound->play();
            //选择动画
            menubtn->zoom1();
            menubtn->zoom2();
            QTimer::singleShot(500, this, [=](){
                this->hide();
                //进入到游戏场景
                play = new PlayScene(i + 1);

                //设置游戏场景的初始位置
                play->setGeometry(this->geometry());
                play->show();



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

        });
        QLabel* label = new QLabel(menubtn);
        label->setFixedSize(menubtn->width(), menubtn->height());
        label->setText(QString::number(i + 1));
       // label->move(25 + i % 4 * 70, 130 + i / 4 * 70);
        //设置对齐方式 水平剧中和垂直集中
        label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);

        //设置让鼠标穿透
        //label->setAttribute(Qt::WA_TransparentForMouseEvents); //51号属性
    }
}

void chooseLevelSense::paintEvent(QPaintEvent* ev){
    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() * 0.5, pix.height() * 0.5);
    painter.drawPixmap(10,30,pix);
}


dataconfig.cpp

#include "dataconfig.h"
#include 
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 > >::iterator it = mData.begin();it != mData.end();it++ )
//    {
//         for(QVector< QVector >::iterator it2 = (*it).begin(); it2!= (*it).end();it2++)
//         {
//            for(QVector::iterator it3 = (*it2).begin(); it3 != (*it2).end(); it3++ )
//            {
//                qDebug() << *it3 ;
//            }
//         }
//         qDebug() << endl;
//    }


}

main.cpp

#include "mainwindow.h"
#include "qdebug.h"
#include 
#include "dataconfig.h"

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

//    //测试关卡数据
//    dataConfig config;
//    for(int i = 0; i < 4; ++i){
//        for(int j = 0; j < 4; ++j){
//            qDebug() << config.mData[1][i][j];
//        }
//        qDebug() << " ";

//    }
    return a.exec();
}

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mypushbotton.h"
#include "qtimer.h"
#include "qsound.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //配置主场景

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

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

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

   //退出按钮实现
    connect(ui->actionexit, &QAction::triggered, [=](){
        this->close();
    });
    \
    //准备开始按钮的音效
    QSound* startSound = new QSound(":/res/TapButtonSound.wav", this);
//    startSound->setLoops(-1); //无限循环
//    startSound->play();
    //实例化选择关卡场景
    chooseSense = new chooseLevelSense();
    //开始按钮
    MyPushBotton* startBtn = new MyPushBotton(":/res/MenuSceneStartButton.png");
    startBtn->setParent(this);
    startBtn->move(this->width() * 0.5 - startBtn->width() * 0.5, this->height() * 0.7);

    //监听选择关卡的信号
    connect(chooseSense, &chooseLevelSense::chooseSenseBack,[=](){
         //隐藏选择关卡
        chooseSense->hide();
          //显示主场景

        this->setGeometry(chooseSense->geometry());
        this->show();

    });
    connect(startBtn, &QPushButton::clicked, [=](){
        //播放开始音效资源
        startSound->play();
        //弹跳特效
        startBtn->zoom1();
        startBtn->zoom2();

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

    });


}
void MainWindow::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);

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


mycoin.cpp

#include "mycoin.h"
#include "qdebug.h"
//MyCoin::MyCoin(QWidget *parent) : QWidget(parent)
//{

//}
MyCoin::MyCoin(QString btnImg){
    QPixmap pix;
    bool ret = pix.load(btnImg);
    if(!ret){
        QString str = QString("图片 %1 加载失败").arg(btnImg);
        qDebug() << str;
        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;
        QString str = QString(":/res/Coin000%1.png").arg(this->min++);
        bool ret = pix.load(str);
        if(!ret){
            qDebug() << "图片加载失败";
        }
        this->setFixedSize(pix.width(), pix.height());
        this->setStyleSheet("QPushButton{border:0px;}");
        this->setIcon(pix);
        this->setIconSize(QSize(pix.width(), pix.height()));
        //判断 如果翻完了 重置min
        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--);
        bool ret = pix.load(str);
        if(!ret){
            qDebug() << "图片加载失败";
        }
        this->setFixedSize(pix.width(), pix.height());
        this->setStyleSheet("QPushButton{border:0px;}");
        this->setIcon(pix);
        this->setIconSize(QSize(pix.width(), pix.height()));
        //判断 如果翻完了 重置min
        if(this->max < this->min){
            this->max = 8;
            isAnimation = false;
            timer2->stop();
        }
    });
}
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;
    }
    else{
        QPushButton::mousePressEvent(e);
    }
}

mypushbutton.cpp

#include "mypushbotton.h"
#include "qpropertyanimation.h"
MyPushBotton::MyPushBotton(QWidget *parent) : QPushButton(parent)
{

}
MyPushBotton::MyPushBotton(QString normalImg, QString pressImg){
    this->normalImg = normalImg;
    this->pressImg = 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 MyPushBotton::zoom1(){
    QPropertyAnimation * annimation = new QPropertyAnimation(this, "geometry");

    //设置时间间隔
    annimation->setDuration(200);

    //起始位置
    annimation->setStartValue(QRect(this->x(),this->y(), this->width(), this->height()));

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

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

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

}
void MyPushBotton::zoom2(){
    QPropertyAnimation * annimation = new QPropertyAnimation(this, "geometry");

    //设置时间间隔
    annimation->setDuration(200);

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

    //结束位置
    annimation->setEndValue(QRect(this->x(),this->y(), this->width(), this->height()));

    //设置弹跳曲线
    annimation->setEasingCurve(QEasingCurve::OutBounce);
    //执行动画
    annimation->start();

}
void MyPushBotton::mousePressEvent(QMouseEvent *e){
    if(this->pressImg != ""){ //传入图片不为空 说明需要有按下状态,切换图片
        QPixmap pix;
        bool ret = pix.load(this->pressImg);
        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 MyPushBotton::mouseReleaseEvent(QMouseEvent* e){
    if(this->pressImg != ""){ //传入图片不为空 说明需要有按下状态,切换图片
        QPixmap pix;
        bool ret = pix.load(this->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()));
    }
    //让父类执行其他操作
    return QPushButton::mouseReleaseEvent(e);
}

playscene.cpp

#include "playscene.h"
#include "QDebug"
#include "qmenu.h"
#include "qmenubar.h"
#include "qpainter.h"
#include "mypushbotton.h"
#include "qtimer.h"
#include "chooselevelsense.h"
#include "qlabel.h"
#include "mycoin.h"
#include "dataconfig.h"
#include "qpropertyanimation.h"
#include "qsound.h"

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

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

    //初始化游戏场景
    //设置固定大小
    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();
    });
    //添加返回音效
    QSound* backSound = new QSound(":/res/BackButtonSound.wav", this);
    //添加翻金币音效
    QSound* flipSound = new QSound(":/res/ConFlipSound.wav",this);
    //胜利按钮音效
    QSound* winSound = new QSound(":/res/LevelWinSound.wav",this);
    //返回按钮
    MyPushBotton * backBtn = new MyPushBotton(":/res/BackButton.png", ":/res/BackButtonSelected.png");
    backBtn->setParent(this);
    backBtn->move(this->width() - backBtn->width(), this->height() - backBtn->height());
    //点击返回
    connect(backBtn,&MyPushBotton::clicked, [=](){
        qDebug() << "翻金币场景中 点击返回";
        //告诉主场景 返回了 监听ChooseWSceneBack的返回按钮
        backSound->play();
        QTimer::singleShot(200, this, [=](){
            emit this->chooseSceneBack();
        });
    });

    //显示当前关卡数
    QLabel *label = new QLabel(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);

    //初始化每个关卡的二维数组

    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;
    QPixmap temppix;
    temppix.load(":/res/LevelCompletedDialogBg.png");
    winLabel->setGeometry(0,0,temppix.width(),temppix.height());
    winLabel->setPixmap(temppix);
    winLabel->setParent(this);
    winLabel->move((this->width() - temppix.width()) * 0.5, -temppix.height());
    //显示金币背景图案
    for(int i = 0; i < 4; ++i){
        for(int j = 0; j < 4; ++j){
            //绘制背景图片
            QLabel* label = new QLabel(this);
            label->setGeometry(0,0,50,50);
            label->setPixmap(QPixmap(":/res/BoardNode(1).png"));
            label->move(57 + i * 50, 200 + j * 50);

            //创建金币
            QString str;
            if(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 = 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){
                                isWin = false;
                                break;
                            }
                        }
                        if(this->isWin == false)
                            break;
                    }
                    if(this->isWin == true){
                        //胜利了
                        //播放音效
                        winSound->play();
                        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(winLabel, "geometry");
                        //设置时间间隔
                        animation->setDuration(1000);
                        //设置开始位置
                        animation->setStartValue(QRect(winLabel->x(), winLabel->y(), winLabel->width(),winLabel->height()));
                        //设置结束位置
                        animation->setEndValue(QRect(winLabel->x(), winLabel->y() + 130, winLabel->width(),winLabel->height()));
                        //设置缓和曲线
                        animation->setEasingCurve(QEasingCurve::OutBounce);
                        animation->start();

                    }
                });
            });
            }
    }

}
void PlayScene::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);

}

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