- 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
东西太多了
!!!