项目实战:Qt5/C++:QT象棋【初版】_偕臧x的博客-程序员宅基地

技术标签: 专栏 - 项目实战开发  Qt5  widget  学习 - Qt  象棋  

项目实战:Qt5/C++:QT象棋【初版】

==================================================================

===完整基于QT的跨平台网络对战中国象棋的项目完整版大更新  2019-04-13

===QT5/C++项目:基于QT的跨平台网络对战象棋(一)

===QT5/C++项目:基于QT的跨平台网络对战象棋(二)

===QT5/C++项目:基于QT的跨平台网络对战象棋(三)

==================================================================

编辑环境:win10_x64 /Qt5.4.1

项目:Qt 象棋

项目简介:一开始还在想,是准备使用Qt写一个IM即时通讯的,既可以增加自己对这个的方面的认知,也可以,但是想一想,时间也不是很多了,大三都快结束了,之前一个星期,写了一个象棋,计划是分成三个功能的:[1]人机对战(单人游戏); [2]双人模式(单PC端); [3]socket 网络双人游戏(多PC端)。而初始阶段,还只是完成了 [2]双人模式(单PC端)的功能,但是后面的功能是在这些基础上面,直接进行一些人工智能,电脑根据玩家的下法,通过指定的规则,来进行可能得算法,从而下一些可能是的的算法步骤。而最后的socket的双人PC端进行游戏,在现在现在基础上面加上Socket编程的类就可以了。

其他:后续还是会继续更新的,当有空的时候是会继续完善后面的功能的。

==================================================================

项目运行效果

==================================================================

==================================================================

项目思路分析:

==================================================================

步骤:

1.绘画棋盘

2.绘画棋子

3.棋盘行列值和屏幕之间的像素值之间进行切换

4.象棋轮流下

5.制定象棋的具体规则

6.屏幕重绘

==================================================================

项目主要源码部分:

==================================================================

//棋盘和象棋走法类

#ifndef BOARD_H
#define BOARD_H

#include <QWidget>
#include "Stone.h"
namespace Ui {
class Board;
}

class Board : public QWidget
{
    Q_OBJECT

public:
    explicit Board(QWidget *parent = 0);
    ~Board();

private:
    bool isDead(int id);
    int getStoneId(int row, int col);
    //车 炮 的功能辅助函数   判断两个点是否在一个直线上面,且返回直线之间的棋子个数
    int  getStoneCountAtLine(int row1, int col1, int row2, int col2);

public:
    //绘画棋盘
    virtual void paintEvent(QPaintEvent *);
    //象棋的棋盘的坐标转换成界面坐标
    QPoint center(int row, int col);
    QPoint center(int id);
    //绘画单个具体的棋子
    void drawStone(QPainter& painter, int id);


    //界面坐标转换成棋盘的行列值[获取鼠标点击的像素坐标,是位于棋盘的哪一个行列值]
    bool getRowCol(QPoint pt, int& row, int& col);
    //鼠标点击事件
    virtual void mousePressEvent(QMouseEvent *);

    //象棋移动的规则[将  士  象  马  车  炮  兵]
    bool canMove(int moveId, int killId, int row, int col);
    bool canMoveJIANG(int moveId, int killId, int row, int col);
    bool canMoveSHI(int moveId, int killId, int row, int col);
    bool canMoveXIANG(int moveId, int killId, int row, int col);
    bool canMoveMA(int moveId, int killId, int row, int col);
    bool canMoveCHE(int moveId, int killId, int row, int col);
    bool canMovePAO(int moveId, int killId, int row, int col);
    bool canMoveBING(int moveId, int killId, int row, int col);

public:
    Stone _stone[32];
    int _r;  //棋子半径
    int _offset;  //距离界面的边距
    int _d;  //间距为50px
    int _selectId;  //IS? 选中棋子[-1:选棋子 || 非-1:走棋子]
    int _clickId; //点击鼠标选中棋子的ID
    bool _bRedTrue;  //红棋先下标志

private:
    Ui::Board *ui;
};

#endif // BOARD_H

#include "Board.h"
#include "ui_Board.h"
#include <QPainter>
#include <QMouseEvent>

Board::Board(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Board)
{
    //初始化32个象棋
    for(int i = 0; i <= 31; i++)
    {
        _stone[i].initialize(i);
    }

    _selectId = -1;  //IS? 选中棋子[-1:选棋子 || 非-1:走棋子]
    _bRedTrue = true;
    ui->setupUi(this);
}

