Qt控件知识

  1. QMainWindow菜单栏
    用代码创建窗口,记得把小部件放到某个窗口上
//1.菜单栏  只能有一个
    //创建
    QMenuBar * bar = menuBar();

    //设置到窗口中
    setMenuBar(bar);
    resize(600,400);

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

    //创建菜单项
    QAction * newAction = fileMenu->addAction("新建");

    //添加分割线
    fileMenu->addSeparator();

    QAction * openAction = fileMenu->addAction("打开");

    //2.工具栏  可以放多个
    QToolBar * toolBar = new QToolBar(this);

    //添加到窗口中addToolBar(toolBar);  默认停靠范围:Qt::LeftToolBarArea
    addToolBar(Qt::LeftToolBarArea,toolBar);

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

    //设置浮动
    toolBar->setFloatable(false);

    //设置移动
    toolBar->setMovable(false);

    //在工具栏中放入小部件
    toolBar->addAction(newAction);

    //添加分割线
    toolBar->addSeparator();

    toolBar->addAction(openAction);

    //状态栏  只能放一个
    QStatusBar * stBar = statusBar();
    setStatusBar(stBar);

    QLabel * label1 = new QLabel("左侧提示信息",this);
    stBar->addWidget(label1);

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

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

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

在这里插入图片描述

