1 引子
要制作象棋,棋子是必不可少的,但是在网上找了很久,没有找到满意且配套的棋子,有的还需要VIP下载就很难受。于是自己通过QT的标签写字功能调整大小,然后使用绘图事件(QPaintEvent)在标签的外部绘制一个圆圈,最后运行截图就有了棋子。但截图的棋子还有一点就是圆圈之外还有白色部分,如下所示
于是准备自己将图片P一下,就想着在网上找一个免费版本的PS,找了一圈无果后,就去逛各个博客论坛看看,终于找到一个百度网盘下载的方法。众所周知,百度网盘非会员下载有一个60s的极速下载通道,奈何需要下载的压缩包3个多G,还是要等很久才能下载完成,期间就捣鼓自己的QT代码。
经过数分钟的等待,终于下载完毕,想想就激动,免费的PS我来啦!!哈哈哈,结果在点开压缩包的一瞬间我蒙了,居然还有密码,然后一看它的安装教程,写了一个网址需要花钱去买密码,我吐了。花钱是不可能花钱的,然后去网上找破解密码的工具,然而用了两个忘了叫啥名字了,反正没有效果,又浪费一堆时间。最后,室友推荐我去微信关注公众号软件管家,终于下载成功了,我**, 你 **不早说。
最后就是去网上使用PS的方法了,这里就不细说了,最后就达到了自己预想的效果,效果如下。
有没有发现和前面图片没什么两样哈哈哈,下面找个背景对比一下,这样就容易发现了。
2. 正文
注意,本项目只是简单实现,因此固定上方为黑方,下方为红方。
前面说了一大堆废话,现在进入正题吧。
首先,应该对棋子单独创建一个类,用于存储该棋子类型,棋子图片,所属阵营,是否被吃(被吃后就不加载该棋子的图片),以及当前位置(棋盘上的x,y值)。
Chess.h头文件
#ifndef CHESS_H
#define CHESS_H
#include <QWidget>
class Chess : public QWidget
{
Q_OBJECT
public:
explicit Chess(QWidget *parent = nullptr);
void operator=(const Chess& c); // 重载赋值构造函数
// 棋子类型 从0开始为 兵,車,馬,象(相),士(仕),将(帅)
enum TYPE{ARMY,PAO,CAR,HORSE,XIANG,SHI,MASTE};
// 棋子所属阵营 red = 0, black = 1
enum BELONG{RED,BLACK};
signals:
public:
// 初始化棋子
void initChess(const int);
public:
int x;
int y;// 棋子所在x,y坐标,移动会改变 (也可以使用行列表示,但x,y更直观)
int chessType; // 棋子类型
int chessBelong; // 棋子所属阵营
int chessId; // 棋子ID
bool isDead; // 棋子是否被吃
QString chessPic; // 棋子图片
};
#endif // CHESS_H
Chess.cpp
#include "chess.h"
Chess::Chess(QWidget *parent) : QWidget(parent)
{
}
void Chess::operator=(const Chess &c){
x = c.x;
y = c.y;
chessType = c.chessType;
chessBelong = c.chessBelong;
chessId = c.chessId;
isDead = c.isDead;
chessPic = c.chessPic;
}
void Chess::initChess(const int id){
if(id > 31 || id < 0)
return ;
// 初始化棋子id
chessId = id;
// 初始化阵营, 上方为黑,下方为紅
if(id < 16)
chessBelong = BLACK;
else
chessBelong = RED;
// 初始都棋子都存在
isDead = false;
// 初始化棋子类型和位置
// 初始化顺序为黑方->紅方,黑方从上往下,从左往右初始化
// 红方从下往上,从左往右初始化
// 棋盘左上角坐标为 (1,1)
switch(id){
case 0: y = 1, x = 1, chessType = CAR; break;
case 1: y = 1, x = 2, chessType = HORSE; break;
case 2: y = 1, x = 3, chessType = XIANG; break;
case 3: y = 1, x = 4, chessType = SHI; break;
case 4: y = 1, x = 5, chessType = MASTE; break;
case 5: y = 1, x = 6, chessType = SHI; break;
case 6: y = 1, x = 7, chessType = XIANG; break;
case 7: y = 1, x = 8, chessType = HORSE; break;
case 8: y = 1, x = 9, chessType = CAR; break;
case 9: y = 3, x = 2, chessType = PAO; break;
case 10: y = 3, x = 8, chessType = PAO; break;
case 11: y = 4, x = 1, chessType = ARMY; break;
case 12: y = 4, x = 3, chessType = ARMY; break;
case 13: y = 4, x = 5, chessType = ARMY; break;
case 14: y = 4, x = 7, chessType = ARMY; break;
case 15: y = 4, x = 9, chessType = ARMY; break;
case 16: y = 10, x = 1, chessType = CAR; break;
case 17: y = 10, x = 2, chessType = HORSE; break;
case 18: y = 10, x = 3, chessType = XIANG; break;
case 19: y = 10, x = 4, chessType = SHI; break;
case 20: y = 10, x = 5, chessType = MASTE; break;
case 21: y = 10, x = 6, chessType = SHI; break;
case 22: y = 10, x = 7, chessType = XIANG; break;
case 23: y = 10, x = 8, chessType = HORSE; break;
case 24: y = 10, x = 9, chessType = CAR; break;
case 25: y = 8, x = 2, chessType = PAO; break;
case 26: y = 8, x = 8, chessType = PAO; break;
case 27: y = 7, x = 1, chessType = ARMY; break;
case 28: y = 7, x = 3, chessType = ARMY; break;
case 29: y = 7, x = 5, chessType = ARMY; break;
case 30: y = 7, x = 7, chessType = ARMY; break;
case 31: y = 7, x = 9, chessType = ARMY; break;
}
// 初始化图片
if(id < 16){ // 黑方
switch (chessType) {
case ARMY: chessPic = ":/ChessImage/black_army.png"; break;
case PAO: chessPic = ":/ChessImage/black_pao.png"; break;
case CAR: chessPic = ":/ChessImage/black_car.png"; break;
case HORSE: chessPic = ":/ChessImage/black_horse.png"; break;
case XIANG: chessPic = ":/ChessImage/black_xiang.png"; break;
case SHI: chessPic = ":/ChessImage/black_shi.png"; break;
case MASTE: chessPic = ":/ChessImage/black_maste.png"; break;
}
}
else{ // 红方
switch (chessType) {
case ARMY: chessPic = ":/ChessImage/red_army.png"; break;
case PAO: chessPic = ":/ChessImage/red_pao.png"; break;
case CAR: chessPic = ":/ChessImage/red_car.png"; break;
case HORSE: chessPic = ":/ChessImage/red_horse.png"; break;
case XIANG: chessPic = ":/ChessImage/red_xiang.png"; break;
case SHI: chessPic = ":/ChessImage/red_shi.png"; break;
case MASTE: chessPic = ":/ChessImage/red_maste.png"; break;
}
}
}
然后需要在棋盘类定义两个数组,chess数组用于存储32个棋子,label数组用于加载棋子,并且label数组合chess数组下标一一对应。也就是一个chess对应一个label。ChessSize用于设置棋盘格子的大小,它在后面使用非常多。
// 棋子大小 即 格子大小
int ChessSize;
// 32个棋子
Chess chess[32];
QLabel* label[32];
定义一个init()函数用于根据棋子的起始位置加载label。
void Widget::init(){
for(int i = 0; i < 32; i++){
chess[i].initChess(i);
// 利用QLabel加载棋子图片
label[i] = new QLabel(this);
label[i]->resize(ChessSize,ChessSize);
label[i]->setPixmap(QPixmap(chess[i].chessPic));
// 自动适应图片大小
label[i]->setScaledContents(true);
label[i]->setGeometry(chess[i].x*ChessSize - ChessSize/2,
chess[i].y*ChessSize - ChessSize/2,
ChessSize,
ChessSize
);
label[i]->show();
}
}
最后就是棋盘的构造函数调用init()
// 设置 棋子大小, 即格子大小
this->ChessSize = 50;
// 固定窗口大小为棋盘大小
this->setMinimumSize(500,550);
this->setMaximumSize(500,550);
// 初始化棋子在棋盘上
init();
最后效果如下