热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Qt学习笔记(5)绘图五子棋游戏

在上一篇博客CQt学习笔记(4)绘图中介绍了Qt中的绘图方法,基于上一篇的博客的知识,使用QPainter设计一个五子棋的棋

          在上一篇博客C++ Qt学习笔记(4)绘图中介绍了Qt中的绘图方法,基于上一篇的博客的知识,使用QPainter设计一个五子棋的棋盘,后续会完成五子棋的游戏设计。

 1. 棋盘的设计

首先需要绘制棋盘的界面,这里采用的方法是,首先需要设定棋盘的大小,定义BOARD_WIDTH,以及BOARD_HEIGHT表示棋盘的大小,CELL_SIZE表示棋盘中每个格子的大小,单位为像素。START_POS表示棋盘中第一个方格左上角的坐标。WIDGET_SIZE设定绘图设备的大小,也即Widget窗口的初始大小。

然后通过:

setFixedSize(WIDGET_SIZE);

设置绘图设备为固定大小。

ROW_NUM_START, COLUMN_NUM_START表示绘制放个上的数字的起始位置,具体的值可以根据绘制的效果进行调节。

BOARD_WIDTH = 15;             // 表示有十五个格子

BOARD_HEIGHT = 15;

CELL_SIZE = (25,25);

START_POS = (40, 40)

ROW_NUM_START = (15, 45)

COLUMN_NUM_START = (39, 25)

绘制棋盘的代码如下所示:

void Widget::paintEvent(QPaintEvent *event)
{QPainter painter(this); // this代表Widget,及绘图设备painter.setRenderHint(QPainter::Antialiasing); // 绘画普通图形启用反走样, 即开启抗锯齿painter.setRenderHint(QPainter::TextAntialiasing); // 绘画文字反走样, 即开启抗锯齿int width = this->width(); // 获取绘图区域的大小int height = this->height();painter.fillRect(this->rect(), Qt::gray); //填充背景颜色// 设置字体QFont font;font.setPointSize(10);font.setBold(true);painter.setFont(font);// 设置画笔QPen pen;pen.setWidth(2); // 设置线宽pen.setColor(Qt::black); // 设置颜色pen.setStyle(Qt::SolidLine); // 设置线型pen.setCapStyle(Qt::FlatCap);pen.setJoinStyle(Qt::BevelJoin);painter.setPen(pen);for(int i=0; i

在绘制完棋盘之后,需要在棋盘上绘制一个落子提示的图标,随着鼠标的移动而提示落子的位置,这里需要使用到鼠标事件,

MouseMoveEvent()来实时获取鼠标的移动位置:
获取坐标以及计算落子位置的方法如下:
1. 获取鼠标在绘图设备中的实际位置:
2. 计算当前位置在棋盘中的坐标,将棋盘的起点START_POS看为(0,0)点

3. 得到鼠标在棋盘中的坐标

4. 给坐标加上一个半个方格大小的偏置量,此时相当于提示符号的位置从方格左上角偏移到十字交叉的位置。

5.判断鼠标的坐标是否在合理的范围之内。

void Widget::mouseMoveEvent(QMouseEvent *event) // 鼠标事件
{QPoint pos &#61; event->pos() - START_POS; // 相对于棋盘起始位置的坐标QPoint temp_point &#61; pos &#43; QPoint(CELL_SIZE.width()/2, CELL_SIZE.height()/2); // 坐标int x &#61; temp_point.x();int y &#61; temp_point.y();// 检测此时坐标的范围是否合理// if(x <&#61; START_POS.x() || y <&#61; START_POS.y() || x >&#61; BOARD_WIDTH*CELL_SIZE.width()-START_POS.x() || y >&#61; BOARD_HEIGHT*CELL_SIZE.height() - START_POS.y())if(x <&#61; 0 || y <&#61; 0 || x >&#61; BOARD_WIDTH*CELL_SIZE.width() || y >&#61; BOARD_HEIGHT*CELL_SIZE.height()){return;}int offset_x &#61; x % CELL_SIZE.width(); // 这个坐标表示不够一个cell_size的坐标的大小int offset_y &#61; y % CELL_SIZE.height();QPoint tip_position &#61; QPoint(x-offset_x, y-offset_y)&#43;START_POS-QPoint(CELL_SIZE.width()/2, CELL_SIZE.height()/2)&#43;QPoint(8, 8);setTrackPos(tip_position);
}

定义一个点trackPos来保存鼠标实时变化的坐标,在构造函数中&#xff0c;需要设置开启MouseTracking:

// 构造函数
Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget), trackPos(28, 28)
{setFixedSize(WIDGET_SIZE); // 设置窗口为固定大小setMouseTracking(true); // 开启MouseTrackingui->setupUi(this);
}