Board::~Board()
{
    delete ui;
}

int Board::getStoneId(int row, int col)
{
    for(int i=0; i<32; ++i)
    {
        if(_stone[i]._row == row && _stone[i]._col == col && !isDead(i))
            return i;
    }
    return -1;
}

bool Board::isDead(int id)
{
    if(id == -1)return true;
    return _stone[id]._deal;
}

int Board::getStoneCountAtLine(int row1, int col1, int row2, int col2)
{
    int ret = 0;
    if(row1 != row2 && col1 != col2)
        return -1;
    if(row1 == row2 && col1 == col2)
        return -1;

    if(row1 == row2)
    {
        int min  = col1 < col2 ? col1 : col2;
        int max = col1 < col2 ? col2 : col1;
        for(int col = min+1; col<max; ++col)
        {
            if(getStoneId(row1, col) != -1) ++ret;
        }
    }
    else
    {
        int min = row1 < row2 ? row1 : row2;
        int max = row1 < row2 ? row2 : row1;
        for(int row = min+1; row<max; ++row)
        {
            if(getStoneId(row, col1) != -1) ++ret;
        }
    }

    return ret;
}

//绘画棋盘
void Board::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    _offset = 60;  //距离界面的边距
    _d = 90; //间距为50px
    _r = _d/2;  //棋子半径为d/2

    //*******************绘画棋盘*******************
    //绘画10条横线
    for(int i = 0; i <= 9; i++)
    {
        painter.drawLine(QPoint(_offset, _offset+i*_d), QPoint(_offset+8*_d, _offset+i*_d));
    }

    //绘画9条竖线
    for(int i = 0; i <= 8; i++)
    {
        if(i==0 || i==8)
        {
            painter.drawLine(QPoint(_offset+i*_d, _offset), QPoint(_offset+i*_d, _offset+9*_d));
        }
        else
        {
            painter.drawLine(QPoint(_offset+i*_d, _offset), QPoint(_offset+i*_d, _offset+4*_d));
            painter.drawLine(QPoint(_offset+i*_d, _offset+5*_d), QPoint(_offset+i*_d, _offset+9*_d));
        }
    }

    //绘画4条斜线
    painter.drawLine(QPoint(_offset+3*_d, _offset), QPoint(_offset+5*_d, _offset+2*_d));
    painter.drawLine(QPoint(_offset+3*_d, _offset+2*_d), QPoint(_offset+5*_d, _offset));
    painter.drawLine(QPoint(_offset+3*_d, _offset+7*_d), QPoint(_offset+5*_d, _offset+9*_d));
    painter.drawLine(QPoint(_offset+3*_d, _offset+9*_d), QPoint(_offset+5*_d, _offset+7*_d));

    QRect rect1(_offset+_d,   _offset+4*_d, _d, _d);
    QRect rect2(_offset+2*_d, _offset+4*_d, _d, _d);
    QRect rect3(_offset+5*_d, _offset+4*_d, _d, _d);
    QRect rect4(_offset+6*_d, _offset+4*_d, _d, _d);
    painter.setFont(QFont("隶书", _r, 800));
    painter.drawText(rect1, "楚", QTextOption(Qt::AlignCenter));
    painter.drawText(rect2, "河", QTextOption(Qt::AlignCenter));
    painter.drawText(rect3, "汉", QTextOption(Qt::AlignCenter));
    painter.drawText(rect4, "界", QTextOption(Qt::AlignCenter));

    //*******************绘画棋子*******************
    for(int i = 0; i <= 31; i++)
    {
        drawStone(painter, i);
    }
}

//象棋的棋盘的坐标转换成界面坐标
QPoint Board::center(int row, int col)
{
    QPoint rePoint;
    //这里注意坐标的转换
    rePoint.rx() = col*_d+_offset;
    rePoint.ry() = row*_d+_offset;
    return rePoint;
}

//重载:坐标转换
QPoint Board::center(int id)
{
    return center(_stone[id]._row, _stone[id]._col);
}

