本案例是对Qt的基本控件,事件处理,资源文件的使用等知识的综合应用。以及一些开发思想和逻辑控制。
首先了解下案例的文件构成
头文件:
mainwindow.h
chooselevelscene.h
playscene.h
mypushbutton.h
mycoin.h
dataconfig.h
源文件:
main.cpp
mainwindow.cpp
chooselevelscene.cpp
playscene.cpp
mypushbutton.cpp
mycoin.cpp
dataconfig.cpp
资源文件
res.qrc 其中添加了图片,音频资源
新建资源文件后,添加前缀,添加文件,构建。 提前将资源文件加载好。
初步实现是搭建基本的场景,先设计出主界面。
mainwindow.h
public:
virtual void paintEvent(QPaintEvent *event);
ChooseLevelScene *chooseScence = NULL;
该文件中主要是这两句, 第一句实现在cpp通过重写绘图事件,构建主场景的显示界面。
第二句提前定义好第二个选择场景。在构造函数中new出该场景对象实现管理与切换。
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置固定大小
setFixedSize(320,588);
//设置窗口图标
setWindowIcon(QIcon(":/image/2.jpg"));
//设置窗口标题
//setWindowTitle("打小猪");
setWindowTitle("pig");
//退出按钮
connect(ui->actionquit,&QAction::triggered,[=](){
this->close();
});
//准备开始按钮的音效
//QSound *startSound = new QSound(":/s/sound/02.wav",this);
//开始按钮
MyPushButton *startBtn = new MyPushButton(":/image/3.jpg");
startBtn->setParent(this);
startBtn->move(this->width()*0.5-startBtn->width()*0.5,this->height()*0.7);
chooseScence = new ChooseLevelScene;
//监听信号
connect(chooseScence,&ChooseLevelScene::chooseSceneBack,this,[=](){
this->setGeometry(chooseScence->geometry());
chooseScence->hide();
this->show();
});
connect(startBtn,&MyPushButton::clicked,[=](){
// qDebug()<<"press start";
//播放开始音效资源
// startSound->play();
// QSound::play(":/s/sound/02.wav");
startBtn->zoom1();
startBtn->zoom2();
//延时进入关卡中
QTimer::singleShot(500,this,[=](){
//设置chooseScence场景的位置
chooseScence->setGeometry(this->geometry());
//进入到选择关卡的场景中
this->hide();
chooseScence->show();
});
});
}
最上面一小段是设置界面大小,标题,图标,以及菜单栏上的退出按钮
另外,本案例中的connect基本都用了lambda表达式,这样就省去了写槽函数。主函数的代码量增大,可读性差了些。 但是免去了定义许多槽函数。
connect(ui->actionquit,&QAction::triggered,[=](){
this->close();
});
接下来注释掉的语句用来建立音效对象。
下来是使用代码建立开始按钮。 设置好它的对象树,并移到合适位置。 (此处的自定义按钮的构造函数中实现了传入图标及按钮大小和图标的设置 )
新建出选择场景用来切换。
两个信号与槽连接实现了开始按钮切换场景和第二个场景中返回按钮返回当前界面
在开始按钮按下中,自定义按扭还封装了弹跳的动画接口,实现按钮特效。
同时,使用定时器
QTimer::singleShot(500,this,[=](){
//设置chooseScence场景的位置
chooseScence->setGeometry(this->geometry());
//进入到选择关卡的场景中
this->hide();
chooseScence->show();
});
实现了场景切换的延时。
chooseScence->setGeometry(this->geometry());
用来保持切换场景时位置不改变
void MainWindow::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QPixmap pix;
pix.load(":/image/7.jpg");
//指定长宽
painter.drawPixmap(0,0,this->width(),this->height(),pix);
//在背景上加图标背景
pix.load(":/image/1.jpg");
//缩放
pix=pix.scaled(pix.width()*0.5,pix.width()*0.5);
painter.drawPixmap(10,30,pix);
}
通过重写绘图事件在主窗口中绘制了背景。 创建画家,装载图片,缩放,绘制。
自定义按钮的构造函数和对外接口提供了一些按钮的自定义功能
mypushbutton.h
class MyPushButton : public QPushButton
{
Q_OBJECT
public:
// explicit MyPushButton(QWidget *parent = nullptr);
// 正常显示的图片路径 按下后的图片路径
MyPushButton(QString normalImg,QString pressImg = "");
QString normalImgPath;
QString pressImgPath;
//弹跳特效
void zoom1(); //向下跳
void zoom2(); //向上跳
virtual void mousePressEvent(QMouseEvent *e);
virtual void mouseReleaseEvent(QMouseEvent *e);
该按钮继承自QPushButton类,自定义了构造函数,重写了鼠标按下和弹起事件,定义了两个弹跳特效的函数,两个QString成员用来保存构造时传入的图片路径
mypushbutton.cpp
MyPushButton::MyPushButton(QString normalImg,QString pressImg )
{
this->normalImgPath = normalImg;
this->pressImgPath = pressImg;
QPixmap pix;
bool ret = pix.load(normalImg);
if(!ret)
{
qDebug()<<"load fail";
return ;
}
//设置按钮依据图片固定大小
this->setFixedSize(pix.width()*0.3,pix.height()*0.3);
//设置不规则样式
this->setStyleSheet("QPushButton{border:0px;}");
//设置图标
this->setIcon(pix);
//设置图标大小
this->setIconSize(QSize(pix.width()*0.3,pix.height()*0.3));
}
void MyPushButton::zoom1()
{
QPropertyAnimation *animation = new QPropertyAnimation(this,"geometry");
//设置动画时间间隔
animation->setDuration(200);
//起始位置
animation->setStartValue(QRect(this->x(),this->y(),this->width(),this->height()));
//结束位置
animation->setEndValue(QRect(this->x(),this->y()+10,this->width(),this->height()));
//设置弹跳曲线
animation->setEasingCurve(QEasingCurve::OutBounce);
//执行动画
animation->start();
}
void MyPushButton::zoom2()
{
QPropertyAnimation *animation = new QPropertyAnimation(this,"geometry");
//设置动画时间间隔
animation->setDuration(200);
//起始位置
animation->setStartValue(QRect(this->x(),this->y()+10,this->width(),this->height()));
//结束位置
animation->setEndValue(QRect(this->x(),this->y(),this->width(),this->height()));
//设置弹跳曲线
animation->setEasingCurve(QEasingCurve::OutBounce);
//执行动画
animation->start();
}
void MyPushButton::mousePressEvent(QMouseEvent *e)
{
if(this->pressImgPath != "")//传入的状态不为空,说明要切换图片
{
QPixmap pix;
bool ret = pix.load(this->pressImgPath);
if(!ret)
{
qDebug()<<"load fail";
}
this->setFixedSize(pix.width()*0.3,pix.height()*0.3);
this->setStyleSheet("QPushButton{border:0px}");
this->setIcon(pix);
this->setIconSize(QSize(pix.width()*0.3,pix.height()*0.3));
}
return QPushButton::mousePressEvent(e);
}
void MyPushButton::mouseReleaseEvent(QMouseEvent *e)
{
if(this->pressImgPath != "")//传入的状态不为空,说明要切换图片
{
QPixmap pix;
bool ret = pix.load(this->normalImgPath);
if(!ret)
{
qDebug()<<"load fail";
}
this->setFixedSize(pix.width()*0.3,pix.height()*0.3);
this->setStyleSheet("QPushButton{border:0px}");
this->setIcon(pix);
this->setIconSize(QSize(pix.width()*0.3,pix.height()*0.3));
}
return QPushButton::mouseReleaseEvent(e);
}
代码多是重复的,核心一个是设置按钮大小和图标
另一个是设置动画。
chooselevelscene.h
virtual void paintEvent(QPaintEvent *event);
PlayScene *play;
signals:
void chooseSceneBack();
主要就是重写绘图事件,另一个是定一个信号传给主界面响应。还有是定义第三个场景用来管理。
chooselevelscene.cpp
ChooseLevelScene::ChooseLevelScene(QWidget *parent) : QMainWindow(parent)
{
//配置选择关卡场景
this->setFixedSize(320,588);
this->setWindowIcon(QPixmap(":/image/2.jpg"));
this->setWindowTitle("choose sceene");
//创建菜单栏
QMenuBar *bar = menuBar();
setMenuBar(bar);
QMenu *startMenu = bar->addMenu("start");
QAction *quitAction = startMenu->addAction("quit");
connect(quitAction,&QAction::triggered,[=](){
this->close();
});
//返回按钮
MyPushButton *backBtn = new MyPushButton(":/image/1.jpg",":/image/2.jpg");
backBtn->setParent(this);
backBtn->move(this->width()-backBtn->width(),this->height()-backBtn->height());
connect(backBtn,&MyPushButton::clicked,[=](){
// backBtn->zoom1();
//告诉主场景 我返回了,主场景监听chooselevelscene的返回按钮
//自定义信号
//延时发送信号
QTimer::singleShot(300,this,[=](){
//进入到选择关卡的场景中
emit this->chooseSceneBack();
});
});
//创建选择关卡的按钮
for(int i =0;i<20;i++) //一个循环写出一个矩阵
{
MyPushButton *menuBtn = new MyPushButton(":/image/2.jpg");
menuBtn->setParent(this);
menuBtn->move(25+i%4*70,130+i/4*70);
connect(menuBtn,&MyPushButton::clicked,[=](){
qDebug()<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;
label->setParent(this);
label->setFixedSize(menuBtn->width(),menuBtn->height());
QFont font;
font.setFamily("华文新魏");
font.setPointSize(20);
label->setFont(font);
label->setStyleSheet("color:blue;"); //设置字体颜色
label->setText(QString::number(i+1));
// label->setFont(QFont());
label->move(25+i%4*70,130+i/4*70);
label->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
//label 把信号屏蔽了, 把鼠标穿透事件捕获了 ,所以要允许穿透
label->setAttribute(Qt::WA_TransparentForMouseEvents);
}
}
设置标题,图标等,新建菜单栏,添加动作。 创建返回按钮。 返回按钮中延时发送返回信号。
创建选择关卡的按钮时用循环控制,新建20个选关按钮。 每个按钮连接信号与槽,切到第三个场景。
通过QLabel标签 设置关卡号。 同时要通过
//label 把信号屏蔽了, 把鼠标穿透事件捕获了 ,所以要允许穿透
label->setAttribute(Qt::WA_TransparentForMouseEvents);
将鼠标事件穿透给按钮
dataconfig.h
explicit dataConfig(QObject *parent = nullptr);
QMap>>mData;
dataconfig.cpp
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>v;
for(int i=0;i<4;i++)
{
QVectorv1;
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,1,0,1},
{1,1,0,1},
{1,1,0,0},
{1,1,0,1} };
v.clear();
for(int i=0;i<4;i++)
{
QVectorv1;
for(int j=0;j<4;j++)
{
v1.push_back(array2[i][j]);
}
v.push_back(v1);
}
mData.insert(2,v);
……