setTrackPos()方法用于更新窗口部件&#xff1a;

void Widget::setTrackPos(QPoint point)
{trackPos &#61; point;update(); // update的作用是更新窗口部件
}

当窗口部件更新后&#xff0c;就会重新绘制棋盘。

绘制落子提示位置的图标&#xff0c;在上述的MouseMoveEvent中已经获取到了绘制的坐标位置&#xff0c;接下来需要定义几个点&#xff0c;连接成图标&#xff1a;

painter.setPen(Qt::red);QPoint poses[12] &#61; {trackPos &#43; QPoint(0, 8),trackPos,trackPos &#43; QPoint(8, 0),trackPos &#43; QPoint(17, 0),trackPos &#43; QPoint(25, 0),trackPos &#43; QPoint(25, 8),trackPos &#43; QPoint(25, 17),trackPos &#43; QPoint(25, 25),trackPos &#43; QPoint(17, 25),trackPos &#43; QPoint(8, 25),trackPos &#43; QPoint(0, 25),trackPos &#43; QPoint(0, 17)};painter.drawPolyline(poses, 3); // poses相当于指针painter.drawPolyline(poses&#43;3, 3); // 从poses&#43;3的点开始&#xff0c;将三个点连成一条线painter.drawPolyline(poses&#43;6, 3);painter.drawPolyline(poses&#43;9, 3);

绘制后的棋盘效果如下所示&#xff1a;

其中红色部分表示落子的提示标记&#xff0c;会随着鼠标的移动而变动位置。

单机鼠标下棋&#xff1a;

单击鼠标下棋的操作需要使用鼠标事件完成&#xff0c;MouseReleasedEvent(),在鼠标送开始&#xff0c;将棋子放到棋盘相应的位置&#xff1a;

首先&#xff0c;用一个二维的数组表示棋盘相应位置的落子情况&#xff0c;board[ i][ j]

1表示白色玩家

2表示黑色玩家

首先在开始棋局之前&#xff0c;需要随棋盘进行初始化操作&#xff0c;初始化的流程如下所示&#xff1a;

需要定义一些棋局中常用的状态量&#xff1a;

// 定义变量QPoint trackPos; // 记录鼠标的位置bool endGame; // 标志游戏是否结束bool WHITE_PALYER; // 白色玩家bool BLACK_PLAYER;bool next_player; // 下一位玩家static const int NO_PIECE &#61; 0; // 用于标记棋盘中某个位置没有棋子// 定义玩家static const int WHITE_PIECE &#61; 1; // 白棋static const int BLACK_PIECE &#61; 2; // 黑棋

初始化的过程如下所示&#xff0c;这里添加了随即决定开局的是白棋还是黑棋的部分&#xff1a;

