Qt 项目实战 | 俄罗斯方块

news2025/4/18 16:10:01

Qt 项目实战 | 俄罗斯方块

  • Qt 项目实战 | 俄罗斯方块
    • 游戏架构
    • 实现游戏逻辑
      • 游戏流程
      • 实现基本游戏功能
        • 设计小方块
        • 设计方块组
        • 添加游戏场景
        • 添加主函数
      • 测试
        • 踩坑点1:rotate 失效
        • 踩坑点2:items 方法报错
        • 踩坑点3:setCodecForTr 失效
        • 踩坑点4:不要在中文路径下运行 Qt 项目
        • 踩坑点5:multiple definition of `qMain(int, char**)'
        • 测试效果

官方博客:https://www.yafeilinux.com/

Qt开源社区:https://www.qter.org/

参考书:《Qt 及 Qt Quick 开发实战精解》

Qt 项目实战 | 俄罗斯方块

开发环境:Qt Creator 4.6.2 Based on Qt 5.9.6

在这里插入图片描述

游戏架构

本项目由三个类构成:

  • OneBox 类:继承自 QGraphicsObject 类。表示小正方形,可以使用信号与槽机制和属性动画。
  • BoxGroup 类:继承自 QObject 类和 QGraphicsItemGroup 类。表示游戏中的方块图形,可以使用信号与槽机制,实现了方块图形的创建、移动和碰撞检测。
  • MyView 类:实现了游戏场景。

游戏场景示意图:

在这里插入图片描述

实现游戏逻辑

游戏流程

游戏流程图:

在这里插入图片描述

七种方块图形:

在这里插入图片描述

方块组移动和旋转:

在这里插入图片描述

  • 碰撞检测:对每一个小方块都使用函数来获取与它们碰撞的图形项的数目,如果数目大于 1,说明已经发生了碰撞。
  • 游戏结束:当一个新的方块组出现时,就立即对它进行碰撞检测,如果发现了碰撞,说明游戏结束,这时由方块组发射游戏结束信号。
  • 消除满行:游戏开始后,每当出现新的方块前,都判断游戏移动区域的每一行是否已经拥有了满行的小方块。若满行,则销毁该行的所有小方块,然后让该行上面的方块都下移一格。

实现基本游戏功能

新建空的 Qt 项目,项目名 myGame。

myGame.pro 中新增代码:

QT += widgets

TARGET = myGame

这也是个踩坑点,在这里提前说了。

添加资源文件,名称为 myImages,添加图片:

在这里插入图片描述

设计小方块

新建 mybox.h,添加 OneBox 类的定义:

#ifndef MYBOX_H
#define MYBOX_H

#include <QGraphicsItemGroup>
#include <QGraphicsObject>

// 小方块类
class OneBox : public QGraphicsObject
{
private:
    QColor brushColor;

public:
    OneBox(const QColor& color = Qt::red);
    QRectF boundingRect() const;
    void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget);
    QPainterPath shape() const;
};

#endif  // MYBOX_H

新建 mybox.cpp,添加 OneBox 类的实现代码:

#include "mybox.h"

#include <QPainter>

OneBox::OneBox(const QColor& color) { brushColor = color; }

QRectF OneBox::boundingRect() const
{
    qreal penWidth = 1;
    return QRectF(-10 - penWidth / 2, -10 - penWidth / 2, 20 + penWidth, 20 + penWidth);
}

void OneBox::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    // 为小方块使用贴图
    painter->drawPixmap(-10, -10, 20, 20, QPixmap(":/images/box.gif"));
    painter->setBrush(brushColor);

    QColor penColor = brushColor;
    // 将颜色的透明度降低
    penColor.setAlpha(20);
    painter->setPen(penColor);
    painter->drawRect(-10, -10, 20, 20);
}

QPainterPath OneBox::shape() const
{
    QPainterPath path;
    // 形状比边框矩形小 0.5 像素,这样方块组中的小方块才不会发生碰撞
    path.addRect(-9.5, -9.5, 19, 19);
    return path;
}
设计方块组

在 mybox.h 中添加头文件:

#include <QGraphicsItemGroup>

再添加 BoxGroup 类的定义:

// 方块组类
class BoxGroup : public QObject, public QGraphicsItemGroup
{
    Q_OBJECT
private:
    BoxShape currentShape;
    QTransform oldTransform;
    QTimer* timer;

protected:
    void keyPressEvent(QKeyEvent* event);

public:
    enum BoxShape
    {
        IShape,
        JShape,
        LShape,
        OShape,
        SShape,
        TShape,
        ZShape,
        RandomShape
    };

    BoxGroup();
    QRectF boundingRect() const;

    bool isColliding();
    void createBox(const QPointF& point = QPointF(0, 0), BoxShape shape = RandomShape);
    void clearBoxGroup(bool destroyBox = false);
    BoxShape getCurrentShape() { return currentShape; }

signals:
    void needNewBox();
    void gameFinished();

public slots:
    void moveOneStep();
    void startTimer(int interval);
    void stopTimer();
};

到 mybox.cpp 中添加头文件:

#include <QKeyEvent>
#include <QTimer>

添加 BoxGroup 类的实现代码:

// 方块组类

void BoxGroup::keyPressEvent(QKeyEvent* event)
{
    switch (event->key())
    {
        case Qt::Key_Down:
            moveBy(0, 20);
            if (isColliding())
            {
                moveBy(0, -20);

                // 将小方块从方块组中移除到场景中
                clearBoxGroup();

                // 需要显示新的方块
                emit needNewBox();
            }
            break;

        case Qt::Key_Left:
            moveBy(-20, 0);
            if (isColliding())
                moveBy(20, 0);
            break;

        case Qt::Key_Right:
            moveBy(20, 0);
            if (isColliding())
                moveBy(-20, 0);
            break;

        case Qt::Key_Up:
            rotate(90);
            if (isColliding())
                rotate(-90);
            break;

        // 空格键实现坠落
        case Qt::Key_Space:
            moveBy(0, 20);
            while (!isColliding())
            {
                moveBy(0, 20);
            }
            moveBy(0, -20);
            clearBoxGroup();
            emit needNewBox();
            break;
    }
}

BoxGroup::BoxGroup()
{
    setFlags(QGraphicsItem::ItemIsFocusable);

    // 保存变换矩阵,当 BoxGroup 进行旋转后,可以使用它来进行恢复
    oldTransform = transform();

    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(moveOneStep()));
    currentShape = RandomShape;
}

QRectF BoxGroup::boundingRect() const
{
    qreal penWidth = 1;
    return QRectF(-40 - penWidth / 2, -40 - penWidth / 2, 80 + penWidth, 80 + penWidth);
}

// 碰撞检测
bool BoxGroup::isColliding()
{
    QList<QGraphicsItem*> itemList = childItems();
    QGraphicsItem* item;
    // 使用方块组中的每一个小方块来进行判断
    foreach (item, itemList)
    {
        if (item->collidingItems().count() > 1)
            return true;
    }
    return false;
}

// 创建方块
void BoxGroup::createBox(const QPointF& point, BoxShape shape)
{
    static const QColor colorTable[7] =
    {
        QColor(200, 0, 0, 100),
        QColor(255, 200, 0, 100),
        QColor(0, 0, 200, 100),
        QColor(0, 200, 0, 100),
        QColor(0, 200, 255, 100),
        QColor(200, 0, 255, 100),
        QColor(150, 100, 100, 100)
    };

    int shapeID = shape;

    if (shape == RandomShape)
    {
        // 产生 0-6 之间的随机数
        shapeID = qrand() % 7;
    }

    QColor color = colorTable[shapeID];

    QList<OneBox*> list;
    //恢复方块组的变换矩阵
    setTransform(oldTransform);
    for (int i = 0; i < 4; ++i)
    {
        OneBox* temp = new OneBox(color);
        list << temp;
        addToGroup(temp);
    }

    switch (shapeID)
    {
        case IShape:
            currentShape = IShape;
            list.at(0)->setPos(-30, -10);
            list.at(1)->setPos(-10, -10);
            list.at(2)->setPos(10, -10);
            list.at(3)->setPos(30, -10);
            break;

        case JShape:
            currentShape = JShape;
            list.at(0)->setPos(10, -10);
            list.at(1)->setPos(10, 10);
            list.at(2)->setPos(-10, 30);
            list.at(3)->setPos(10, 30);
            break;

        case LShape:
            currentShape = LShape;
            list.at(0)->setPos(-10, -10);
            list.at(1)->setPos(-10, 10);
            list.at(2)->setPos(-10, 30);
            list.at(3)->setPos(10, 30);
            break;

        case OShape:
            currentShape = OShape;
            list.at(0)->setPos(-10, -10);
            list.at(1)->setPos(10, -10);
            list.at(2)->setPos(-10, 10);
            list.at(3)->setPos(10, 10);
            break;

        case SShape:
            currentShape = SShape;
            list.at(0)->setPos(10, -10);
            list.at(1)->setPos(30, -10);
            list.at(2)->setPos(-10, 10);
            list.at(3)->setPos(10, 10);
            break;

        case TShape:
            currentShape = TShape;
            list.at(0)->setPos(-10, -10);
            list.at(1)->setPos(10, -10);
            list.at(2)->setPos(30, -10);
            list.at(3)->setPos(10, 10);
            break;

        case ZShape:
            currentShape = ZShape;
            list.at(0)->setPos(-10, -10);
            list.at(1)->setPos(10, -10);
            list.at(2)->setPos(10, 10);
            list.at(3)->setPos(30, 10);
            break;

        default: break;
    }
    // 设置位置
    setPos(point);
    // 如果开始就发生碰撞,说明已经结束游戏
    if (isColliding())
    {
        stopTimer();
        emit gameFinished();
    }
}

// 删除方块组中的所有小方块
void BoxGroup::clearBoxGroup(bool destroyBox)
{
    QList<QGraphicsItem*> itemList = childItems();
    QGraphicsItem* item;
    foreach (item, itemList)
    {
        removeFromGroup(item);
        if (destroyBox)
        {
            OneBox* box = (OneBox*)item;
            box->deleteLater();
        }
    }
}

// 向下移动一步
void BoxGroup::moveOneStep()
{
    moveBy(0, 20);
    if (isColliding())
    {
        moveBy(0, -20);
        // 将小方块从方块组中移除到场景中
        clearBoxGroup();
        emit needNewBox();
    }
}

// 开启定时器
void BoxGroup::startTimer(int interval) { timer->start(interval); }

// 停止定时器
void BoxGroup::stopTimer() { timer->stop(); }
添加游戏场景

新建一个 C++ 类,类名为 MyView,基类为 GraphicsView,继承自 QWidget:

在这里插入图片描述

更改 myview.h:

#ifndef MYVIEW_H
#define MYVIEW_H

#include <QGraphicsView>
#include <QWidget>

class BoxGroup;

class MyView : public GraphicsView
{
private:
    BoxGroup* boxGroup;
    BoxGroup* nextBoxGroup;
    QGraphicsLineItem* topLine;
    QGraphicsLineItem* bottomLine;
    QGraphicsLineItem* leftLine;
    QGraphicsLineItem* rightLine;
    qreal gameSpeed;
    QList<int> rows;

    void initView();
    void initGame();
    void updateScore(const int fullRowNum = 0);

public:
    explicit MyView(QWidget* parent = 0);

public slots:
    void startGame();
    void clearFullRows();
    void moveBox();
    void gameOver();
};

#endif  // MYVIEW_H

更改 myview.cpp:

#include "myview.h"

#include <QIcon>

#include "mybox.h"

// 游戏的初始速度
static const qreal INITSPEED = 500;

// 初始化游戏界面
void MyView::initView()
{
    // 使用抗锯齿渲染
    setRenderHint(QPainter::Antialiasing);
    // 设置缓存背景,这样可以加快渲染速度
    setCacheMode(CacheBackground);
    setWindowTitle(tr("MyBox方块游戏"));
    setWindowIcon(QIcon(":/images/icon.png"));
    setMinimumSize(810, 510);
    setMaximumSize(810, 510);
    // 设置场景
    QGraphicsScene* scene = new QGraphicsScene;
    scene->setSceneRect(5, 5, 800, 500);
    scene->setBackgroundBrush(QPixmap(":/images/background.png"));
    setScene(scene);
    // 方块可移动区域的四条边界线
    topLine = scene->addLine(197, 47, 403, 47);
    bottomLine = scene->addLine(197, 453, 403, 453);
    leftLine = scene->addLine(197, 47, 197, 453);
    rightLine = scene->addLine(403, 47, 403, 453);
    // 当前方块组和提示方块组
    boxGroup = new BoxGroup;
    connect(boxGroup, SIGNAL(needNewBox()), this, SLOT(clearFullRows()));
    connect(boxGroup, SIGNAL(gameFinished()), this, SLOT(gameOver()));
    scene->addItem(boxGroup);
    nextBoxGroup = new BoxGroup;
    scene->addItem(nextBoxGroup);

    startGame();
}

// 初始化游戏
void MyView::initGame()
{
    boxGroup->createBox(QPointF(300, 70));
    boxGroup->setFocus();
    boxGroup->startTimer(INITSPEED);
    gameSpeed = INITSPEED;
    nextBoxGroup->createBox(QPointF(500, 70));
}

// 更新分数
void MyView::updateScore(const int fullRowNum) {}

MyView::MyView(QWidget* parent) : QGraphicsView(parent) { initView(); }

// 开始游戏
void MyView::startGame() { initGame(); }

// 清空满行
void MyView::clearFullRows()
{
    // 获取比一行方格较大的矩形中包含的所有小方块
    for (int y = 429; y > 50; y -= 20)
    {
        QList<QGraphicsItem*> list = scene()->items(199, y, 202, 22, Qt::ContainsItemShape);
        // 如果该行已满
        if (list.count() == 10)
        {
            foreach (QGraphicsItem* item, list)
            {
                OneBox* box = (OneBox*)item;
                box->deleteLater();
            }
            // 保存满行的位置
            rows << y;
        }
    }

    if (rows.count() > 0)
    {
        // 如果有满行,下移满行上面的各行再出现新的方块组
        moveBox();
    }
    else  // 如果没有满行,则直接出现新的方块组
    {
        boxGroup->createBox(QPointF(300, 70), nextBoxGroup->getCurrentShape());
        // 清空并销毁提示方块组中的所有小方块
        nextBoxGroup->clearBoxGroup(true);
        nextBoxGroup->createBox(QPointF(500, 70));
    }
}

// 下移满行上面的所有小方块
void MyView::moveBox()
{
    // 从位置最靠上的满行开始
    for (int i = rows.count(); i > 0; i--)
    {
        int row = rows.at(i - 1);
        foreach (QGraphicsItem* item, scene()->items(199, 49, 202, row - 47, Qt::ContainsItemShape))
        {
            item->moveBy(0, 20);
        }
    }
    // 更新分数
    updateScore(rows.count());
    // 将满行列表清空为 0
    rows.clear();
    // 等所有行下移以后再出现新的方块组
    boxGroup->createBox(QPointF(300, 70), nextBoxGroup->getCurrentShape());
    nextBoxGroup->clearBoxGroup(true);
    nextBoxGroup->createBox(QPointF(500, 70));
}

// 游戏结束
void MyView::gameOver() {}
添加主函数

新建 main.cpp,添加代码:

#include <QApplication>
#include <QTextCodec>
#include <QTime>

#include "myview.h"

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

    QTextCodec::setCodecForTr(QTextCodec::codecForLocale());

    // 设置随机数的初始值
    qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));

    MyView view;
    view.show();

    return app.exec();
}

测试

运行程序。

果不其然的报错了。

主要是一些 Qt4 和 Qt5 的差别带来的问题。

踩坑点1:rotate 失效

函数 void BoxGroup::keyPressEvent(QKeyEvent* event) 原代码:

void BoxGroup::keyPressEvent(QKeyEvent *event)
{
    switch (event->key())
    {
    case Qt::Key_Down :
        moveBy(0, 20);
        if (isColliding()) {
            moveBy(0, -20);

            // 将小方块从方块组中移除到场景中
            clearBoxGroup();

            // 需要显示新的方块
            emit needNewBox();
        }
        break;

    case Qt::Key_Left :
        moveBy(-20, 0);
        if (isColliding())
            moveBy(20, 0);
        break;

    case Qt::Key_Right :
        moveBy(20, 0);
        if (isColliding())
            moveBy(-20, 0);
        break;

    case Qt::Key_Up :
        rotate(90);
        if(isColliding())
            rotate(-90);
        break;

    // 空格键实现坠落
    case Qt::Key_Space :
        moveBy(0, 20);
        while (!isColliding()) {
            moveBy(0, 20);
        }
        moveBy(0, -20);
        clearBoxGroup();
        emit needNewBox();
        break;
    }
}

其中的 rotate 函数失效。

在 Qt5 中,QGraphicsItem::rotate 已经不再使用,而是使用 setRotation。

修改为:

void BoxGroup::keyPressEvent(QKeyEvent* event)
{
    qreal oldRotate;

    switch (event->key())
    {
        // 下移
        case Qt::Key_Down:
            moveBy(0, 20);
            if (isColliding())
            {
                moveBy(0, -20);
                // 将小方块从方块组中移除到场景中
                clearBoxGroup();
                // 需要显示新的方块
                emit needNewBox();
            }
            break;
        // 左移
        case Qt::Key_Left:
            moveBy(-20, 0);
            if (isColliding())
                moveBy(20, 0);
            break;
        // 右移
        case Qt::Key_Right:
            moveBy(20, 0);
            if (isColliding())
                moveBy(-20, 0);
            break;
        // 旋转
        case Qt::Key_Up:
            // 在 Qt5 中,QGraphicsItem::rotate 已经不再使用,而是使用 setRotation
            /* old code */
            //    rotate(90);
            //   if (isColliding())
            //       rotate(-90);
            //    break;
            /* old code */

            oldRotate = rotation();
            if (oldRotate >= 360)
            {
                oldRotate = 0;
            }
            setRotation(oldRotate + 90);
            if (isColliding())
            {
                setRotation(oldRotate - 90);
            }
            break;

        // 空格键实现坠落
        case Qt::Key_Space:
            moveBy(0, 20);
            while (!isColliding())
            {
                moveBy(0, 20);
            }
            moveBy(0, -20);
            clearBoxGroup();
            emit needNewBox();
            break;
    }
}

参考博客:Qt及Qt Quick开发实战精解项目二俄罗斯方块 rotate失效方法报错

踩坑点2:items 方法报错

在 void MyView::clearFullRows() 函数里有这样一行代码:

QList<QGraphicsItem*> list = scene()->items(199, y, 202, 22, Qt::ContainsItemShape);

报错信息:

myview.cpp:75:47: error: no matching member function for call to 'items'
qgraphicsscene.h:158:28: note: candidate function not viable: requires at most 4 arguments, but 5 were provided
qgraphicsscene.h:159:28: note: candidate function not viable: requires at most 4 arguments, but 5 were provided
qgraphicsscene.h:160:28: note: candidate function not viable: requires at most 4 arguments, but 5 were provided
qgraphicsscene.h:161:28: note: candidate function not viable: requires at most 4 arguments, but 5 were provided
qgraphicsscene.h:175:35: note: candidate function not viable: requires at least 6 arguments, but 5 were provided
qgraphicsscene.h:156:28: note: candidate function not viable: allows at most single argument 'order', but 5 arguments were provided

大概意思是参数不匹配。

修改为:

QList<QGraphicsItem*> list = scene()->items(199, y, 202, 22, Qt::ContainsItemShape, Qt::AscendingOrder);

新增的一项 Qt::AscendingOrder 的意思是对 QList 的内容正序排序。

参考博客:Qt及Qt Quick开发实战精解项目二俄罗斯方块 items方法报错

踩坑点3:setCodecForTr 失效

在 main.cpp 中有这样一行代码:

QTextCodec::setCodecForTr(QTextCodec::codecForLocale());

这行代码主要解决 Qt 中文乱码的问题。

但是在 Qt5 中 setCodecForTr 函数已经失效了,我们改成:

QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8"));

这个视个人电脑使用的编码决定。

踩坑点4:不要在中文路径下运行 Qt 项目

就是这样,喵~

踩坑点5:multiple definition of `qMain(int, char**)’