//绘画单个具体的棋子
void Board::drawStone(QPainter &painter, int id)
{
    if(_stone[id]._deal)
        return;

    QPoint temp = center(id);
    QRect rect(temp.x()-_r, temp.y()-_r, _d, _d);

    if(_selectId == id)
        painter.setBrush(QBrush(QColor(64,64,196, 80)));
    else
        painter.setBrush(QBrush(QColor(64,64,196, 10)));

    painter.setPen(QColor(0, 0, 0));
    painter.drawEllipse(center(id), _r, _r);  //绘画圆形
    painter.setFont(QFont("华文行楷", _r, 700));

    if(id < 16)
        painter.setPen(QColor(255, 0, 0));
    else
        painter.setPen(QColor(0, 0, 0));

    painter.drawText(rect, _stone[id].getText(), QTextOption(Qt::AlignCenter));  //绘画圆形里面的汉字
}

//界面坐标转换成棋盘的行列值[获取鼠标点击的像素坐标,是位于棋盘的哪一个行列值]
bool Board::getRowCol(QPoint pt, int &row, int &col)
{
    for(row = 0; row <= 9; row++)
    {
        for(col = 0; col <= 8; col++)
        {
            QPoint temp = center(row, col);
            int x = temp.x()-pt.x();
            int y = temp.y()-pt.y();

            if(x*x+y*y < _r*_r)
                return true;
        }
    }
}

//鼠标点击事件
void Board::mousePressEvent(QMouseEvent *ev)
{
    QPoint pt = ev->pos();
    //将pt转化成棋盘的像行列值
    //判断这个行列值上面有没有棋子
    int row, col;

    //点击棋盘外面就不做处理
    if(!getRowCol(pt, row, col))
        return;

    _clickId = -1;
    int i;

    //判断是哪一个棋子被选中,根据ID(这里的局部i)来记录下来
    for(i = 0; i <= 31; i++)
    {
        if(_stone[i]._row == row && _stone[i]._col == col && _stone[i]._deal == false)
            break;
    }

    if(i < 32)
        _clickId = i;  //选中的棋子的ID

    if(_selectId == -1)//选中棋子
    {
        if(_clickId != -1)
        {
            if(_bRedTrue == _stone[_clickId]._red)
                _selectId = _clickId;
        }
    }
    else//走棋子
    {
        if(canMove(_selectId, _clickId, row, col ))
        {
            //_selectId为第一次点击选中的棋子,
            //_clickId为第二次点击||被杀的棋子ID,准备选中棋子下子的地方
            _stone[_selectId]._row = row;
            _stone[_selectId]._col = col;
            if(_clickId != -1)
                _stone[_clickId]._deal = true;

            _selectId = -1;
            _bRedTrue = !_bRedTrue;
        }

    }
    update();
}

//总的移动规则,选中准备下的棋子,被杀的棋子, 准备移动到的目的行列值
bool Board::canMove(int moveId, int killId, int row, int col)
{
    //1.确定是选择其它棋子还是走棋
    //2.是否需要使用到canMoveXXX()来做限制
    //3.罗列出所有情况,和需要的得到的结果值 ==>  然后进行中间的逻辑层判断※不要受到别人的代码框架的束缚※
        if(_stone[moveId]._red == _stone[killId]._red)  //选择其它棋子,返回false
        {
            if(killId == -1)  //其中有一个特殊情况,黑+_stone[-1]._red ==> 也需要判断能否
            {
                switch (_stone[moveId]._type)
                {
                case Stone::JIANG:
                    return canMoveJIANG(moveId, killId, row, col);
                case Stone::SHI:
                    return canMoveSHI(moveId, killId, row, col);
                case Stone::XIANG:
                    return canMoveXIANG(moveId, killId, row, col);
                case Stone::MA:
                    return canMoveMA(moveId, killId, row, col);
                case Stone::CHE:
                    return canMoveCHE(moveId, killId, row, col);
                case Stone::PAO:
                    return canMovePAO(moveId, killId, row, col);
                case Stone::BING:
                    return canMoveBING(moveId, killId, row, col);
                }

            }

            _selectId = killId;
            update();

            return false;
        }
        else  //选择其走棋,返回true
        {
            switch (_stone[moveId]._type)
            {
            case Stone::JIANG:
                return canMoveJIANG(moveId, killId, row, col);
            case Stone::SHI:
                return canMoveSHI(moveId, killId, row, col);
            case Stone::XIANG:
                return canMoveXIANG(moveId, killId, row, col);
            case Stone::MA:
                return canMoveMA(moveId, killId, row, col);
            case Stone::CHE:
                return canMoveCHE(moveId, killId, row, col);
            case Stone::PAO:
                return canMovePAO(moveId, killId, row, col);
            case Stone::BING:
                return canMoveBING(moveId, killId, row, col);
            }
            return true;
        }
}

