Qt中提供了强大的2D绘图系统,可以使用相同的API在屏幕和绘图设备上进行绘制,它主要基于QPainter、QPaintDevice和QPaintEngine这三个类。其中QPainter用来执行绘图操作;QPaintDevice提供绘图设备,它是一个二维空间的抽象,可以使用QPainter在其上进行绘制;QPaintEngine提供了一些接口,可以用于QPainter在不同的设备上进行绘制。
在绘图系统中由QPainter来完成具体的绘制操作,QPainter类提供了大量高度优化的函数来完成GUI编程所需要的大部分绘制工作。QPainter可以绘制一切想要的图形,从最简单的一条直线到其他任何复杂的图形,它还可以用来绘制文本和图片。QPainter可以在继承自QPaintDevice类的任何对象上进行绘制操作。
QPainter一般在一个部件的重绘事件(PaintEvent)的处理函数paintEvent()中进行绘制,首先要创建QPainter对象,然后进行图形的绘制,最后销毁QPainter对象。
1.新建QtGui应用,项目名称为line,类信息界面不用修改,即类名为MainWindow,基类为QMainWindow。
在mainwindow.h文件中添加重绘事件处理函数的声明:
protected:
voidpaintEvent(QPaintEvent );
所有的绘制操作都要在这个函数里面完成。
下面到mainwindow.cpp文件中先需要添加头文件包含:
#include
添加函数定义
Void MainWindow::paintEvent(QPaintEvent)
{
QPainterpainter(this);
painter.drawLine(QPointF(0,0), QPointF(100, 100));
}
修改paintEvent()函数的内容更改如下:
voidMainWindow::paintEvent(QPaintEvent*)
{
QPainterpainter(this);
QPenpen;//画笔
pen.setColor(QColor(255,0,0));//设置画笔颜色
QBrushbrush(QColor(0,255,0,125));//画刷
painter.setPen(pen);//添加画笔
painter.setBrush(brush);//添加画刷
painter.drawRect(50,50,200,100);//绘制矩形
}
这里分别新建了一个画笔QPen,和画刷QBrush。其中画笔使用了setColor()函数为其设置了颜色,而画刷是在构建的时候直接为其设置的颜色。这里的颜色都是使用的QColor类提供的,里面如果是三个参数,那么分别是红、绿、蓝分量的值,也就是经常说的rgb,取值范围都是0-255,比如这里的(255,0,0)就表明红色分量为255,其他分量为0,那么出来就是红色。如果是四个参数,最后一个参数alpha是设置透明度的,取值范围也是0-255,0表示完全透明,而255表示完全不透明。然后我们将画笔和画刷设置到了painter上,并使用drawRect()绘制了一个矩形,其左上角顶点在(50,50),宽为200,高为100。
可以使用pen.setStyle()来设置画笔样式,可用的画笔样式如下图所示。我们可以将鼠标光标移动到QPen上,按F1就可以查看对应的说明文档。
这个也可以将鼠标光标移动到QBrush上按F1查看其帮助文档。在Qt中为画刷提供了一些可用的样式,可以使用setStyle()函数来设置。如下图所示:
修改paintEvent()函数:
VoidMainWindow::paintEvent(QPaintEvent *)
{
QPainterpainter(this);
QPenpen(Qt::DotLine);
QBrushbrush(Qt::blue);
brush.setStyle(Qt::Dense5Pattern);
painter.setPen(pen);
painter.setBrush(brush);
painter.drawRect(50,50,200,200);
}
按照文档开始步骤创建一个名为gobang的项目。
1.在mainwindow.h中声明重绘函数
首先我们设定一下窗口大小,我们可以使用resize来设定窗口大小
因为我们要绘制一个1818,棋格宽高为25的棋盘,所以我们需要设定大小为480480
接下来我们就可以开始绘制了。首先开始引入#include ,在DrawChessBroad()函数中开始绘制。
效果如图所示:
绘制一个棋子,首先我们绘制的棋子需要知道棋子的圆心坐标,然后五子棋分为黑白两种棋子,每种棋子轮流落子,因此我们需要有一个bool变量,代表当前是黑方还是白方。
步骤如下,选中项目名bogang,点击右键,选择’添加新文件…’,选择C++ C++ Class,点击Choose…
创建成功,文件目录如图
在item.cpp中,添加有参构造的定义
因为后面我们需要用到棋子判断相等,所以我们需要在item.h中重写==
至此,棋子类定义完成。
2.3 在mainwindow.h中,声明一个绘制棋子的函数DrawItems,定义一个QVector来记录我们的落子,定义一个m_bIsBlackTun来记录当前落子的颜色,黑白之间切换。注:因为我们要使用棋子类及QVector,所以我们需要引入相应的头文件。
在mainwindow.cpp中添加棋子绘制的函数的定义,并初始化落子棋子颜色,及清空棋子
绘制棋子,因为我们每落一次棋子,就相当于把之前所有的棋子都重新绘制。
棋子绘制完成,但是我们如果要下棋,就得添加一个鼠标点击事件,每次点击就相当于落一次子。
在mainwindow.h中声明mousePressEvent(QMouseEvent*event)
接着在mainwindow.cpp中定义mousePressEvent。头部引入#include ,在paintEvent函数中添加棋子绘制并添加更新。
运行项目可以通过鼠标点击绘制棋子
五子棋判断输赢的方式当五个同颜色的棋子都在同一条直线并处于相邻位置时则取得胜利。
当我们一次落子,可以有四种情况可以取得胜利:落子的上方+下方至少有同色的四颗棋子,落子的左方+右方至少有同色的四颗棋子,落子的左上方+右下方至少有同色的四颗棋子,落子的右上方+左下方至少有同色的四颗棋子
首先我们在mainwindow.h中声明一个获取一个方向上的棋子数量intCountRoundItems(Item it, QPoint pt);并在mainwindow.cpp中定义
为了判断输赢,我们需要获取到当前落子的八个方向的棋子数量。在我们鼠标点击的时候就需要统计,如果我们要获取左边棋子的数量,就需要在当前的棋子的x坐标-1,y坐标不变,所以我们可以通过CountRoundItems(item,QPoint(-1,0))来获取左边同色棋子的数量。依次获取其他方向的棋子数量。
正如一开始所说,只需要判断四种情况就可以判断输赢。当某一方赢了之后,我们使用QMessageBox::information(this,“提示胜利”,strTip,QMessageBox::Yes);给一个获胜的提示,并清空m_items里的棋子,然后开始新的一局。注:记得引入QMessageBox。
运行效果:
本篇文章是我之前在微博里发布的一篇文章,现在抄录过来。
item.h
#ifndef ITEM_H
#define ITEM_H
#include
class Item
{
public:
Item();
Item(QPoint pt,bool bBlack);//棋子类的有参构造
QPoint m_pt;//棋子坐标
//重写==
bool operator ==(const Item &t1) const
{
return (m_bBlack == t1.m_bBlack && m_pt == t1.m_pt);
}
bool m_bBlack;//是黑方还是白方下棋
};
#endif // ITEM_H
item.cpp
#include "item.h"
Item::Item()
{
}
Item::Item(QPoint pt, bool bBlack)
{
m_pt = pt;
m_bBlack = bBlack;
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include "item.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void DrawChessBroad();//绘制棋盘
void DrawItems();//绘制棋子
QVector- m_items;//记录我们的落子
bool m_bIsBlackTun;//记录落子颜色
int CountRoundItems(Item it, QPoint pt);//获取一个方向上的棋子数量
void mousePressEvent(QMouseEvent *event);//鼠标点击落子
void paintEvent(QPaintEvent *event);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include
#include
//棋盘行和列
#define CHESS_ROWS 18
#define CHESS_COLUMES 18
//棋盘格的宽、高
#define RECT_WIDTH 25
#define RECT_HEIGHT 25
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//比18*25.5稍微大一些
resize(480,480);
m_bIsBlackTun = 0;//初始化落子颜色 0 为白色 1为黑色
m_items.clear();//清空我们的落子
}
void MainWindow::DrawChessBroad(){
//鼠标光标定位到QPainter,按F1查看帮助文档,找到drawRect函数
QPainter painter(this);
QPen pen;//画笔
pen.setColor(Qt::black);//定义画笔颜色
pen.setWidth(2);//设置画笔的宽度
QBrush brush(QColor(Qt::darkYellow));//画刷并设置颜色
painter.setPen(pen);//添加画笔
painter.setBrush(brush);//添加画刷
//因为我们要绘制18*18的棋盘,所以我们使用双重for循环来绘制18*18个棋盘格子
for(int j = 0;jpos().x();//获取鼠标点击的x坐标
int chess_y = event->pos().y();//获取鼠标点击的y坐标
pt.setX(chess_x/RECT_WIDTH);//设置棋子x坐标
pt.setY(chess_y/RECT_HEIGHT);//设置棋子y坐标
//循环所有棋子判断落子处是否存在棋子
for(int i = 0;i= 4)|| (Up+Down)>=4 || (LeftUp+RightDown)>=4||(RightUp + LeftDown>=4))
{
QString strTip = item.m_bBlack?"黑棋胜出!":"白棋胜出!";//判断当前落子的颜色给出相应的获胜提示
QMessageBox::information(this,"提示胜利",strTip,QMessageBox::Yes);
m_items.clear();//清空所有落子
return;
}
m_bIsBlackTun = !m_bIsBlackTun;//切换棋子颜色
}
void MainWindow::paintEvent(QPaintEvent *event)
{
//绘制棋盘
DrawChessBroad();
//绘制棋子
DrawItems();
//更新
update();
}
MainWindow::~MainWindow()
{
delete ui;
}