2.资源文件添加
右键项目->添加新文件->Qt->Qt Resource File->起名字res 生成res.qrc文件->用编辑的方式打开->添加前置-添加文件->使用“:+前缀名+文件名”
在这里插入图片描述
3.创建对话框
对话框分为模态对话框和非模态对话框,模态对话框打开之后不可以对其他窗口进行操作,非模态对话框打开之后可以对其他窗口进行操作。

 //点击新建 创建对话框
    connect(ui->actionNew,&QAction::triggered,this,[=](){
       //对话框分类  模态对话框 非模态对话框
       //模态对话框  不可以对其他窗口进行操作
       //非模态对话框 可以对其他窗口进行操作

       //模态对话框创建
        QDialog dlg(this);
        dlg.resize(200,150);
        dlg.exec();

        //非模态对话框
        QDialog * dlg2 = new QDialog(this);
        dlg2->resize(200,150);
        dlg2->show();

		//设置55号属性
        //非模态对话框创建在堆里,关闭子窗口并不会将其删除,若多次操作会导致内存爆炸
        setAttribute(Qt::WA_DeleteOnClose);  //再关闭子窗口时,释放内存
        dlg2->setAttribute(Qt::WA_DeleteOnClose);

4.错误提示对话框

QMessageBox::critical(this,"错误","critical");

在这里插入图片描述
5.信息提示对话框

QMessageBox::information(this,"信息","info");

在这里插入图片描述
6.询问提示对话框
参数1 父窗口 参数2 标题 参数3 提示信息 参数4 按键类型 参数5 默认关联回车按钮

QMessageBox::question(this,"提示","question",QMessageBox::Save,QMessageBox::Cancel)

该函数返回用户点击的按钮,通过判断可以指定点击之后发生的事件

//询问提示对话框
//参数1  父窗口  参数2  标题  参数3  提示信息  参数4  按键类型  参数5  默认关联回车按键
        if(QMessageBox::Save == QMessageBox::question(this,"提示","question",QMessageBox::Save,QMessageBox::Cancel)){
            qDebug()<<"点击的是保存";
        }else{
            qDebug()<<"点击的是取消";
        }

在这里插入图片描述
7.警告提示对话框

//警告提示对话框
QMessageBox::warning(this,"警告","warning");

在这里插入图片描述
8.颜色对话框
生成一个颜色对话框,返回该颜色的r、g、b三个值

 //颜色对话框  Qt::red是默认选择的颜色
 QColor color = QColorDialog::getColor(Qt::red);
      qDebug()<<color.red()<<color.green()<<color.blue();

在这里插入图片描述
9.选择文件和目录
参数1 父窗口 参数2 标题 参数3 默认的路径或自己指定的路径 参数4 指定打开某一类型的文档

 //选择文件和目录   默认打开本文件下的路径  或 第三个参数可以指定打开路径  第四个参数可以指定打开某一类型的文档
 QString fileName = QFileDialog::getOpenFileName(this,"打开文件","路径",".jpg");

在这里插入图片描述
10.字体对话框
返回QFont类型值,font.family()是返回字体名字,font.pointSize()是返回字号大小,font.bold()是否加粗,font.italic()是否倾斜

//字体对话框
bool flag;  //若用户点击ok按钮,则设为true,函数返回用户所选择的字体,否则返回默认字体
QFont font = QFontDialog::getFont(&flag,QFont("华文彩云",36));
qDebug()<<"字体为:"<<font.family().toUtf8().data()<<"字号:"<<font.pointSize()<<"是否加粗:"<<font.bold()<<"是否倾斜:"<<font.italic();
//字体为: 华文彩云 字号: 36 是否加粗: false 是否倾斜: false

在这里插入图片描述
11.ui控件

Push Button  按钮
Tool Button  按钮,可添加图片
Radio Button 单选按钮,使用GroupBox将多个单选按钮进行组合
//默认选择某一个单选按钮
ui->radioButton->setChecked(true); //默认选择第一个
connect(ui->radioButton_2,&QRadioButton::clicked,[=](){
        qDebug()<<"选择女生"; //选择女生之后发生的事件
    });

--------------------------------------------------
CheckBox复选按钮,也用GroupBox进行组合
//复选按钮 点击 环境好 之后 的监听事件
connect(ui->checkBox,&QCheckBox::clicked,[=](){
        qDebug()<<"选择环境好";
    });
--------------------------------------------------
//listWidget文本框
QListWidgetItem * item = new QListWidgetItem("锄禾日当午");
//将项加载到控件中
ui->listWidget->addItem(item);
//设置对齐方式,垂直居中
item->setTextAlignment(Qt::AlignCenter);

//整首诗一次性加入到该模块中,但不能垂直居中了
QStringList list;
list<<"锄禾日当午"<<"汗滴禾下土"<<"谁知盘中餐"<<"粒粒皆辛苦";
ui->listWidget->addItems(list);
--------------------------------------------------
//给新建添加小图标
//actionNew是按钮的名字,ui界面中起的
ui->actionNew->setIcon(QIcon(":/image/kobe.jpg"));
---------------------------------------------------
GroupBox 将多个组件组合在一起
Scroll Area有侧边滚轮
Tool Box类似于QQ分组
Tab Widget
Stacked Widget 左右箭头切换界面的效果
-----------------------------------------------------
combo Box下拉框
ui->comboBox->addItem("奔驰");
ui->comboBox->addItem("宝马");
ui->comboBox->addItem("拖拉机");
//将下拉框和按钮连接起来,点击按钮来选择下拉框中的某一项
connect(ui->pb_select,&QPushButton::clicked,[=](){
//拖拉机的索引是2,根据索引号或者值(“拖拉机”)来选择
       ui->comboBox->setCurrentIndex(2);
    });
---------------------------------------------------
Spin Box 类似于购物时添加数量的一个按钮
TextLabel设置一个label,添加图片进去
ui->label_img->setPixmap(QPixmap(":/image/kobe.jpg"));

利用QLabel显示动态图片 格式要求
QMovie * movie = new QMovie("路径");
ui->label_img->setMovie(movie);
movie->start();

--------------------------------------------------
TreeWidget树控件使用
//treeWidget树控件使用
    //设置头
    ui->treeWidget->setHeaderLabels(QStringList()<<"英雄"<<"英雄简介");

    //创建力量根
    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);
	//给每个子空间都加上相应的显示
    QStringList heroL1;
    heroL1<<"船长"<<"前排坦克,能肉能输出";

    QTreeWidgetItem * l1 = new QTreeWidgetItem(heroL1);
    //添加到控件中
    liItem->addChild(l1);
---------------------------------------------
TabelWidget表格控件使用
//tableWidge表格控件使用
    //设置列数
    ui->tableWidget->setColumnCount(3);

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

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

    QList<QString> nameList;
    nameList<<"亚瑟"<<"妲己"<<"安其拉"<<"赵云"<<"孙悟空";
    QStringList sexList;
    sexList<<"男"<<"女"<<"女"<<"男"<<"男";

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

整体效果图:
在这里插入图片描述
12.自定义控件封装
右键项目->添加新文件->Qt-Qt设计师界面类->在ui文件中设计自定义控件->在主窗口中做提升操作(在自定义控件中做出自己想要的控件,然后在主窗口中添加与自定义控件相同的类型,例如widget,右键提升,选择相应的基类名称和提升类的名称即可!)相当于把一个 小的控件加到大窗口中。
案例:滚动条和数值同步移动
在这里插入图片描述

SmallWidgt.h
#ifndef SMALLWIDGET_H
#define SMALLWIDGET_H
#include <QWidget>
namespace Ui {
class SmallWidget;
}
class SmallWidget : public QWidget
{
    Q_OBJECT
public:
    explicit SmallWidget(QWidget *parent = 0);
    ~SmallWidget();

    //设置值
    void setData(int val);

    //获取值
    int getData();

private:
    Ui::SmallWidget *ui;
};
#endif // SMALLWIDGET_H

SmallWidgt.cpp
//修改SpinBox  右侧滚动条 跟着移动
    void(QSpinBox:: *spinBoxP)(int) = &QSpinBox::valueChanged;

    connect(ui->spinBox,spinBoxP,[=](int val){
        ui->horizontalSlider->setValue(val);
    });

    //右侧滚动条移动,左侧跟着改变数字
    connect(ui->horizontalSlider,&QSlider::valueChanged,[=](int val){
        ui->spinBox->setValue(val);
    });

	//设置值
	void SmallWidget::setData(int val){
    	ui->horizontalSlider->setValue(val);
	}

	//获取值
	int SmallWidget::getData(){
    //qDebug()<<ui->horizontalSlider->value();
    	return ui->horizontalSlider->value();
	}
widget.cpp
主窗口中设置两个按钮的功能,将其与控件连接到一起
//设置按钮,将小控件设置到一半位置
    connect(ui->ptn_set,&QPushButton::clicked,[=](){
        ui->widget->setData(50);
    });

    //点击获取值
    connect(ui->ptn_get,&QPushButton::clicked,[=](){
        //ui->widget->getData();
        qDebug()<<ui->widget->getData();
    });

13.鼠标事件

//均是虚函数,需要在cpp文件中重写
//鼠标进入事件
    void enterEvent(QEvent *);

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

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

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

    //鼠标释放事件
    void mouseReleaseEvent(QMouseEvent *ev);
MyLabel::MyLabel(QWidget *parent) :
    QLabel(parent)
{
    //设置鼠标追踪   若没有这句代码,鼠标只有在点击时候移动才会触发事件,有了这句当鼠标进入该区域就会触发事件
    setMouseTracking(true);
}

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

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

//鼠标移动事件
void MyLabel::mouseMoveEvent(QMouseEvent *ev){
    qDebug()<<"鼠标移动";
}

//鼠标按下事件
void MyLabel::mousePressEvent(QMouseEvent *ev){
    //鼠标左键按下  buttons防止中途更换按键产生的误操作;&符号是位与操作符,返回的值为二进制做&运算
    //鼠标左键按下时触发事件
    if(ev->buttons() & Qt::LeftButton){
        //arg是参数的意思,1,2 表示参数位置,按顺序添加
        QString str = QString("鼠标按下了  x= %1  y= %2 ").arg(ev->x()).arg(ev->y());
        qDebug()<<str;
    }
}

//鼠标释放事件
void MyLabel::mouseReleaseEvent(QMouseEvent *ev){
    qDebug()<<"鼠标释放";
}

14.定时器
添加两个定时器,分别使不同label中的数字做加法

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

    //添加定时器
    void timerEvent(QTimerEvent *);

    //第一个定时器标识
    int id1;

    //第二个定时器标识
    int id2;
private:
    Ui::Widget *ui;
};