bool Board::canMoveJIANG(int moveId, int killId, int row, int col)
{
    if(_stone[moveId]._red) //红 将
    {
        if(row > 2 || col < 3 || col > 5) return false;
    }
    else  //黑 将
    {
        if(row < 7 || col < 3 || col > 5) return false;
    }

    int dr = _stone[moveId]._row - row;
    int dc = _stone[moveId]._col - col;
    int d = abs(dr)*10 + abs(dc);
    if(d == 1 || d == 10)
        return true;

    return false;
}

bool Board::canMoveSHI(int moveId, int killId, int row, int col)
{
    if(_stone[moveId]._red) //红 士
    {
        if(row > 2 || col < 3 || col > 5) return false;
    }
    else  //黑 士
    {
        if(row < 7 || col < 3 || col > 5) return false;
    }

    int dr = _stone[moveId]._row - row;
    int dc = _stone[moveId]._col - col;
    int d = abs(dr)*10 + abs(dc);
    if(d == 11)
        return true;

    return false;
}

bool Board::canMoveXIANG(int moveId, int killId, int row, int col)
{
    if(_stone[moveId]._red) //红
    {
        if(row > 4) return false;
    }
    else  //黑
    {
        if(row < 5) return false;
    }

    int dr = _stone[moveId]._row - row;
    int dc = _stone[moveId]._col - col;
    int d = abs(dr)*10 + abs(dc);

    int dr2 = (_stone[moveId]._row + row)/2;
    int dc2 = (_stone[moveId]._col + col)/2;

    //象眼被堵,就不能够调,就会有i属于0~31,返回false
    int i = 0;
    for(i = 0; i <= 31; i++)
    {
        if(_stone[i]._row == dr2 && _stone[i]._col == dc2 && _stone[i]._deal == false)
            break;
    }

    if(0 <= i && i <= 31)
        return false;

    if(d == 22)
        return true;

    return false;
}

bool Board::canMoveMA(int moveId, int killId, int row, int col)
{
    int dr = _stone[moveId]._row - row;
    int dc = _stone[moveId]._col - col;
    int d = abs(dr)*10 + abs(dc);
    int dr2 = (_stone[moveId]._row + row)/2;
    int dc2 = (_stone[moveId]._col + col)/2;

    //蹩脚马
    if(abs(dr) == 2 && abs(dc)==1)
    {
        int i = 0;
        if(row < _stone[moveId]._row )
        {
            for(i = 0; i <= 31; i++)
            {
                if(_stone[i]._row == (_stone[moveId]._row-1) && _stone[i]._col == _stone[moveId]._col && _stone[i]._deal == false)
                    break;
            }
        }
        else
        {
            for(i = 0; i <= 31; i++)
            {
                if(_stone[i]._row == (_stone[moveId]._row+1) && _stone[i]._col == _stone[moveId]._col && _stone[i]._deal == false)
                    break;
            }
        }

        if(0 <= i && i <= 31)
            return false;
    }

    if(abs(dr) == 1 && abs(dc)==2)
    {
        int i = 0;
        if(col < _stone[moveId]._col)
        {

            for(i = 0; i <= 31; i++)
            {
                if(_stone[i]._row == _stone[moveId]._row && _stone[i]._col == (_stone[moveId]._col-1) && _stone[i]._deal == false)
                    break;
            }
        }
        else
        {
            for(i = 0; i <= 31; i++)
            {
                if(_stone[i]._row == _stone[moveId]._row && _stone[i]._col == (_stone[moveId]._col+1) && _stone[i]._deal == false)
                    break;
            }
        }

        if(0 <= i && i <= 31)
            return false;
    }

    if(d == 12 || d == 21)
        return true;

    return false;
}

bool Board::canMoveCHE(int moveId, int killId, int row, int col)
{  
    int ret = getStoneCountAtLine(_stone[moveId]._row, _stone[moveId]._col, row, col);
    if(ret == 0)
        return true;
    return false;
}

bool Board::canMovePAO(int moveId, int killId, int row, int col)
{
    int ret = getStoneCountAtLine(row, col, _stone[moveId]._row, _stone[moveId]._col);
    if(killId != -1)
    {
        if(ret == 1) return true;
    }
    else
    {
        if(ret == 0) return true;
    }
    return false;
}