void Widget::initBoard()
{// 对棋盘进行初始化for(int i&#61;0; i u(0, 1);e.seed(10); // 设置随机数种子double rand_number &#61; e(); // 生成随机数if(rand_number > 0.5){// 白棋先落子WHITE_PALYER &#61; true;BLACK_PLAYER &#61; false;next_player &#61; WHITE_PALYER;}else{// 黑棋先落子WHITE_PALYER &#61; false;BLACK_PLAYER &#61; true;next_player &#61; BLACK_PLAYER;}}

在游戏的过程中&#xff0c;每次都是通过鼠标点击棋盘的某一位置&#xff0c;实现棋子的落下&#xff0c;所以需要是实现鼠标事件MouseReleasedEvent();

在MouseReleasedEvent()事件函数中&#xff0c;首先获取到鼠标按下时的坐标&#xff0c;其次&#xff0c;就是在鼠标所按下的坐标处绘制相应的棋子&#xff0c;MouseReleasedEvent()的实现如下所示&#xff1a;

void Widget::mouseReleaseEvent(QMouseEvent *event)
{if(!endGame) // 游戏未结束{QPoint pos &#61; event->pos() - START_POS;int x &#61; pos.x();int y &#61; pos.y();int x_pos &#61; x / CELL_SIZE.width(); // 整数&#xff0c;确定第几个格子int y_pos &#61; y / CELL_SIZE.height();int x_offset &#61; x % CELL_SIZE.width(); // 余数&#xff0c;计算是否需要偏移int y_offset &#61; y % CELL_SIZE.height();if(x_offset > CELL_SIZE.width()/2){x_pos&#43;&#43;;}if(y_offset > CELL_SIZE.height()/2){y_pos&#43;&#43;;}dropPiece(x_pos, y_pos); //落子}}

这里的dropPiece就是表示在对应的位置(x,y)处绘制棋子&#xff0c;具体的实现过程为&#xff1a;

void Widget::dropPiece(int x, int y)
{if(x>&#61;0 && x<&#61;BOARD_WIDTH && y>&#61;0 && y<&#61;BOARD_HEIGHT && board[x][y]&#61;&#61;NO_PIECE){if(next_player &#61;&#61; WHITE_PALYER){board[x][y] &#61; WHITE_PIECE; // 当前位置是白棋}else{board[x][y] &#61; BLACK_PIECE; // 当前位置是黑棋}// 切换落子的玩家next_player &#61; !next_player;// 判断输赢checkWinner();update(); // 更新窗口组件}}

在落子之后&#xff0c;还需要判断此时的输赢情况&#xff0c;这里使用checkWinner()实现&#xff1a;

bool Widget::isHFivePiece(int x, int y)
{// 判断水平方向int piece &#61; board[x][y]; // 当前棋子的值for(int i&#61;1; i<5; i&#43;&#43;){if(x&#43;i>BOARD_WIDTH || board[x&#43;i][y]!&#61;piece){return false;}}return true;
}bool Widget::isVFivePiece(int x, int y)
{// 判断垂直方向int piece &#61; board[x][y];for(int i&#61;1; i<5; i&#43;&#43;){if(y&#43;i>BOARD_HEIGHT || board[x][y&#43;i]!&#61;piece){return false;}}return true;
}bool Widget::isLeftSlash(int x, int y)
{// 沿着左对角线int piece &#61; board[x][y];for(int i&#61;1; i<5; i&#43;&#43;){if(x&#43;i>BOARD_WIDTH || y&#43;i>BOARD_HEIGHT || board[x&#43;i][y&#43;i]!&#61;piece){return false;}}return true;
}bool Widget::isRightSlash(int x, int y)
{// 沿着右对角线int piece &#61; board[x][y];for(int i&#61;1; i<5; i&#43;&#43;){if(x-i<0 || y&#43;i>BOARD_HEIGHT || board[x-i][y&#43;i]!&#61;piece){return false;}}return true;
}bool Widget::isFivePiece(int x, int y)
{// 是否赢棋return isHFivePiece(x, y) || isVFivePiece(x, y) || isLeftSlash(x, y) || isRightSlash(x, y);
}void Widget::checkWinner()
{bool fullPieces &#61; true; // 和棋for(int i&#61;0; i}

最后&#xff0c;在执行update()之后&#xff0c;需要在QPainterEvent()中再次绘制新添加的棋子&#xff0c;实际上是将棋盘重新刷新依次&#xff0c;添加新的棋子&#xff1a;
 

// 绘制棋子painter.setPen(Qt::NoPen);// 查看棋盘的状态for(int i&#61;0; i

最终的效果如下图所示&#xff1a;

1. 现在需要对代码进行一下整合&#xff0c;第一步是实现五子棋界面的部分&#xff0c;创建一个基于QWidget类的类BoardWidget来表示棋盘&#xff0c;以及在下棋过程中的具体操作&#xff0c;这里不需要创建.ui文件&#xff1a;

boardwidget.h文件的实现&#xff1a;包含棋盘基本功能的实现&#xff0c;如棋盘绘制&#xff0c;落子位置跟踪&#xff0c;鼠标事件实现落子&#xff0c;判断棋局输赢等功能&#xff0c;都在BoardWidget类中实现&#xff1a;

#ifndef BOARDWIDGET_H
#define BOARDWIDGET_H#include class BoardWidget : public QWidget
{Q_OBJECT
public:explicit BoardWidget(QWidget *parent &#61; 0);~BoardWidget();signals:void game_over(int winner); // 游戏结束的信号public slots:protected:void paintEvent(QPaintEvent* event);void mouseMoveEvent(QMouseEvent* event);void mouseReleaseEvent(QMouseEvent* event);public:void initBoard();
private:void setTrackPos(QPoint point); // 追踪鼠标位置void dropPiece(int x, int y); // 落子// 判断输赢bool isFivePiece(int x, int y);bool isVFivePiece(int x, int y); // 从(x,y)开始&#xff0c;沿着垂直方向bool isHFivePiece(int x, int y); // 从(x,y)开始&#xff0c;沿着水平方向bool isLeftSlash(int x, int y); // 从(x,y)开始&#xff0c;沿着左对角线bool isRightSlash(int x, int y); // 从(x,y)开始&#xff0c;沿着右对角线void checkWinner();// 定义变量QPoint trackPos; // 记录鼠标的位置bool endGame; // 标志游戏是否结束bool WHITE_PALYER; // 白色玩家bool BLACK_PLAYER;bool next_player; // 下一位玩家public:// 棋盘的大小15x15static const int BOARD_WIDTH &#61; 15;static const int BOARD_HEIGHT &#61; 15;int board[BOARD_WIDTH][BOARD_HEIGHT]; // 定义棋盘//棋盘起始的的位置 行和列static const QPoint ROW_NUM_START;static const QPoint COLUMN_NUM_START;// sizestatic const QSize WIDGET_SIZE;static const QSize CELL_SIZE;static const QPoint START_POS;static const int NO_PIECE &#61; 0; // 用于标记棋盘中某个位置没有棋子// 定义玩家static const int WHITE_PIECE &#61; 1; // 白棋static const int BLACK_PIECE &#61; 2; // 黑棋};#endif // BOARDWIDGET_H

boardwidget.cpp

#include "boardwidget.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include // 初始化参数
// 1. 棋盘的起始位置&#xff1a;
const QPoint BoardWidget::ROW_NUM_START(15, 45);
const QPoint BoardWidget::COLUMN_NUM_START(35, 25);// 2.size初始化
const QSize BoardWidget::WIDGET_SIZE(830, 830);
const QSize BoardWidget::CELL_SIZE(45, 45);const QPoint BoardWidget::START_POS(40, 40);BoardWidget::BoardWidget(QWidget *parent) : QWidget(parent), trackPos(28, 28)
{setFixedSize(WIDGET_SIZE); // 设置窗口为固定大小setMouseTracking(true); // 开启MouseTrackinginitBoard(); // 初始化棋盘
}BoardWidget::~BoardWidget()
{}void BoardWidget::paintEvent(QPaintEvent *event)
{QPainter painter(this); // this代表Widget&#xff0c;及绘图设备painter.setRenderHint(QPainter::Antialiasing); // 绘画普通图形启用反走样, 即开启抗锯齿painter.setRenderHint(QPainter::TextAntialiasing); // 绘画文字反走样&#xff0c; 即开启抗锯齿int width &#61; this->width(); // 获取绘图区域的大小int height &#61; this->height();painter.fillRect(this->rect(), Qt::gray); //填充背景颜色// 设置字体QFont font;font.setPointSize(10);font.setBold(true);painter.setFont(font);// 设置画笔QPen pen;pen.setWidth(2); // 设置线宽pen.setColor(Qt::black); // 设置颜色pen.setStyle(Qt::SolidLine); // 设置线型pen.setCapStyle(Qt::FlatCap);pen.setJoinStyle(Qt::BevelJoin);painter.setPen(pen);for(int i&#61;0; i{QPoint pos &#61; event->pos() - START_POS; // 相对于棋盘起始位置的坐标QPoint temp_point &#61; pos &#43; QPoint(CELL_SIZE.width()/2, CELL_SIZE.height()/2); // 坐标int x &#61; temp_point.x();int y &#61; temp_point.y();// 检测此时坐标的范围是否合理// if(x <&#61; START_POS.x() || y <&#61; START_POS.y() || x >&#61; BOARD_WIDTH*CELL_SIZE.width()-START_POS.x() || y >&#61; BOARD_HEIGHT*CELL_SIZE.height() - START_POS.y())if(x <&#61; 0 || y <&#61; 0 || x >&#61; BOARD_WIDTH*CELL_SIZE.width() || y >&#61; BOARD_HEIGHT*CELL_SIZE.height()){return;}int offset_x &#61; x % CELL_SIZE.width(); // 这个坐标表示不够一个cell_size的坐标的大小int offset_y &#61; y % CELL_SIZE.height();// 绘制的图标的位置&#xff0c;中心的为十字交叉的位置QPoint tip_position &#61; QPoint(x-offset_x, y-offset_y)&#43;START_POS-QPoint(CELL_SIZE.width()/2, CELL_SIZE.height()/2)&#43;QPoint(8, 8);setTrackPos(tip_position);}void BoardWidget::mouseReleaseEvent(QMouseEvent *event)
{if(!endGame) // 游戏未结束{QPoint pos &#61; event->pos() - START_POS;int x &#61; pos.x();int y &#61; pos.y();int x_pos &#61; x / CELL_SIZE.width(); // 整数&#xff0c;确定第几个格子int y_pos &#61; y / CELL_SIZE.height();int x_offset &#61; x % CELL_SIZE.width(); // 余数&#xff0c;计算是否需要偏移int y_offset &#61; y % CELL_SIZE.height();if(x_offset > CELL_SIZE.width()/2){x_pos&#43;&#43;;}if(y_offset > CELL_SIZE.height()/2){y_pos&#43;&#43;;}dropPiece(x_pos, y_pos); //落子}}void BoardWidget::initBoard()
{// 对棋盘进行初始化for(int i&#61;0; i u(0, 1);e.seed(10); // 设置随机数种子double rand_number &#61; e(); // 生成随机数if(rand_number > 0.5){// 白棋先落子WHITE_PALYER &#61; true;BLACK_PLAYER &#61; false;next_player &#61; WHITE_PALYER;}else{// 黑棋先落子WHITE_PALYER &#61; false;BLACK_PLAYER &#61; true;next_player &#61; BLACK_PLAYER;}update();}void BoardWidget::setTrackPos(QPoint point)
{trackPos &#61; point;update(); // update的作用是更新窗口部件
}void BoardWidget::dropPiece(int x, int y)
{if(x>&#61;0 && x<&#61;BOARD_WIDTH && y>&#61;0 && y<&#61;BOARD_HEIGHT && board[x][y]&#61;&#61;NO_PIECE){if(next_player &#61;&#61; WHITE_PALYER){board[x][y] &#61; WHITE_PIECE; // 当前位置是白棋}else{board[x][y] &#61; BLACK_PIECE; // 当前位置是黑棋}// 切换落子的玩家next_player &#61; !next_player;// 判断输赢checkWinner();update(); // 更新窗口组件}}bool BoardWidget::isHFivePiece(int x, int y)
{// 判断水平方向int piece &#61; board[x][y]; // 当前棋子的值for(int i&#61;1; i<5; i&#43;&#43;){if(x&#43;i>BOARD_WIDTH || board[x&#43;i][y]!&#61;piece){return false;}}return true;
}bool BoardWidget::isVFivePiece(int x, int y)
{// 判断垂直方向int piece &#61; board[x][y];for(int i&#61;1; i<5; i&#43;&#43;){if(y&#43;i>BOARD_HEIGHT || board[x][y&#43;i]!&#61;piece){return false;}}return true;
}bool BoardWidget::isLeftSlash(int x, int y)
{// 沿着左对角线int piece &#61; board[x][y];for(int i&#61;1; i<5; i&#43;&#43;){if(x&#43;i>BOARD_WIDTH || y&#43;i>BOARD_HEIGHT || board[x&#43;i][y&#43;i]!&#61;piece){return false;}}return true;
}bool BoardWidget::isRightSlash(int x, int y)
{// 沿着右对角线int piece &#61; board[x][y];for(int i&#61;1; i<5; i&#43;&#43;){if(x-i<0 || y&#43;i>BOARD_HEIGHT || board[x-i][y&#43;i]!&#61;piece){return false;}}return true;
}bool BoardWidget::isFivePiece(int x, int y)
{// 是否赢棋return isHFivePiece(x, y) || isVFivePiece(x, y) || isLeftSlash(x, y) || isRightSlash(x, y);
}void BoardWidget::checkWinner()
{bool fullPieces &#61; true; // 和棋for(int i&#61;0; i}

在设计完成BoardWidget类的设计后&#xff0c;需要设计一个游戏的界面&#xff0c;这个界面的作用是可以将棋盘&#xff0c;以及其他的一些功能性的按钮添加到上面&#xff0c;形成一个面向用户的游戏界面。将这个类命名为GameWidget类&#xff1a;

gamewidget.h文件&#xff1a;

#ifndef GAMEWIDGET_H
#define GAMEWIDGET_H#include
#include "boardwidget.h"class GameWidget : public QWidget
{Q_OBJECTpublic:GameWidget(QWidget *parent &#61; 0);~GameWidget();private:BoardWidget* board;private slots:void restart_game();public slots:void showWinner(int winner);};#endif // GAMEWIDGET_H

在gamewidget中&#xff0c;需要对棋盘以及按钮的位置进行布局&#xff0c;所以需要用到布局管理器&#xff0c;在界面中添加一个重新开始游戏的按钮&#xff0c;在这个按钮按下的时候&#xff0c;需要调用棋盘的初始化函数&#xff0c;将整个棋盘清空&#xff0c;同时&#xff0c;在判断为玩家赢棋之后&#xff0c;需要弹出一个模态对话框&#xff0c;进行提示&#xff1a;

#include "gamewidget.h"
#include
#include
#include
#include
#include
#include GameWidget::GameWidget(QWidget *parent): QWidget(parent)
{setWindowTitle("Gomoku game"); // 设置窗口标题&#xff1a;QVBoxLayout* mainLayout &#61; new QVBoxLayout(this); // 布局管理器 垂直board &#61; new BoardWidget(this); // 新建棋盘对象QHBoxLayout* horizon_layout &#61; new QHBoxLayout(this); // 水平布局管理器QPushButton* btn_new_game &#61; new QPushButton("Resart"); // 按钮&#xff0c;开始新游戏horizon_layout->addWidget(btn_new_game);horizon_layout->addStretch();mainLayout->addLayout(horizon_layout);mainLayout->addWidget(board);connect(btn_new_game, SIGNAL(clicked()), this, SLOT(restart_game()));// 将当前的按钮与当前页面的resart_game()槽函数连接&#xff0c;在槽函数中调用initBoard()connect(board, SIGNAL(game_over(int)), this, SLOT(showWinner(int)));// 这种连接方式才能保证信号与槽连接正确, 不同对象之间信号与槽连接传递消息
}GameWidget::~GameWidget()
{}void GameWidget::showWinner(int winner)
{QString playerName;if(winner&#61;&#61;BoardWidget::WHITE_PIECE){playerName &#61; "White Winner";// qDebug() <<"Winner is 1" <}void GameWidget::restart_game()
{qDebug() <<"Restart the game" <initBoard();
}

main.cpp文件&#xff1a;

#include "gamewidget.h"
#include int main(int argc, char *argv[])
{QApplication a(argc, argv);GameWidget w;w.show();return a.exec();
}

整个项目的目录如下所示&#xff1a;

需要在项目中的.pro文件中添加&#xff1a;

QMAKE_CXXFLAGS &#43;&#61; -std&#61;c&#43;&#43;11

使得Qt项目能够支持C&#43;&#43;11.

程序运行后的效果&#xff1a;

 

 

-----------------------------------------------------------------------------------------------------------------------------------------

由于刚开始学习Qt,对教材上好多的地方理解不到位&#xff0c;后续会不断完善五子棋程序。


推荐阅读
  • iOS绘制就是采集点,贝塞尔曲线得到形状,绘图上下文去渲染出来AsanaDrawsana图形库,设计的挺好他可以画多种图形, ... [详细]
  • 本文探讨了在Java中如何正确地将多个不同的数组插入到ArrayList中,避免所有数组在插入后变得相同的问题。我们将分析代码中的问题,并提供解决方案。 ... [详细]
  • 本文探讨了如何在Classic ASP中实现与PHP的hash_hmac('SHA256', $message, pack('H*', $secret))函数等效的哈希生成方法。通过分析不同实现方式及其产生的差异,提供了一种使用Microsoft .NET Framework的解决方案。 ... [详细]
  • addcslashes—以C语言风格使用反斜线转义字符串中的字符addslashes—使用反斜线引用字符串bin2hex—函数把包含数据的二进制字符串转换为十六进制值chop—rt ... [详细]
  • nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • Java多线程实现:从1到100分段求和并汇总结果
    本文介绍如何使用Java编写一个程序,通过10个线程分别计算不同区间的和,并最终汇总所有线程的结果。每个线程负责计算一段连续的整数之和,最后将所有线程的结果相加。 ... [详细]
  • 深入理解Java多线程并发处理:基础与实践
    本文探讨了Java中的多线程并发处理机制,从基本概念到实际应用,帮助读者全面理解并掌握多线程编程技巧。通过实例解析和理论阐述,确保初学者也能轻松入门。 ... [详细]
  • 本文介绍了在T-SQL中如何有效地进行字符串分割以及如何将多行字符串合并为单行的方法,提供了具体的函数实现和示例。 ... [详细]
  • Android 自定义指南针视图实现
    本文介绍了如何在Android应用中自定义绘制指南针视图,包括方位角的计算、不同方向的颜色区分以及视图随手势移动的功能实现。 ... [详细]
  • 深入理解ThinkPHP5.1自定义标签的应用与实现
    本文详细探讨了ThinkPHP5.1框架中自定义标签的创建与使用方法,包括标签库的建立、模板配置以及在实际项目中的应用技巧。 ... [详细]
  • 当前,许多屏幕截图应用程序支持任意形状的截图功能。这引发了一个技术问题:如何高效地判断一个像素点是否位于指定的曲线或形状内部?本文将深入探讨这一问题,并提供一种简洁有效的解决方案。 ... [详细]
  • 本文详细探讨了RippleEffect的实现细节,包括其背后的绘图逻辑和动画控制机制,旨在帮助开发者更好地理解和应用这一视觉效果。 ... [详细]
author-avatar
顽童0006_648
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有