Widget::Widget(QWidget *parent) :    QWidget(parent),    ui(new Ui::Widget)
{
    ui->setupUi(this);
    //开启计时器
    id1 = startTimer(1000); //单位 毫秒

    id2 = startTimer(2000); //单位 毫秒
	
	//定时器2
	//创建定时器对象
    QTimer * timer1 = new QTimer(this);
    timer1->start(500);

    //每隔0.5秒 会抛出一个信号timeout出来
    connect(timer1,&QTimer::timeout,[=](){
        //每隔0.5秒,让label_4数字++
        static int num =1;
        ui->label_4->setText(QString::number(num++));
    });

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

//添加定时器
void Widget::timerEvent(QTimerEvent *e){
	//不太懂!?
    if(e->timerId() == id1){
        //每隔1秒 让label_2数字++
        static int num = 1;
        ui->label_2->setText(QString::number(num++));
    }
    if(e->timerId() == id2){
        //每个2s 让label_3数字++
        static int num2=1;
        ui->label_3->setText(QString::number(num2++));
    }
}

15.事件

   //事件分发器,返回bool类型值,true为自己处理该事件
    bool event(QEvent *e);
//事件分发器  用来分发事件
bool MyLabel::event(QEvent *e){
    if(e->type() == QEvent::MouseButtonPress){
        //如果是鼠标按下  拦截事件,不向下分发
        QMouseEvent *ev = static_cast<QMouseEvent *>(e);
        QString str = QString("event中  鼠标按下了  x= %1  y= %2 ").arg(ev->x()).arg(ev->y());
        qDebug()<<str;
        return true;
    }
    //其他事件  抛给父类处理
    return QLabel::event(e);
}

在这里插入图片描述
16.过滤器

//给label添加事件过滤器,做更高级的拦截操作
//1.给控件安装过滤器
ui->label->installEventFilter(this);
//重写过滤器事件  obj是控件对象,e是发生的事件
bool Widget::eventFilter(QObject *obj, QEvent *e){
    if(obj == ui->label){
        if(e->type() == QEvent::MouseButtonPress){
            //如果是鼠标按下  拦截事件,不向下分发
            QMouseEvent *ev = static_cast<QMouseEvent *>(e);
            QString str = QString("事件过滤器  鼠标按下了  x= %1  y= %2 ").arg(ev->x()).arg(ev->y());
            qDebug()<<str;
            return true;
        }
    }
    //其他事件抛给父类
    return QWidget::eventFilter(obj,e);
}
过滤器和事件分发器有什么不一样呢?

17.绘图事件
创建画家,可以设置画笔,字体,画刷,画线的风格,创建画笔之后要添加到画家身上painter.setXXX()!

    //绘图事件
    void paintEvent(QPaintEvent *);
//绘图事件
void Widget::paintEvent(QPaintEvent *){
   //创建一个画家
    QPainter painter(this);

    //设置画笔
    QPen pen(QColor(255,0,0));

    //设置画笔的宽度
    pen.setWidth(3);

    //设置风格
    pen.setStyle(Qt::DotLine);

    //将笔添加到画家
    painter.setPen(pen);

    //画刷
    QBrush brush(Qt::green);

    //画刷的风格
    brush.setStyle(Qt::Dense4Pattern);
    painter.setBrush(brush);

    //画线
    painter.drawLine(QPoint(0,0),QPoint(100,100));

    //画圆  ellipse是椭圆,圆是特殊的椭圆,第一个点是远点坐标,后面两个数是x_r,y_r;二者相等就是个圆了
    painter.drawEllipse(QPoint(100,100),50,50);

    //画矩形  20,20是坐标,50,50是长和宽
    painter.drawRect(QRect(20,20,50,50));

    //写字  相当于画了一个矩形框,在这个矩形框内写字
    painter.drawText(QRect(10,200,100,100),"好好学习,天天向上");


------------------------------------------------------------------------
	painter.drawEllipse(QPoint(100,100),50,50);

    //设置抗锯齿能力 线更圆滑一些  效率会变低
    painter.setRenderHint(QPainter::Antialiasing);
    painter.drawEllipse(QPoint(250,100),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));
}