bool Board::canMoveBING(int moveId, int killId, int row, int col)
{
    int dr = _stone[moveId]._row - row;
    int dc = _stone[moveId]._col - col;
    int d = abs(dr)*10 + abs(dc);
    if(d != 1 && d != 10) return false;

    if(_stone[moveId]._red) //红 兵
    {
        if(row <  _stone[moveId]._row) return false;
        if(_stone[moveId]._row == 3 || _stone[moveId]._row == 4)
        {
            if(col == _stone[moveId]._col && row == (_stone[moveId]._row+1))
                return true;
        }
        else
        {
            if((col == _stone[moveId]._col && row >= 5) || (row == _stone[moveId]._row && abs(col-_stone[moveId]._col)==1))
                    return true;
        }
        return false;
    }
    else  //黑 兵
    {
        if(row >  _stone[moveId]._row) return false;
        if(_stone[moveId]._row == 5 || _stone[moveId]._row == 6)
        {
            if(col == _stone[moveId]._col && row == (_stone[moveId]._row-1))
                return true;
        }
        else
        {
            if((col == _stone[moveId]._col && row <= 4) || (row == _stone[moveId]._row && abs(col-_stone[moveId]._col)==1))
                    return true;
        }
        return false;
    }
    return true;
}




 

//棋子类
class Stone
{
public:
    Stone();
    ~Stone();

public:
    QString getText();  //根据enum  TYPE得类型决定棋子上面的汉字
    void initialize(int id);  //32个棋子的初始化

public:
    enum TYPE{JIANG, SHI, XIANG, MA, CHE, PAO, BING };
    int _row;  //棋子在棋盘的行(不是界面的坐标)
    int _col;  //棋子在棋盘的列(不是界面的坐标)
    int _id;  //棋子的ID
    bool _deal;  //棋子是否死亡
    bool _red;  //棋子的颜色
    TYPE _type;  //棋子的类型
};

=================================================================

 

<br>

 本文初发于 "偕臧的小站" ifmet.cn,同步转载于此

<br>

==================================================================

链接:百度网盘 请输入提取码 密码:0o4l

==================================================================

完整基于QT的跨平台网络对战中国象棋的项目完整版大更新  2019-04-13

QT5/C++项目:基于QT的跨平台网络对战象棋(一)

QT5/C++项目:基于QT的跨平台网络对战象棋(二)

QT5/C++项目:基于QT的跨平台网络对战象棋(三)


==================================================================
源码下载

- GitHub: ChineseChess『荐』
Gitee: ChineseChess


你的 `star` 和 `fork` 是对我最大的支持。也欢迎学习这个系列的  QT/DTK 学习,附学习由浅入深的目录

打包体验程序,下载地址:releases

欢迎 star 和 fork 这个系列的 Qt / DTK 学习,附学习进阶的路线图。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_33154343/article/details/80931400

智能推荐

模型预处理均值、方差的理解与使用_onnx模型前处理,均值和方差_GeneralJing的博客-程序员宅基地

数据预处理常用的均值与方差如下:if 'coco' in args.dataset: mean_vals = [0.471, 0.448, 0.408] std_vals = [0.234, 0.239, 0.242]elif 'imagenet' in args.dataset: mean_vals = [0.485, 0.456, 0.406] std_vals = [0.229, 0.224, 0.225]对自定义数据集图像计算均值与方差:import

WordPress函数:add_action(添加动作)_GaiMingZhong的博客-程序员宅基地

说明将函数连接到指定action(动作)。在Plugin API/Action Reference 上查看动作hook列表。wordpress核心调用do_action() 时触发动作。用法1234&amp;lt;?php add_action( $tag, $function_to_add, $priority, $accepted_args );?&amp;gt;参数$tag...

amazeui字体大小_bangyanqiu5256的博客-程序员宅基地

.am-text-xs - 12px.am-text-sm - 14px.am-text-default - 16px.am-text-lg - 18px.am-text-xl - 24px.am-text-xxl - 32px.am-text-xxxl - 42px转载于:https://www.cnblogs.com/wanhao0102/p/50...

Android 自定义属性时TypedArray的使用方法_ihoudf的博客-程序员宅基地