报错信息:

error: multiple definition of `qMain(int, char**)'

这是在 pro 文件中出的问题,频繁的添加以及移除文件,导致 HEADERS 以及 SOURCES 中会重复添加。

在这里插入图片描述

这里 main.cpp 重复了,删掉一个即可。

测试效果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1156377.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

界面控件DevExpress WPF Gauge组件 - 轻松实现个性化商业仪表盘

DevExpress WPF Gauge&#xff08;仪表&#xff09;控件包含了多种圆形仪表类型、水平和垂直线性仪表、分段和矩阵数字仪表以及状态指示器&#xff0c;同时还具有最终用户交互性的集成支持。 P.S&#xff1a;DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至…

Intel oneAPI笔记--oneAPI简介、SYCL编程简介

oneAPI简介 Intel oneAPI是Intel提供的统一编程模型和软件开发框架。 它旨在简化可充分利用英特尔各种硬件架构&#xff08;包括 CPU、GPU 和 FPGA&#xff09;的应用程序的开发 oneAPI一个重要的特性是开放性&#xff0c;支持多种类型的架构和不同的硬件供应商&#xff0c;是…

RK3588编译MXNet框架

目录 1. 背景 2.编译MXNet准备 3.开发板编译 1. 背景 MXNet&#xff08;也称为Apache MXNet或incubator-mxnet&#xff09;是一个开源的深度学习框架&#xff0c;它最初由华为和亚马逊AWS共同开发&#xff0c;并于2017年成为Apache软件基金会的孵化项目。MXNet旨在提供高效、…

DAY40 343. 整数拆分 + 96. 不同的二叉搜索树

343. 整数拆分 题目要求&#xff1a;给定一个正整数 n&#xff0c;将其拆分为至少两个正整数的和&#xff0c;并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 示例 1: 输入: 2输出: 1解释: 2 1 1, 1 1 1。 示例 2: 输入: 10输出: 36解释: 10 3 3 4, 3 3 …

从 Seq2Seq 到 Attention:彻底改变序列建模

探究Attention机制和意力的起源。 简介 在这篇博文[1]中&#xff0c;将讨论注意力机制的起源&#xff0c;然后介绍第一篇将注意力用于神经机器翻译的论文。由于上下文压缩、短期记忆限制和偏差&#xff0c;具有 2 个 RNN 的 Seq2Seq 模型失败了。该模型的 BLEU 分数随着序列长度…

如何用ChatGPT进行“论文翻译+润色”?

2024年申报国自然项目基金撰写及技巧最新基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法 GPT引领前沿与应用突破之GPT4科研实践技术与AI绘图 不夸张说&#xff0c;只要调教好咒语&#xff0c;就必然会形成一场论文翻译润色…

Spring Security的基本授权配置方式

参考&#xff1a;方法安全&#xff08;Method Security&#xff09; :: Spring Security Reference (springdoc.cn)、 授权 HttpServletRequest :: Spring Security Reference (springdoc.cn) 前文为&#xff1a;Spring Security&#xff1a;授权框架 一、HttpServletRequest…

xcode 安装及运行个人app编程应用

1.xcode 介绍 Xcode 是运行在操作系统Mac OS X上的集成开发工具&#xff08;IDE&#xff09;&#xff0c;由Apple Inc开发。Xcode是开发 macOS 和 iOS 应用程序的最快捷的方式。Xcode 具有统一的用户界面设计&#xff0c;编码、测试、调试都在一个简单的窗口内完成 2.xcode 下…

Redis统计大法:挖掘数据的四重宝藏【redis第五部分】

Redis统计大法&#xff1a;挖掘数据的四重宝藏 前言第一&#xff1a;redis集合统计简介第二&#xff1a;聚合统计->数据的综合分析总和&#xff08;Sum&#xff09;&#xff1a;平均值&#xff08;Average&#xff09;中位数&#xff08;Median&#xff09; 第三&#xff1a…

urlPattern配置和request

urlPattern配置 Servlet类编写好后&#xff0c;想要被访问到&#xff0c;就需要配置其访问路径&#xff08;urlPattern&#xff09; 一个Servlet可以配置多个urlPattern&#xff1a; WebServlet&#xff08;urlPatterns{"/demo","/demo2"}) urlPattern配置…

html获取网络数据,列表展示 一

html获取网络数据&#xff0c;列表展示 js遍历json数组中的json对象 image.png || - 判断数据是否为空&#xff0c;为空就显示 - <!DOCTYPE html> <html><head><meta charset"utf-8"><title>网页列表</title></head><b…

FreeRTOS深入教程(空闲任务和Tick中断深入分析)

文章目录 前言一、空闲任务源码分析二、Tick中断深入分析总结 前言 本篇文章主要带大家深入分析空闲任务和Tick中断的作用。 一、空闲任务源码分析 在启动调度器时会创建出空闲任务&#xff1a; /* 启动调度器 */ vTaskStartScheduler();在空闲任务中会调用到prvCheckTasks…

k8s pod获取ip地址过程

在学习 Kubernetes 网络模型的过程中&#xff0c;了解各种网络组件的作用以及如何交互非常重要。本文就介绍了各种网络组件在 Kubernetes 集群中是如何交互的&#xff0c;以及如何帮助每个 Pod 都能获取 IP 地址。 Kubernetes 网络模型的核心要求之一是每个 Pod 都拥有自己的 …

oracle 重启步骤及踩坑经验

oracle 重启步骤及踩坑经验 标准重启步骤 切换到oracle用户 su - oracle关闭监听 lsnrctl stop杀掉oracle有关进程 ps -ef|grep $ORACLE_SID|grep -v ora_|grep LOCALNO|awk {print $2}|xargs kill -9#查询pid ps -ef|grep $ORACLE_SID|grep -v ora_|grep LOCALNO|awk {p…

Linux--jdk、tomcat、环境配置,mysql安装、后端项目搭建

前言 上期我们讲到了安装linux虚拟机&#xff0c;这期我们来讲一下如何使用xshell和xftp在linux系统上搭建我们的单体项目 一、软件的传输 1.1 xftp Xftp是一款功能强大的文件传输软件&#xff0c;用于在本地主机和远程服务器之间进行快速、安全的文件传输。它是由南京帆软科…

【MongoDB】Windows 安装MongoDB 6.0

一、下载安装包 安装包下载地址https://www.mongodb.com/try/download/community这里我选择的是 二、解压并安装 1、解压 这里我将压缩包解压到了D盘&#xff0c;并重命名成了mongodb&#xff0c;解压后的目录如下&#xff1a; 2、创建配置文件 在D:\mongodb下新建conf目录…

数据库面试题整理

目录 MySQL事务隔离级别有哪几种&#xff1f;MySQL的常用的存储引擎有哪些&#xff1f;特点是什么&#xff0c;分别适合什么场景下使用MySQL有数据缓存吗&#xff1f;原理是怎么样的&#xff1f;InnoDB的缓冲池默认是开启的吗&#xff1f;基本原理是什么&#xff1f;会有脏数据…

Flutter 01 目录结构入门

一、Flutter目录结构&#xff1a; 二、Flutter入口文件、入口方法&#xff1a; 三、Flutter Demo&#xff1a; demo1&#xff1a; import package:flutter/material.dart;//MaterialApp 和 Scaffold两个组件装饰App void main() {runApp(MaterialApp(home: Scaffold(appBar: A…

当函数参数为一级指针,二级指针

当函数参数为一级指针&#xff0c;二级指针 在讲述内容之前&#xff0c;先讲四点重要知识 1.当传入参数时&#xff0c;函数形参会立即申请形参的内存空间&#xff0c;函数执行完毕后&#xff0c;形参的内存空间立即释放掉。 1.指针是存放其他变量地址的变量。指针有自己的内…

腾讯云轻量应用镜像、系统镜像、Docker基础镜像、自定义镜像和共享镜像介绍

腾讯云轻量应用服务器镜像类型分为应用镜像、系统镜像、Docker基础镜像、自定义镜像和共享镜像&#xff0c;腾讯云百科txybk.com来详细说下不同镜像类型说明和详细介绍&#xff1a; 轻量应用服务器镜像类型说明 腾讯云轻量应用服务器 应用镜像&#xff1a;独有的应用镜像除了包…