在这里插入图片描述
在这里插入图片描述
画出已有图片

painter.drawPixmap(posX,0,QPixmap(":/Image/Luffy.png"));
 //点击移动按钮 让图片移动
    posX = 0;
    connect(ui->btn_move,&QPushButton::clicked,[=](){
        posX +=20;
        //手动调用绘图事件
        update();

    });

    //用计时器来使图片移动
    connect(timer1,&QTimer::timeout,[=](){
        posX++;
        update();
    });

绘图设备

   // QPixmap做绘图设备  对不同平台做了显示的优化
   //创建大小为300*300的画板
    QPixmap pix(300,300);

    //背景填充为白色
    pix.fill(Qt::white);

    QPainter painter(&pix);

    painter.setPen( QPen(Qt::red));
    painter.drawEllipse(QPoint(150,150),100,100);

    pix.save("E:\\c++\\pix.png");
-----------------------------------------------------------------
    //QImage做绘图设备  不同平台下显示效果一样,可以对像素的访问做了优化,可以修改像素点
    QImage img(300,300,QImage::Format_RGB32);

    img.fill(Qt::white);

    QPainter painter(&img);
    painter.setPen( QPen(Qt::green));
    painter.drawEllipse(QPoint(150,150),100,100);

paintEvent函数:
    //修改像素点
    for(int i =100;i<150;i++){
        for(int j = 100;j<150;j++){
            QRgb value = qRgb(255,0,0);
            img.setPixel(i,j,value);
        }
    }
    painter.drawImage(0,0,img);
-----------------------------------------------------------------
    img.save("E:\\c++\\img.png");

    QPicture pic;
    QPainter painter;
    //画家拿到画板
    painter.begin(&pic);

    painter.setPen( QPen(Qt::blue));
    painter.drawEllipse(QPoint(150,150),100,100);
    painter.end();
    //保存的后缀名没有要求
    pic.save("E:\\c++\\pic.zt");

painEvent函数:
 //重现QPicture命令
    QPicture pic;
    pic.load("E:\\c++\\pic.zt");
    //显示上面画的图像
    painter.drawPicture(0,0,pic);

18.文件读写

 //点击按钮 弹出文件对话框,选择文件
    connect(ui->pushButton,&QPushButton::clicked,[=](){
        QString filePath = QFileDialog::getOpenFileName(this,"打开文件","E:\\C++");
        qDebug()<<filePath;
        if(filePath.isEmpty()){
            QMessageBox::warning(this,"警告","文件路径不能为空");
            return;
        }else{
            //将文件路径放入到lineEdit中
            ui->lineEdit->setText(filePath);

            //将文件内容读取到textEdit中
            QFile file(filePath);
            file.open(QIODevice::ReadOnly);

            //qt默认支持的格式是utf-8
            QByteArray array;
            //一次性全读
            array = file.readAll();
            
            //一行一行读  array = file.readLine();
            //atEnd()是否读到最后一行
            while(!file.atEnd()){
                array += file.readLine();
            }

            ui->textEdit->setText(array);
            
            //转格式为codec设置的格式
            //文本编码格式类
            //QTextCodec * codec = QTextCodec::codecForName("gbk");
            //ui->textEdit->setText(codec->toUnicode(array));
            
            file.close();
            
            //写文件
            file.open(QIODevice::Append);   //追加的方式写文件
            file.write("aaa");
            file.close();
        }

    });

19.文件信息
文件后缀名最常用!

 //读取文件信息
 QFileInfo info(filePath);
qDebug()<<"文件后缀名:"<<info.suffix()<<"文件大小:"<<info.size()<<
          "文件名:"<<info.fileName()<<"文件路径:"<<info.filePath();

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

项目:金币游戏
1.创建项目:选择基类为QMainWindow,类名为MainScene
2.添加资源:qtresource->res.qrc
3.设置游戏主场景配置:在菜单栏设置退出

mainscene.h

#ifndef MAINSCENE_H
#define MAINSCENE_H
#include <QMainWindow>

namespace Ui {
class MainScene;
}