有时候android传统的页面布局不足以满足我们的需求,常常需要自己定义view,通常继承View,然后重写构造方法以及onDraw等函数,再具体实现自己定义的复杂view。我们知道在给控件赋属性时,通常使用的是android系统自带的属性,比如 android:layout_height="wrap_content",除此之外,我们亦可以自己定义属性,这样在使用的时候我们就可以使用形如 mya...

解决VS2017安装一直卡在正在下载_vs2017安装卡住不动_程序员黄老师的博客-程序员宅基地

最近,很多同学在安装VS2017的时候是不是遇到以下情况呢?一直卡住不动呢?一直在提取,很恼火那么不用担心,直接找黄老师老师帮你解决就可以啦!可以直接加老师企鹅354974212或者直接看视频跟着老师安装吧!https://edu.csdn.net/course/detail/8641...

运输公司对用户计算运费.路程越远每公里运费越低.每公里每吨货物的基本运费p = 3;用户需要输入货物重量w和距离s;根据距离的不同折扣d不同(具体见)下面的表格,要求根据用户输入的w和s,计算出总运费_棒老师的博客-程序员宅基地

/*1.运输公司对用户计算运费.路程越远每公里运费越低.每公里每吨货物的基本运费p = 3;用户需要输入货物重量w和距离s;根据距离的不同折扣d不同(具体见)下面的表格,要求根据用户输入的w和s,计算出总运费f其计算公式为f=p*w*s*(1-d)。           s 250 500 100020003000*/#include

随便推点

SysTick滴答定时器延时函数(精确定时)_systick延时函数_梁山皮卡丘的博客-程序员宅基地

SysTick是什么SysTick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。SysTick定时器是系统滴答定时器,一个24位的倒计数定时器,计到0时,将从RELOAD寄存器中自动重装载定时器初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。SysTick定时器也可以做中断,也可以设置其中断的优先级,但是在这里只介绍它的延时功能。SysTick寄存器CTRL SysTick控制和状态寄存器LOAD

【网络教程】苹果MACCMS10怎样设置伪静态_苹果cms浏览模式非静态,无法生成_xiaoqiangclub的博客-程序员宅基地

文章目录规则说明宝塔面板设置原文链接规则说明在maccms10安装包里面其实就有伪静态规则说明说明所在地址 maccmas10/说明文档/伪静态规则这里是rewrite说明文件的内容1,确认空间支持rewrite组件。2,按照 伪静态rewrite 目录下的说明文档操作。3,后台设置浏览模式为 rewrite伪静态 。如果使用rewrite伪静态模式,请注意把配置文...

YT14-HDU-三分查找求F(x)的最小值_三分法求最小值 hdu_SAP 皮德憨的博客-程序员宅基地

Problem DescriptionNow, here is a fuction:  F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 Can you find the minimum value when x is between 0 and 100.InputThe first line of the input contains an in

视频编码学习(一)_视频编码亮度适应性_LuoYao_Yang的博客-程序员宅基地

兜兜转转,在文字矫正方向的失利以## 标题后,转向了视频编码。目前视频编码和卷积神经网络的结合还不是很多,后面就记录一下自己在视频编码中的学习。什么是视频编码?我们平时所接触到的视频,有的大有的小,但是很多情况下的视频都是非常大的,这对我们的传输造成了很大困扰。我们通过视频编码技术,能够让我们的传输更加方便。冗余在我们的视觉系统中,当一张图片有一些轻微的损耗时,我们用肉眼是观察不到相应的变...

Listener的使用(监听用户session的开始和结束,HttpSession范围内属性的改变)_httpsession属性变更_千秋大业一壶茶的博客-程序员宅基地

HttpSessionListener用于监听用户session的创建和销毁,实现该接口的监听器需要实现sessionCreated和sessionDestroyed方法    HttpSessionAttributeListener用于监听HttpSession范围内属性的变化,需实现attributeAdded、attributeRemoved、attributeReplaced三个方法,

QT 进度条类 QProgressDialog的简单使用_之乎者也哦的博客-程序员宅基地

一、The QProgressDialog class provides feedback on the progress of a slow operation. QProgressDialog 类对于比较慢的处理进程提供了一种反馈,使得我们在进行操作的时候能够看到处理的进度。例如:二、打开Qt,新建项目,名称为new4,选择Widget,这里不用Mainwindow,ui设计很简单...

推荐文章

热门文章

相关标签