Qt中国象棋之棋盘的绘制

中国象棋简介

中国象棋是起源于中国的一种棋戏,属于二人对抗性游戏的一种,在中国有着悠久的历史。由于用具简单,趣味性强,成为流行极为广泛的棋艺活动。

棋盘简介

  • 直线

棋盘上较长的平行排列的边称为直线,共有9条,其中7条被河界隔断。用红色棋子一方的直线从右往左依次用中文数字一、二、三、四、五、六、七、八、九表示;用黑色棋于一方的直线在红方对面也从右往左依次用阿拉伯数字1、2、3、4、5、6、7、8、9表示。

  • 横线

棋盘上较短的平行排列的边称为横线。横线共有10条,用红色棋子一方的横线从红方底线算起,从下往上依次用中文数字一至十表示;用黑色棋子一方的横线则从黑方底线开始,依次用阿拉伯数字1-10表示。

  • 交叉点

直线与横线相交的地方称为“交叉点”。整个棋盘共有90个交叉点,棋子就摆放和活动在这些交叉点上。

  • 河界

棋盘中央没有画直线的地方称为“河界”。它代表弃战双方的分界线,确定了各自的地域。

  • 九宫

棋盘两端各画有斜交叉线的地方称为“九宫”。将则只能在各自“九宫”的9个交叉点上活动。

棋子

所有的棋子共有三十二个,其中又分为红、黑两组(分别代表对垒的一方),每组共有十六个棋子(为了区别双方的棋子,不仅在颜色中有所区别,而且还会使用同音不同字的棋子),其中又各分为七种棋子,其名称和数目如下:

红棋子:帅一个,车、马、炮、相、士各两个,兵五个。

黑棋子:将一个,车、马、炮、象、士各两个,卒五个。

通过Qt5实现中国象棋

Qt5纯代码实现中国象棋,通过paintEvent绘制事件绘制棋盘和棋子

通过重绘事件绘制棋盘和棋子,通过鼠标事件实现棋子移动等

设计思路

  1. 绘制棋盘
  2. 绘制棋子
  3. 走棋
  4. 走棋规则

一、新建项目

新建项目 -> 其他项目 -> Empty qmake Project,项目名填myChinessChess

添加新文件 -> C++ -> C++ Source File,文件名main.cpp

工程文件myChinessChess.pro添加一行

QT += widgets gui

二、添加棋盘类

添加新文件 -> C++ -> C++ Class,类名ChessBoard,Base class选QWidget

main.cpp文件内容如下,可以先运行一下

#include <QApplication>

#include "chessboard.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    ChessBoard board;
    board.show();

    return app.exec();
}

棋盘头文件chessboard.h头文件中

#ifndef CHESSBOARD_H
#define CHESSBOARD_H

#include <QWidget>
#include <QPaintEvent>
#include <QPainter>
#include <QPoint>
#include <QRect>
#include <QPen>

class ChessBoard : public QWidget
{
    Q_OBJECT
public:
    QPoint origin;  /*棋盘原点坐标*/
    int sideLen;    /*棋盘格子边长*/
    explicit ChessBoard(QWidget *parent = nullptr);    /*构造函数*/
    void paintEvent(QPaintEvent *); /*重绘事件*/
    void drawRightAngle(QPainter &pt, QPoint c);    /*绘制棋子炮的停靠点(绘制几个直角)*/

    QPoint center(int row, int col);    /*将棋盘行、列坐标转换成像素坐标*/

signals:

public slots:
};

#endif // CHESSBOARD_H

棋盘实现文件chessboard.cpp

#include "chessboard.h"

ChessBoard::ChessBoard(QWidget *parent) : QWidget(parent)
{
    setWindowTitle(tr("中国象棋"));
    origin = QPoint(60,60);  /*棋盘原点坐标*/
    sideLen = 60;    /*棋盘格子边长*/
    resize(origin.x()*3+sideLen*8, origin.y()*2+sideLen*9);
}


/*重绘事件*/
void ChessBoard::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    QPen pen;
    pen.setWidth(3);
    painter.setPen(pen);

    /*绘制棋盘外廊框*/
    painter.drawRect(QRect(origin.x()-5,origin.y()-5, sideLen*8+10, sideLen*9+10));
    /*绘制棋盘外围*/
    pen.setWidth(1);
    painter.setPen(pen);
    painter.drawRect(QRect(origin, center(9,8)));
    /*绘制剩下的8横7竖*/
    for(int i=1; i<=8; i++) {
        painter.drawLine(center(i,0), center(i,8));
        if(i<8) {
            painter.drawLine(center(0,i), center(4,i));
            painter.drawLine(center(5,i), center(9,i));
        }
    }
    /*绘制九宫斜线*/
    painter.drawLine(center(0,3), center(2,5));
    painter.drawLine(center(2,3), center(0,5));
    painter.drawLine(center(7,3), center(9, 5));
    painter.drawLine(center(9,3), center(7,5));
    /*绘制楚河、汉界*/
    painter.setPen(Qt::gray);
    painter.setFont(QFont("system", 24, sideLen/2));
    painter.drawText(QRect(center(4,1), center(5,3)), "楚河", QTextOption(Qt::AlignCenter));
    painter.drawText(QRect(center(4,5), center(5,7)), "汉界", QTextOption(Qt::AlignCenter));
    /*绘制直角(棋子炮的停靠点)*/
    drawRightAngle(painter, center(2,1));
    drawRightAngle(painter, center(2,7));
    drawRightAngle(painter, center(7,1));
    drawRightAngle(painter, center(7,7));
}

/*绘制棋子炮的停靠点(绘制几个直角)*/
void ChessBoard::drawRightAngle(QPainter &pt, QPoint c)
{
    int x = c.x();
    int y = c.y();
    int r = sideLen/10;
    pt.drawLine(x-2*r, y-r, x-r, y-r);
    pt.drawLine(x-2*r, y+r, x-r, y+r);
    pt.drawLine(x+r, y-r, x+2*r, y-r);
    pt.drawLine(x+r, y+r, x+2*r, y+r);

    pt.drawLine(x-r, y-2*r, x-r, y-r);
    pt.drawLine(x-r, y+r, x-r, y+2*r);
    pt.drawLine(x+r, y-2*r, x+r, y-r);
    pt.drawLine(x+r, y+r, x+r, y+2*r);
}

/*将棋盘行、列坐标转换成像素坐标*/
QPoint ChessBoard::center(int row, int col)
{
    return QPoint(origin.x()+sideLen*col, origin.y()+sideLen*row);
}

效果图

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值