class MainScene : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainScene(QWidget *parent = 0);
    ~MainScene();

    //利用绘图事件 绘制背景
    void paintEvent(QPaintEvent *);

    //维护选择关卡场景的指针
    ChooseLevelScene * chooseScene;
private:
    Ui::MainScene *ui;
};

#endif // MAINSCENE_H

mainscene.cpp

#include "mainscene.h"
#include "ui_mainscene.h"
#include<QPaintEvent>
#include<QPainter>
MainScene::MainScene(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainScene)
{
    ui->setupUi(this);

    //主场景的基本配置
    this->setWindowTitle("翻金币主场景");

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

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

    //点击开始中的退出  实现退出游戏
    connect(ui->actionQuit,&QAction::triggered,[=](){
        this->close();
    });
    
    //开始音效
    QSound * startSound = new QSound(":/res/TapButtonSound.wav",this);

    //播放次数,-1为重复播放
    //startSound->setLoops(5);

    //创建选择关卡的场景
    chooseScene = new ChooseLevelScene;
-------------------------自定义封装按钮,放在主窗口中进行测试↓-----------------------------
    //开始按钮
    MyPushButton * startBtn = new MyPushButton(":/res/MenuSceneStartButton.png");
    startBtn->move(this->width()*0.5-startBtn->width()*0.5,this->height()*0.7);
    //将设置的按钮放在父窗口上
    startBtn->setParent(this);
    connect(chooseScene,&ChooseLevelScene::chooseSceneBack,[=](){
        chooseScene->hide();
        this->show();
    });
	connect(startBtn,&MyPushButton::clicked,[=](){
        startBtn->zoom1();
        startBtn->zoom2();

        //延时进入到选择关卡的场景
        QTimer::singleShot(500,this,[=](){
            //旧场景自身隐藏
            this->hide();
            //显示选择关卡新场景
            chooseScene->show();
        });
    });
}
-------------------------自定义封装按钮,放在主窗口中进行测试 ↑------------------------------
//利用绘图事件 绘制背景
void MainScene::paintEvent(QPaintEvent *){

    QPainter painter(this);

    //加载背景图片
    painter.drawPixmap(0,0,this->width(),this->height(),QPixmap(":/res/PlayLevelSceneBg.png"));

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

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

1.自定义封装按钮:
1.创建MyPushButton类,继承QPushButton
2.重写构造函数,设置两个参数,一个是默认显示图片路径,一个是按下后显示的图片路径(默认为空)
3.设置不规则图片,四个方法缺一不可
4.在主场景中测试该按钮

mypushbutton.h

#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H
#include <QPushButton>
class MyPushButton : public QPushButton
{
    Q_OBJECT
public:
    //explicit MyPushButton(QWidget *parent = 0);

    //normarImg代表正常显示的图片  pressImg代表按下后显示的图片
    MyPushButton(QString normarImg,QString pressImg="");

    QString normalImgPath;

    QString pressImgPath;
//开始按钮的动画设置
    //向下弹起
    void zoom1();

    //向上弹起
    void zoom2();
    
    //重写鼠标按下
    void mousePressEvent(QMouseEvent *e);

    //重写鼠标释放
    void mouseReleaseEvent(QMouseEvent *e);
signals:

public slots:
};
#endif // MYPUSHBUTTON_H

mypushbutton.cpp

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

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

    //QPixmap加载图标
    QPixmap pix;
    bool ret = pix.load(normalImgPath);
    if(!ret){
        QString srt = QString("图片加载失败 %1").arg(normarImg);
        qDebug()<<srt;
        return;
    }

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

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

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

    //设置图标大小
    this->setIconSize(QSize(pix.width(),pix.height()));
}
//向下弹起
void MyPushButton::zoom1(){

    //动画对象
    QPropertyAnimation * animation = new QPropertyAnimation(this,"geometry");

    //动画设置时间间隔
    animation ->setDuration(200);

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

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

    //设置弹起效果
    animation->setEasingCurve(QEasingCurve::OutBounce);

    //让动画执行
    animation->start(QAbstractAnimation::DeleteWhenStopped);
}

//向上弹起
void MyPushButton::zoom2(){
    //动画对象
    QPropertyAnimation * animation = new QPropertyAnimation(this,"geometry");

    //动画设置时间间隔
    animation ->setDuration(200);

    //设置起始位置 和zoom1里面不太一样  但为啥是这里+10
    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(QAbstractAnimation::DeleteWhenStopped);
}

//重写鼠标按下   我运行的时候鼠标按下,按钮就掉下去了,很奇怪!!!
void MyPushButton::mousePressEvent(QMouseEvent *e){
    //如果按下图片的路径不为空,代表需要切换图片
    if(this->pressImgPath != ""){
        QPixmap pix;
        bool ret = pix.load(pressImgPath);
        if(!ret){
            QString srt = QString("图片加载失败 %1").arg(pressImgPath);
            qDebug()<<srt;
            return;
        }

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

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

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

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

    //点击响应时间抛给父类
    QPushButton::mousePressEvent(e);
}

//重写鼠标释放
void MyPushButton::mouseReleaseEvent(QMouseEvent *e){
    //如果按下图片的路径不为空,代表需要切换图片
    if(this->pressImgPath != ""){
        QPixmap pix;
        bool ret = pix.load(this->normalImgPath);
        if(!ret){
            QString srt = QString("图片加载失败 %1").arg(normalImgPath);
            qDebug()<<srt;
            return;
        }

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

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

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

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

    //点击响应时间抛给父类
    QPushButton::mouseReleaseEvent(e);
}

chooselevelscene.h

#ifndef CHOOSELEVELSCENE_H
#define CHOOSELEVELSCENE_H
#include <QMainWindow>

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

    //重写绘图事件
    void paintEvent(QPaintEvent *);
signals:
    //点击返回按钮后  抛出自定义信号
    void chooseSceneBack();
public slots:

};
#endif // CHOOSELEVELSCENE_H

chooselevelscene.cpp

#include "chooselevelscene.h"
#include<QMenuBar>
#include<QAction>
#include<QPainter>
ChooseLevelScene::ChooseLevelScene(QWidget *parent) :
    QMainWindow(parent)
{
    //菜单栏
    QMenuBar * bar = menuBar();
    QMenu * startMenu = bar->addMenu("开始");
    QAction * quitAction = startMenu->addAction("退出");

    connect(quitAction,&QAction::triggered,[=](){
       this->close();
    });

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

    //窗口大小
    this->setFixedSize(320,588);

    //设置图标
    this->setWindowIcon(QPixmap(":/res/Coin0001.png"));
	
	//选中按钮后的音效
    QSound * chooseSound = new QSound(":/res/TapButtonSound.wav",this);

    //返回音效按钮
    QSound * backSound = new QSound(":/res/BackButtonSound.wav",this);
-----------------------------------返回按钮的设置↓--------------------------------------------
	//返回按钮
    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()<<"f";
        //延时发送返回信号
        QTimer::singleShot(500,this,[=](){
        	backSound->play();
            emit this->chooseSceneBack();
        });
    });
 //指向具体关卡的指针
    playScene = NULL;
-----------------------------------返回按钮的设置↑------------------------------------------ 
//创建20个选择关卡的按钮
    for(int i =0;i<20;i++){
        MyPushButton * menuBtn = new MyPushButton(":/res/LevelIcon.png");

        menuBtn->setParent(this);

        //一个for循环做出一个矩阵,用% 和 /,前者代表行,后者代表列
        menuBtn->move(25+(i%4)*70,130+(i/4)*70);

        connect(menuBtn,&MyPushButton::clicked,[=](){
            //qDebug()<<"您选择的是第"<<i+1<<"关";
            playScene = new PlayScene(i+1);
			chooseSound->play();
            this->hide();
			//设置游戏场景位置
            this->playScene->setGeometry(this->geometry());

            this->playScene->show();

            //监听游戏场景中点击返回按钮 发送自定义信号
            connect(this->playScene,&PlayScene::chooseSceneBack,[=](){
            	
            	//跟上一个场景中的位置相同
                this->setGeometry(this->playScene->geometry());
                
                delete this->playScene;
                this->playScene = NULL;
                this->show();
            });
        });

        //创建显示具体关卡号label
        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->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
        //添加QLabel之后会覆盖到按钮上面,从而吸收鼠标事件,解决方法:

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

//重写绘图事件
void ChooseLevelScene::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");
    painter.drawPixmap( (this->width()-pix.width())*0.5,30,pix.width(),pix.height(),pix);
}

2.开始按钮特效封装:在自定义类MyPushButton中添加zoom1和zoom2弹起效果函数,设置动画的事件间隔,设置起始位置,并且让动画执行
3.实现返回按钮:点击返回按钮回到主场景
重写鼠标按下和鼠标释放事件,点击后发送自定义的信号(自定义信号的写法),在主场景中监听返回的信号,并把选关场景隐藏,显示主场景
4.创建选择关卡的小按钮:
利用for循环实现二维矩阵(记住是如何实现的:一个for实现二维矩阵),并创建20个按钮,在按钮上创建QLabel显示具体关卡号,QLabel设置:设置父窗口,位置,文本,固定大小,设置居中,由于QLabel会覆盖按钮,并吸收点击事件,所以设置鼠标穿透属性。

5.用户选择关卡,创建游戏场景
初始化场景中的内容
选择关卡场景和游戏场景之间的切换
创建玩家具体显示的关卡号的标签
设置位置和大小
设置吸收事件
playscene.h

#ifndef PLAYSCENE_H
#define PLAYSCENE_H

#include <QMainWindow>

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

    //具体选择的关卡号
    int leaveIndex;

    //重写绘图事件
    void paintEvent(QPaintEvent *);
        
    //记录当前关卡的二维数组
    int gameArray[4][4]; //二维数组
    //是否胜利
    bool isWin = true;
signals:
    void chooseSceneBack();
public slots:

};

#endif // PLAYSCENE_H

playscene.cpp

#include "playscene.h"
#include<QMenu>
#include<QMenuBar>
#include<QDebug>
#include<QPainter>
#include"mypushbutton.h"
#include"chooselevelscene.h"
#include<QLabel>

PlayScene::PlayScene(int leaveIndex){

    //记录用户选择的具体关卡号
    this->leaveIndex = leaveIndex;
    qDebug()<<"用户选择的是"<<this->leaveIndex<<"关";

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

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

    //设置标题
    this->setWindowTitle("第"+QString::number(this->leaveIndex)+"关");

    //创建菜单栏
    QMenuBar * bar = this->menuBar();
    this->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/ConFilpSound.wav",this);
    //胜利按钮音效
    QSound * winSound = new QSound(":/res/LevelWinSound.wav",this);

    //返回按钮
    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,[=](){
        emit this->chooseSceneBack();
    });

    //创建用户选择关卡的标签
    QLabel * label = new QLabel;
    label->setParent(this);

    QString str = QString("Leavel: %1 ").arg(this->leaveIndex);
    label->setText(str);
//设置字体
    QFont font;
    font.setFamily("华文新魏");
    font.setPointSize(15);
    label->setFont(font);
    //设置位置和大小  设置字体的显示范围和大小
    label->setGeometry(QRect(30,this->height()-50,120,50));

--------------------------------维护金币银币的数组的初始化↓---------------------------------
	dataConfig config;
    //初始化二维数组
    for(int i=0;i<4;i++){
        for(int j =0;j<4;j++){
            this->gameArray[i][j] = config.mData[this->leaveIndex][i][j];
        }
    }
--------------------------------维护金币银币的数组的初始化↑--------------------------------- 
-----------------------------------------胜利图片的加载↓------------------------------------
    //胜利图片,用标签的形式,先将其放在窗口中-h的位置
    QLabel * winLabel =new QLabel;
    QPixmap tmpPix;
    tmpPix.load(":/res/LevelCompletedDialogBg.png");
    winLabel->setGeometry(0,0,tmpPix.width(),tmpPix.height());
    winLabel->setPixmap(tmpPix);
    winLabel->setParent(this);
    winLabel->move((this->width() - tmpPix.width())*0.5,-tmpPix.height());
-----------------------------------------胜利图片的加载👆------------------------------------
//创建金币背景图片
    for(int i = 0; i<4;i++){
        for(int j=0;j<4;j++){
            //QLabel显示图片
            QLabel * label = new QLabel;
            QPixmap pix;
            pix.load(":/res/BoardNode.png");
            label->setGeometry(0,0,pix.width(),pix.height());
            
            label->setParent(this);
            label->move(57+i*50,200+j*50);
-----------------------------------------金币银币的设置↓------------------------------------			
			QString str;
            if(this->gameArray[i][j]==1){
                str = ":/res/Coin0001.png";
            }
            else{
                str = ":/res/Coin0008.png";
            }
            //创建金币
            MyCoin * coin = new MyCoin(str);
            coin->setParent(this);
            coin->move(59+i*50,204+j*50);
-----------------------------------------金币银币的设置↑------------------------------------
			//给金币的属性赋值
            coin->posX = i;
            coin->posY = j;
            coin->flag = this->gameArray[i][j];
---------------------------------------翻转金币↓-------------------------------------------
            connect(coin,&MyCoin::clicked,[=](){
                //点击金币的音效播放
                flipSound->play();
                //将所有的按钮都屏蔽点击
               for(int i =0;i<4;i++){
                   for(int j = 0;j<4;j++){
                       //如果有一个是银币的状态,就是失败了
                       coinBtn[i][j]->isWin =true;

                   }
               }
               
               coin->changeFlag();
               //同步二维数组,如果以后有保存需求,可以利用数组还原
               this->gameArray[i][j] = this->gameArray[i][j] == 1 ? 0:1;


               //翻转周围硬币  检测右侧金币是否可以翻转
               //右侧硬币是否可以翻转
               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] == 1 ? 0:1;
               }
               //检测左侧硬币是否可以翻转
               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] == 1 ? 0:1;
               }
               //检测下侧金币是否可以翻转
               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] == 1 ? 0:1;
               }
               //检测上侧金币是否可以翻转
               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] == 1 ? 0:1;
               }
---------------------------------------翻转金币↑-------------------------------------------
   				//开启可以让金币点击的状态
               for(int i =0;i<4;i++){
                   for(int j = 0;j<4;j++){
                       //如果有一个是银币的状态,就是失败了
                       coinBtn[i][j]->isWin =false;

                   }
               }               

				//检测是否胜利
               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(isWin){
                   qDebug()<<"游戏胜利了";
					//播放胜利音效
			       winSound->play();
                   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);  //时间间隔1s
                   animation->setStartValue(QRect(winLabel->x(),winLabel->y(),winLabel->width(),winLabel->height()));
                   animation->setEndValue(QRect(winLabel->x(),winLabel->y()+114,winLabel->width(),winLabel->height()));
                   animation->setEasingCurve(QEasingCurve::OutBounce);
                   animation->start(QAbstractAnimation::DeleteWhenStopped); 
----------------------------胜利图片以动画形式弹出来↑---------------------------------------
               }
            });
        }
    }
}

//重写绘图事件
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.width(),pix.height(),pix);
}

金币类的创建:
创建MyCoin类
重写构造函数,传入显示的金币或者银币的图片路径
根据路径显示金币或银币
mycoin.h

#ifndef MYCOIN_H
#define MYCOIN_H
#include <QPushButton>
class MyCoin : public QPushButton
{
    Q_OBJECT
public:
    //explicit MyCoin(QWidget *parent = 0);
    //参数列表
    MyCoin(QString imgPath);
    //x坐标
    int posX;

    //y坐标
    int posY;

    //正反标志
    bool flag;

    //改变标志,执行翻转效果
    void changeFlag();

    //正面翻反面 定时器
    QTimer *timer1;
    //反面翻正面 定时器
    QTimer *timer2;

    //最小图片
    int min = 1;

    //最大图片
    int max = 8;
    
    //做翻转动画的标志
    bool isAnimation =false;
    
    //重写鼠标按下事件
    void mousePressEvent(QMouseEvent *e);
signals:

public slots:
};
#endif // MYCOIN_H

mycoin.cpp

#include "mycoin.h"
#include<QDebug>
#include<QPixmap>
MyCoin::MyCoin(QString imgPath){
    QPixmap pix;
    bool ret = pix.load(imgPath);
    if(!ret){
        qDebug()<<"图片加载失败:"<<imgPath;
        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);

    //监听两个定时器的timeout信号
    //金币翻银币的计时器
    connect(timer1,&QTimer::timeout,[=](){
        QPixmap pix;
        QString str = QString(":/res/Coin000%1").arg(this->min++);
        bool ret = pix.load(str);
        if(!ret){
            qDebug()<<"图片加载失败:"<<imgPath;
            return;
        }

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

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

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

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

        if(this->min>this->max){
            //还原最小值
            this->min = 1;
            
            //动画执行结束,isAnimation值为false
            this->isAnimation = false;
            timer1->stop();
        }
    });

    //银币翻金币的定时器
    connect(timer2,&QTimer::timeout,[=](){
        QPixmap pix;
        QString str = QString(":/res/Coin000%1").arg(this->max--);
        bool ret = pix.load(str);
        if(!ret){
            qDebug()<<"图片加载失败:"<<imgPath;
            return;
        }

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

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

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

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

        if(this->max<this->min){
            //还原最小值
            this->max = 8;
            
            //动画执行结束,isAnimation值为false
            this->isAnimation = false;
            timer2->stop();
        }
    });
}
---------------------------------金币翻转定时器↑--------------------------------------------
//改变硬币的状态,执行翻转效果
void MyCoin::changeFlag(){
    if(this->flag){
        //启动金币翻银币的定时器
        timer1->start(30);
        //做动画时,值为true
        this->isAnimation = true;
        this->flag = false;
    }else{
        //启动银币翻金币的定时器
        timer2->start(30);
        //做动画时,值为true
        this->isAnimation = true;
        //如果是银币的标志,改为金币
        this->flag = true;
    }
}

//重写鼠标按下事件
void MyCoin::mousePressEvent(QMouseEvent *e){
    //如果做动画,这个期间不响应事件
    if(this->isAnimation || this->isWin){
        return;
    }else{
        //否则抛给父类
        return QPushButton::mousePressEvent(e);
    }
}



配置文件的导入:
在项目中加入dataConfig.h和dataConfig.cpp

初始化关卡:
利用配置文件中的数据来初始化,在playScene中创建二维数组gameArray[4][4]维护当前关卡,将配置文件中的数组赋值给gameArray若值为1,使其显示金币,值为2显示银币。

金币翻转特效实现:
给每个硬币增加位置属性:posX和posY,以及判断正反面的标志flag
增加翻转硬币的行为,开启相应的定时器
监听定时器,并且执行切换的动画

优化游戏:
问题:当用户疯狂点击时,动画在执行过程中就会切换另一个动画
设置一个标志解决,bool isAnimation=false;
做动画时,将标志改为true,屏蔽点击事件
做完动画,将标志改为false

翻转周围金币:
创建金币二维数组,方便翻转周围金币MyCoin * coinBtn;
点击金币后,翻转周围,并检测周围金币是否可以翻转(也就是看周围有无金币)
测试

游戏胜利的检测:
在playScene中加入isWin是否胜利的标志
翻转周围金币后,判断是否胜利(看数组的值是否等于0)

游戏胜利后禁止点击:
当游戏判断胜利后,禁止所有金币的点击
解决bug,当手速过快可以再点击胜利后又点击其他金币的bug(先将金币数组全部改为true,不让用户点击,之后再改回来)

胜利图片做动画:
图片用QLabel形式显示,先防到窗口中-h的位置,胜利后,再通过动画,让其弹出来

音效添加:
QSound类,创建对象,并添加声音文件,在适当的位置.play();
设置循环播放:setLoop(x),x为次数,x=-1时代表无限循环

优化项目:将三个场景的切换在同一个位置上
this->setGeometry(this->playScene->geometry());

项目打包发布:切换成release版本进行运行->将exe放入文件中->通过命令打包windeployqt coinFlip.exe->可以通过第三方工具再进行封装nis edit

东西太多了
!!!

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值