第十四章- 面对墙壁

news2024/11/13 10:51:24

在这里插入图片描述

这是最后的例子:一个完整的游戏。

我们添加键盘快捷键并引入鼠标事件到CannonField。我们在CannonField周围放一个框架并添加一个障碍物(墙)使这个游戏更富有挑战性。

  • lcdrange.h包含LCDRange类定义
  • lcdrange.cpp包含LCDRange类实现
  • cannon.h包含CannonField类定义
  • cannon.cpp包含CannonField类实现
  • gamebrd.h包含GameBoard类定义
  • gamebrd.cpp包含GameBoard类实现
  • main.cpp包含MyWidget和main

一行一行地解说

cannon.h:

CannonField现在可以接收鼠标事件,使得用户可以通过点击和拖拽炮筒来瞄准。CannonField也有一个障碍物的墙。

protected:
    void  paintEvent(QPaintEvent *);
    void  mousePressEvent(QMouseEvent *);
    void  mouseMoveEvent(QMouseEvent *);
    void  mouseReleaseEvent(QMouseEvent *);

除了常见的事件处理器,CannonField实现了三个鼠标事件处理器。名称说明了一切。

    void  paintBarrier(QPainter *);

这个私有函数绘制了障碍物墙。

    QRect barrierRect() const;

这个私有函数返回封装障碍物的矩形。

    bool  barrelHit(const QPoint &) const;

这个私有函数检查是否一个点在加农炮炮筒的内部。

    bool barrelPressed;

当用户在炮筒上点击鼠标并且没有放开的话,这个私有变量为true。


cannon.cpp:

    barrelPressed = false;

这一行被添加到构造函数中。最开始的时候,鼠标没有在炮筒上点击。

    else if (shotR.x() > width() || shotR.y() > height() ||
             shotR.intersects(barrierRect()))

现在我们有了一个障碍物,这样就有了三种射击的方法。我们来测试一下第三种。

void CannonField::mousePressEvent(QMouseEvent *e)
{
    if (e->button() != Qt::LeftButton)
        return;
    if (barrelHit(e->pos()))
        barrelPressed = true;
}

这是一个Qt事件处理器。当鼠标指针在窗口部件上,用户按下鼠标的按键时,它被调用。

如果事件不是由鼠标左键产生的,我们立即返回。否则,我们检查鼠标指针是否在加农炮的炮筒内。如果是的,我们设置barrelPressed为true。

注意pos()函数返回的是窗口部件坐标系统中的点。

void CannonField::mouseMoveEvent(QMouseEvent *e)
{
    if (!barrelPressed)
        return;
    QPoint pnt = e->pos();
    if (pnt.x() <= 0)
        pnt.setX(1);
    if (pnt.y() >= height())
        pnt.setY(height() - 1);
    double rad = atan(((double)rect().bottom()-pnt.y())/pnt.x());
    setAngle(qRound (rad*180/3.14159265));
}

这是另外一个Qt事件处理器。当用户已经在窗口部件中按下了鼠标按键并且移动/拖拽鼠标时,它被调用。(你可以让Qt在没有鼠标按键被按下的时候发送鼠标移动事件。请看QWidget::setMouseTracking()。)

这个处理器根据鼠标指针的位置重新配置加农炮的炮筒。

首先,如果炮筒没有被按下,我们返回。接下来,我们获得鼠标指针的位置。如果鼠标指针到了窗口部件的左面或者下面,我们调整鼠标指针使它返回到窗口部件中。

然后我们计算在鼠标指针和窗口部件的左下角所构成的虚构的线和窗口部件下边界的角度。最后,我们把加农炮的角度设置为我们新算出来的角度。

记住要用setAngle()来重新绘制加农炮。

void CannonField::mouseReleaseEvent(QMouseEvent *e)
{
    if (e->button() == Qt::LeftButton)
        barrelPressed = false;
}

只要用户释放鼠标按钮并且它是在窗口部件中按下的时候,这个Qt事件处理器就会被调用。

如果鼠标左键被释放,我们就会确认炮筒不再被按下了。

绘画事件包含了下述额外的两行:

    if (updateR.intersects(barrierRect()))
        paintBarrier(&p);

paintBarrier()做的和paintShot()、paintTarget()和paintCannon()是同样的事情。

void CannonField::paintBarrier(QPainter *p)
{
    p->setBrush(Qt::yellow);
    p->setPen(Qt::black);
    p->drawRect(barrierRect());
}

这个私有函数用一个黑色边界黄色填充的矩形作为障碍物。

QRect CannonField::barrierRect() const
{
    return QRect( 145, height() - 100, 15, 100 );
}

这个私有函数返回障碍物的矩形。我们把障碍物的下边界和窗口部件的下边界放在了一起。

bool CannonField::barrelHit(const QPoint &p) const
{
    QTransform transform;
    transform.translate(0, height() - 1);
    transform.rotate(-ang);

    transform = transform.inverted();    // QTransform 的逆矩阵操作
    QPoint transformedPoint = transform.map(p); // 将点 p 转换到炮管坐标系
    return barrelRect.contains(transformedPoint);    // 检查转换后的点是否在 barrelRect 内
}

如果点在炮筒内,这个函数返回true;否则它就返回false。

这里我们使用QTransform类。它是在头文件QTransform中定义的,这个头文件被QPainter包含。

QTransform定义了一个坐标系统映射。它可以执行和QPainter中一样的转换。

这里我们实现同样的转换的步骤就和我们在paintCannon()函数中绘制炮筒的时候所作的一样。首先我们转换坐标系统,然后我们旋转它。

现在我们需要检查点p(在窗口部件坐标系统中)是否在炮筒内。为了做到这一点,我们倒置这个转换矩阵。倒置的矩阵就执行了我们在绘制炮筒时使用的倒置的转换。我们通过使用倒置矩阵来映射点p,并且如果它在初始的炮筒矩形内就返回true。


gameboard.cpp:

#include <QShortcut>

我们包含QShortcut的类定义。

    QVBoxLayout *boxLayout = new QVBoxLayout; // 创建 QVBoxLayout 对象

    QFrame *boxFrame = new QFrame(this); //用于创建一个框架,可以用 `setFrameStyle` 设置样式。
    boxFrame->setFrameStyle(QFrame::WinPanel | QFrame::Sunken); //设置一个框架样式,使其看起来像一个有阴影的面板。`QFrame::WinPanel` 和 `QFrame::Sunken` 是样式标志,使得框架有一个凹陷的效果。
    boxFrame->setLayout(boxLayout); // 将 QVBoxLayout 设置到 QFrame 上

    CannonField *cannonField = new CannonField(boxFrame);
    boxLayout->addWidget(cannonField); // 添加 CannonField 到 QVBoxLayout

我们创建并设置一个QVBoxLayout,然后设置它的框架风格,并在之后创建CannonField作为这个盒子的子对象。因为没有其它的东西在这个盒子里了,效果就是QVBoxLayout会在CannonField周围生成了一个框架。

    QShortcut *fireShortcut = new QShortcut(Qt::Key_Space, this);
    connect(fireShortcut, SIGNAL(activated()), this, SLOT(fire()));
    QShortcut *quitShortcut = new QShortcut(Qt::Key_Q, this);
    connect(quitShortcut, SIGNAL(activated()), qApp, SLOT(quit()));

现在我们创建并设置一个加速键。加速键就是在应用程序中截取键盘事件并且如果特定的键被按下的时候调用相应的槽。这种机制也被称为快捷键。注意快捷键是窗口部件的子对象并且当窗口部件被销毁的时候销毁。QShortcut不是窗口部件,并且在它的父对象中没有任何可见的效果。

我们定义两个快捷键。我们希望在Space键被按下的时候调用fire()槽,在Q键被按下的时候,应用程序退出。

Ctrl、Key_Enter、Key_Return和Key_Q都是Qt提供的常量。它们实际上就是Qt::Key_Enter等等,但是实际上所有的类都继承了Qt这个命名空间类。

    QGridLayout *grid = new QGridLayout;
    grid->addWidget(quit, 0, 0);
    grid->addWidget(boxFrame, 1, 1);
    grid->setColumnStretch(1, 10);

我们放置boxFrame,不是CannonField,在右下的单元格中。

行为

现在当你按下Space的时候,加农炮就会发射。你也可以用鼠标来确定加农炮的角度。障碍物会使你在玩游戏的时候获得更多一点的挑战。我们还会在CannnonField周围看到一个好看的框架。

练习

新的练习是:写一个突围游戏。

最后的劝告:现在向前进,创造编程艺术的杰作!


lcdrange.h

#ifndef LCDRANGE_H
#define LCDRANGE_H

#include <QWidget>

class QSlider;
class QLabel;

class LCDRange : public QWidget
{
    Q_OBJECT
public:
    LCDRange(QWidget *parent = 0);
    LCDRange(const QString &s, QWidget *parent = 0);

    int value() const;
    const QString text() const;

public slots:
    void setValue(int);
    void setRange(int minVal, int maxVal);
    void setText(const QString &s);

signals:
    void valueChanged(int);

private:
    void init();

    QSlider *slider;
    QLabel  *label;
};

#endif // LCDRANGE_H

lcdrange.cpp

#include "lcdrange.h"
#include <QVBoxLayout>
#include <QLCDNumber>
#include <QSlider>
#include <QLabel>

LCDRange::LCDRange(QWidget *parent)
    : QWidget(parent)
{
    init();
}

LCDRange::LCDRange(const QString &s, QWidget *parent)
    : QWidget(parent)
{
    init();
    setText(s);
}

void LCDRange::init()
{
    QLCDNumber *lcd  = new QLCDNumber(2);
    slider = new QSlider(Qt::Horizontal);
    slider->setRange(0, 99);
    slider->setValue(0);

    label = new QLabel;
    label->setAlignment(Qt::AlignHCenter);

    connect(slider, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)));
    connect(slider, SIGNAL(valueChanged(int)), SIGNAL(valueChanged(int)));

    setFocusProxy(slider); //设置这个窗口部件的焦点为slider

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(lcd);
    layout->addWidget(slider);
    layout->addWidget(label);
    setLayout(layout);
}

int LCDRange::value() const
{
    return slider->value();
}

const QString LCDRange::text() const
{
     return label->text();
}

void LCDRange::setValue(int value)
{
    slider->setValue(value);
}

void LCDRange::setRange(int minVal, int maxVal)
{
    if (minVal < 0 || maxVal > 99 || minVal > maxVal)
    {
        qWarning( "LCDRange::setRange(%d,%d)\n"
                 "\tRange must be 0~99\n"
                 "\tand minVal must not be greater than maxVal",
                 minVal, maxVal);
        return;
    }
    slider->setRange(minVal, maxVal);
}

void LCDRange::setText(const QString &s)
{
    label->setText(s);
}

cannon.h

#ifndef CANNON_H
#define CANNON_H

class QTimer;

#include <QWidget>

class CannonField : public QWidget
{
    Q_OBJECT
public:
    CannonField(QWidget *parent = 0);
    int angle() const {return ang;}
    int force() const {return f;}
    bool gameOver() const {return gameEnded;}
    bool isShooting() const;
    QSize sizeHint() const;

public slots:
    void setAngle(int degrees);
    void setForce(int newton);
    void shoot();
    void newTarget();
    void setGameOver();
    void restartGame();

private slots:
    void moveShot(); // 更新炮弹的位置

signals:
    void hit();
    void missed();
    void angleChanged(int);
    void forceChanged(int);
    void canShoot(bool);

protected:
    void  paintEvent(QPaintEvent *); // 窗口刷新/重绘
    void  mousePressEvent(QMouseEvent *);
    void  mouseMoveEvent(QMouseEvent *);
    void  mouseReleaseEvent(QMouseEvent *);


private:
    void paintShot(QPainter *);
    void paintTarget(QPainter *);
    void paintCannon(QPainter *);
    void paintBarrier( QPainter *);
    QRect cannonRect() const;
    QRect shotRect() const;
    QRect targetRect() const;
    QRect barrierRect() const;
    bool  barrelHit(const QPoint &) const;

    int ang;
    int f;

    int timerCount;
    QTimer *autoShootTimer;
    float shoot_ang;
    float shoot_f;

    QPoint target;
    bool gameEnded;
    bool barrelPressed;
};

#endif // CANNON_H

cannon.cpp

#include "cannon.h"
#include <QPaintEvent>
#include <QDateTime>
#include <QPainter>
#include <QPixmap>
#include <QTimer>

#include <stdlib.h>
#include <math.h>

CannonField::CannonField(QWidget *parent)
    : QWidget(parent)
{
    ang = 45;
    f = 0;
    timerCount = 0;
    autoShootTimer = new QTimer;
    connect(autoShootTimer, SIGNAL(timeout()), this, SLOT(moveShot()));

    shoot_ang = 0;
    shoot_f = 0;
    target = QPoint(0, 0);
    gameEnded = false;
    barrelPressed = false;
    setAutoFillBackground(true);
    setPalette(QPalette(QColor(250, 250, 200)));
    newTarget();
}

void CannonField::setAngle(int degrees)
{
    if (degrees < 5)
        degrees = 5;
    if (degrees > 70)
        degrees = 70;
    if (ang == degrees)
        return;
    ang = degrees;
    repaint(cannonRect());
    emit angleChanged(ang);
}

void CannonField::setForce(int newton)
{
    if (newton < 0)
        newton = 0;
    if (f == newton)
        return;
    f = newton;
    emit forceChanged(f);
}

void CannonField::shoot()
{
    if (isShooting())
        return;
    timerCount = 0;
    shoot_ang = ang;
    shoot_f = f;
    autoShootTimer->start(50);
    emit canShoot(false);
}

void  CannonField::newTarget()
{
    static bool first_time = true;
    if (first_time)
    {
        first_time = false;
        QTime midnight(0, 0, 0);
        srand(midnight.secsTo(QTime::currentTime()));
    }
    QRegion r(targetRect());
    target = QPoint(200 + rand() % 190, 10 + rand() % 255);
    repaint(r.united(targetRect()));
    emit canShoot(true);
}

void CannonField::setGameOver()
{
    if (gameEnded)
        return;
    if (isShooting())
        autoShootTimer->stop();
    gameEnded = true;
    repaint();
}

void CannonField::restartGame()
{
    if (isShooting())
        autoShootTimer->stop();
    gameEnded = false;
    repaint();
    emit canShoot(true);
}

void CannonField::moveShot()
{
    QRegion r(shotRect());
    timerCount++;

    QRect shotR = shotRect();

    if (shotR.intersects(targetRect()))
    {
        autoShootTimer->stop();
        emit hit();
    }
    else if (shotR.x() > width() || shotR.y() > height() ||
             shotR.intersects(barrierRect()))
    {
        autoShootTimer->stop();
        emit missed();
        emit canShoot(true);
    }
    else
    {
        r = r.united(QRegion(shotR));
    }

    repaint(r);
}

void CannonField::mousePressEvent(QMouseEvent *e)
{
    if (e->button() != Qt::LeftButton)
        return;
    if (barrelHit(e->pos()))
        barrelPressed = true;
}

void CannonField::mouseMoveEvent(QMouseEvent *e)
{
    if (!barrelPressed)
        return;
    QPoint pnt = e->pos();
    if (pnt.x() <= 0)
        pnt.setX(1);
    if (pnt.y() >= height())
        pnt.setY(height() - 1);
    double rad = atan(((double)rect().bottom()-pnt.y())/pnt.x());
    setAngle(qRound (rad*180/3.14159265));
}

//鼠标释放事件
void CannonField::mouseReleaseEvent(QMouseEvent *e)
{
    if (e->button() == Qt::LeftButton)
        barrelPressed = false;
}

void CannonField::paintEvent(QPaintEvent *e)
{
    QRect updateR = e->rect();
    QPainter p(this);

    if (gameEnded)
    {
        p.setPen(Qt::black);
        p.setFont(QFont("Courier", 48, QFont::Bold ));
        p.drawText(rect(),Qt::AlignHCenter, "Game Over");
    }
    if (updateR.intersects(cannonRect()))
        paintCannon(&p);
    if (autoShootTimer->isActive() && updateR.intersects(shotRect()))
        paintShot(&p);
    if (updateR.intersects(targetRect()))
        paintTarget(&p);
    if (updateR.intersects(barrierRect()))
        paintBarrier(&p);
}

void CannonField::paintShot(QPainter *p)
{
    p->setBrush(Qt::black);
    p->setPen(Qt::NoPen);
    p->drawEllipse(shotRect()); // 绘制填充圆
}

void CannonField::paintTarget(QPainter *p)
{
    p->setBrush(Qt::red);
    p->setPen(Qt::NoPen);
    p->drawRect(targetRect());
}

void CannonField::paintBarrier(QPainter *p)
{
    p->setBrush(Qt::yellow);
    p->setPen(Qt::black);
    p->drawRect(barrierRect());
}

const QRect barrelRect(33, -4, 15, 8);

void CannonField::paintCannon(QPainter *p)
{
    QRect cr = cannonRect();
    QPixmap pix(cr.size());
    pix.fill(Qt::transparent); //使用透明像素图

    QPainter tmp(&pix);
    tmp.setBrush(Qt::blue);
    tmp.setPen(Qt::NoPen);

    tmp.translate(0, pix.height() - 1);
    tmp.drawPie(QRect(-35,-35, 70, 70), 0, 90*16);
    tmp.rotate(-ang);
    tmp.drawRect(barrelRect);
    tmp.end();

    p->drawPixmap(cr.topLeft(), pix);
}

QRect CannonField::cannonRect() const
{
    QRect r(0, 0, 50, 50);
    r.moveBottomLeft(rect().bottomLeft());
    return r;
}

QRect CannonField::shotRect() const
{
    const double gravity = 4;

    double time      = timerCount / 4.0;
    double velocity  = shoot_f;
    double radians   = shoot_ang * 3.14159265 / 180;

    double velx      = velocity * cos(radians);
    double vely      = velocity * sin(radians);
    double x0        = (barrelRect.right() + 5) * cos(radians);
    double y0        = (barrelRect.right() + 5) * sin(radians);
    double x         = x0 + velx * time;
    double y         = y0 + vely * time - 0.5 * gravity * time * time;

    QRect r = QRect(0, 0, 6, 6);
    r.moveCenter(QPoint(qRound(x), height() - 1 - qRound(y)));

    return r;
}

QRect CannonField::targetRect() const
{
    QRect r(0, 0, 20, 10);
    r.moveCenter(QPoint(target.x(),height() - 1 - target.y()));
    return r;
}

QRect CannonField::barrierRect() const
{
    return QRect( 145, height() - 100, 15, 100 );
}

bool CannonField::barrelHit(const QPoint &p) const
{
    QTransform transform;
    transform.translate(0, height() - 1);
    transform.rotate(-ang);

    // QTransform 的逆矩阵操作
    transform = transform.inverted();

    // 将点 p 转换到炮管坐标系
    QPoint transformedPoint = transform.map(p);

    // 检查转换后的点是否在 barrelRect 内
    return barrelRect.contains(transformedPoint);
}

bool CannonField::isShooting() const
{
    return autoShootTimer->isActive();
}

QSize CannonField::sizeHint() const
{
    return QSize( 400, 300 );
}

gameboard.h

#ifndef GAMEBOARD_H
#define GAMEBOARD_H

#include <QWidget>
#include "cannon.h"

class LCDRange;
class QLCDNumber;
class CannonField;
class QPushButton;

class GameBoard : public QWidget
{
    Q_OBJECT
public:
    explicit GameBoard(QWidget *parent = 0);

protected slots:
    void  fire();
    void  hit();
    void  missed();
    void  newGame();

private:
    QLCDNumber  *hits;
    QLCDNumber  *shotsLeft;
    CannonField *cannonField;
};

#endif // GAMEBOARD_H

gameboard.cpp

#include "gameboard.h"

#include <QApplication>
#include <Qpushbutton>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QLCDNumber>
#include <QShortcut>
#include <QLabel>
#include <QFrame>
#include <Qfont>

#include "lcdrange.h"
#include "cannon.h"

GameBoard::GameBoard(QWidget *parent)
    : QWidget(parent)
{
    QPushButton *quit = new QPushButton("Quit");
    quit->setFont(QFont("Times", 18, QFont::Bold));

    connect(quit, SIGNAL(clicked()), qApp, SLOT(quit()));

    LCDRange *angle  = new LCDRange("ANGLE");
    angle->setRange(5, 70);

    LCDRange *force  = new LCDRange("FORCE");
    force->setRange(10, 50);

    QVBoxLayout *boxLayout = new QVBoxLayout; // 创建 QVBoxLayout 对象

    QFrame *boxFrame = new QFrame(this); //用于创建一个框架,可以用 `setFrameStyle` 设置样式。
    boxFrame->setFrameStyle(QFrame::WinPanel | QFrame::Sunken); //设置一个框架样式,使其看起来像一个有阴影的面板。`QFrame::WinPanel` 和 `QFrame::Sunken` 是样式标志,使得框架有一个凹陷的效果。
    boxFrame->setLayout(boxLayout); // 将 QVBoxLayout 设置到 QFrame 上

    cannonField = new CannonField(boxFrame);
    boxLayout->addWidget(cannonField); // 添加 CannonField 到 QVBoxLayout

    connect(angle, SIGNAL(valueChanged(int)), cannonField, SLOT(setAngle(int)));
    connect(cannonField, SIGNAL(angleChanged(int)), angle, SLOT(setValue(int)));

    connect(force, SIGNAL(valueChanged(int)), cannonField, SLOT(setForce(int)));
    connect(cannonField, SIGNAL(forceChanged(int)), force, SLOT(setValue(int)));

    connect(cannonField, SIGNAL(hit()), this, SLOT(hit()));
    connect(cannonField, SIGNAL(missed()), this, SLOT(missed()));

    QPushButton *shoot = new QPushButton("Shoot");
    shoot->setFont(QFont("Times", 18, QFont::Bold));

    connect(shoot, SIGNAL(clicked()), SLOT(fire()));
    connect(cannonField, SIGNAL(canShoot(bool)), shoot, SLOT(setEnabled(bool)));

    QPushButton *restart = new QPushButton("New Game");
    restart->setFont(QFont("Times", 18, QFont::Bold));

    connect(restart, SIGNAL(clicked()), this, SLOT(newGame()));

    QShortcut *fireShortcut = new QShortcut(Qt::Key_Space, this);
    connect(fireShortcut, SIGNAL(activated()), this, SLOT(fire()));
    QShortcut *quitShortcut = new QShortcut(Qt::Key_Q, this);
    connect(quitShortcut, SIGNAL(activated()), qApp, SLOT(quit()));

    hits = new QLCDNumber(2);
    shotsLeft = new QLCDNumber(2);
    QLabel *hitsL = new QLabel("HITS");
    QLabel *shotsLeftL = new QLabel("SHOTS LEFT");

    QGridLayout *grid = new QGridLayout;
    grid->addWidget(quit, 0, 0);
    grid->addWidget(boxFrame, 1, 1);
    grid->setColumnStretch(1, 10);

    QVBoxLayout *leftBox = new QVBoxLayout;
    grid->addLayout(leftBox, 1, 0);
    leftBox->addWidget(angle);
    leftBox->addWidget(force);

    QHBoxLayout *topBox = new QHBoxLayout;
    grid->addLayout(topBox, 0, 1);
    topBox->addWidget(shoot);
    topBox->addWidget(hits);
    topBox->addWidget(hitsL);
    topBox->addWidget(shotsLeft);
    topBox->addWidget(shotsLeftL);
    topBox->addStretch(1);
    topBox->addWidget(restart);

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addLayout(grid);
    setLayout(layout);

    angle->setValue(60);
    force->setValue(25);
    angle->setFocus();

    newGame();
}

void GameBoard::fire()
{
    if (cannonField->gameOver() || cannonField->isShooting())
        return;
    shotsLeft->display(shotsLeft->intValue() - 1);
    cannonField->shoot();
}

void GameBoard::hit()
{
    hits->display(hits->intValue() + 1);
    if (shotsLeft->intValue() == 0)
        cannonField->setGameOver();
    else
        cannonField->newTarget();
}

void GameBoard::missed()
{
    if (shotsLeft->intValue() == 0)
        cannonField->setGameOver();
}

void GameBoard::newGame()
{
    shotsLeft->display(10);
    hits->display(0);
    cannonField->restartGame();
    cannonField->newTarget();
}


main.cpp

#include <QApplication>
#include "gameboard.h"

int main(int argc, char **argv)
{
    QApplication a(argc, argv);

    GameBoard g;
    g.setGeometry(100, 100, 500, 355);
    g.show();
    return a.exec();
}

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

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

相关文章

Linux 必备:“lsof” 命令 —— 解开系统资源的神秘密码

lsof 似侦探&#xff0c;揭示 Linux 中文件进程关系。图文指南助您探索。 lsof应急排查的作用 发现非法连接&#xff0c;检测未经授权的访问或攻击。定位服务故障&#xff0c;查看是否有进程占用关键端口。找出资源占用过高的进程&#xff0c;优化系统性能。追踪恶意软件的异…

博主正在AI+宠物创业中...

最近开始创业啦&#xff0c;csdn上没太大时间一一回复大家&#xff0c;说一声抱歉啦&#xff01; AI宠物创业中&#xff0c;宠有灵犀CTO&#xff0c;北大硕士 双学位 前阿里巴巴达摩院&#xff0c;邮箱17387842007163.com 我们瞄准了宠物赛道&#xff0c;做的是 供应链电商社交…

One-for-All:上交大提出视觉推理的符号化与逻辑推理分离的新范式 | ECCV 2024

通过对多样化基准的严格评估&#xff0c;论文展示了现有特定方法在实现跨领域推理以及其偏向于数据偏差拟合方面的缺陷。从两阶段的视角重新审视视觉推理&#xff1a;&#xff08;1&#xff09;符号化和&#xff08;2&#xff09;基于符号或其表示的逻辑推理&#xff0c;发现推…

罐装食品检测检测系统源码分享 # [一条龙教学YOLOV8标注好的数据集一键训练_70+全套改进创新点发刊_Web前端展示]

罐装食品检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

一起学习LeetCode热题100道(57/100)

57.电话号码的字母组合(学习) 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a;digit…

ETL数据集成丨实现SQLServer数据库的高效实时数据同步

SQL Server&#xff0c;作为一款功能强大的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;在企业级应用中占据着举足轻重的地位。它不仅提供了可靠的数据存储与管理能力&#xff0c;还集成了高级数据分析、报表服务、集成服务以及商业智能等功能&#xff0c;为…

如何使用 500 多个表构建企业级 AI 查询向导

迄今为止的旅程&#xff1a;Confluence Agent 回顾 在深入研究 SQL Agent 之前&#xff0c;让我们先简单回顾一下我们开发的 Confluence Agent&#xff1a; 元数据提取&#xff1a;捕获我们的知识库的结构。内容提取&#xff1a;提取文档的核心内容。格式处理&#xff1a;分离 …

台灯应该买什么样的才能护眼?适合孩子的护眼台灯挑选指南

2022年3月1日起&#xff0c;正式实施的《儿童青少年学习用品近视防控卫生要求》&#xff08;GB 40070-2021&#xff09;规定了与近视防控相关的读写作业台灯卫生要求。台灯应该买什么样的才能护眼&#xff1f;要求从照度、均匀度、显色指数、色温、防蓝光等方面去完善护眼台灯&…

如何利用 Go 语言开发高可用服务

高可用的含义是尽量减少服务的不可用&#xff08;日常维护或者突发系统故障&#xff09;时长&#xff0c;提升服务的可用时长。如何衡量一个服务的可用性呢&#xff1f;或许你也听说过&#xff0c;通常企业可能会要求服务的可用性能能够达到三个 9(也就是 99.9%)或者 4个 9 &am…

手机三要素验证API接口,选择的时候应该注意什么?

在选择手机三要素验证API接口时&#xff0c;为了确保接口的安全性、可靠性和适用性&#xff0c;需要注意以下几个方面&#xff1a; 服务商的合法性和资质 合法性&#xff1a;确保服务商具有合法的经营资质和业务范围&#xff0c;以避免法律风险。 资质认证&#xff1a;查看服务…

运维的理解、定位及其在现代企业中的重要性

在当今数字化转型的大潮中&#xff0c;运维&#xff08;Operation & Maintenance, O&M&#xff09;作为企业IT架构中不可或缺的一环&#xff0c;其角色与职责正经历着深刻的变革。运维不再仅仅是技术层面的支持与维护&#xff0c;而是逐渐演变为一种集技术支持、业务服…

ORM框架:Mybatis与Hibernate

认识ORM ORM, Object-Relationl Mapping&#xff0c;对象关系映射。它的作用是在关系型数据库和对象之间作一个映射。 可以在对象模型和关系型数据库的表之间建立一座桥梁&#xff0c;程序员使用 API 直接操作 JavaBean 对象就可以实现数据的存储、查询、更改和删除等操作。 常…

okhttp异步请求连接阻塞问题排查

表现&#xff1a; 使用okhttp请求外部大模型接口时&#xff0c;当并发在2-5左右&#xff0c;出现请求被阻塞在建立http连接之前&#xff0c;阻塞时间超长&#xff08;>20s&#xff0c;从日志看有160s存在&#xff09;。但是httpconfig的connTimeout时间配置为100s&#xff…

在线客服系统PHP源码免费开源 (搭建教程+全新UI)

安装环境 宝塔面板 php>8.0 mysql5.7 安装搭建 1.建站点 上传程序 2.建数据库 导入数据 3.网站目录/public 伪静态设置 4.修改数据库配置信息 5.修改config.js里的配置信息 6.启动wokerman命令 更详细的搭建教程请下载源码根目录下 安装教程.docx 产品亮点: …

综合评价 | 基于层次-熵权-变异系数-正态云组合法的综合评价模型(Matlab)

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 综合评价 | 基于层次-熵权-变异系数-正态云组合法的综合评价模型&#xff08;Matlab&#xff09; AHP层次分析法是一种解决多目标复杂问题的定性和定量相结合进行计算决策权重的研究方法。该方法将定量分析与定性分析…

生信之家:生物信息学爱好者的温馨交流与科研合作社区

介绍 在生物信息学这个迅速发展的领域&#xff0c;交流与合作显得尤为重要。生信之家正是为此而生的&#xff0c;它是一个专为生物信息学研究人员、学生以及爱好者打造的在线社区。在这里&#xff0c;用户可以分享知识、讨论技术、寻找解决方案&#xff0c;并与来自全球的同行…

页面卡顿检测方案

引言 卡顿现象在早期的开发项目中是一个非常值得注意的问题。随着应用功能的不断增加&#xff0c;代码复杂度也在不断提升&#xff0c;特别是在较为低端的机型上&#xff0c;稍有不慎就可能引发卡顿现象。虽然近年来新发布的设备性能显著提升&#xff0c;但卡顿问题仍然不容忽…

kettle定时发送邮件功能怎样集成到系统中?

kettle定时发送邮件的配置步骤&#xff1f;如何设置kettle发信&#xff1f; kettle不仅能够及时通知相关人员数据处理的状态&#xff0c;还能确保系统的自动化和高效运作。AokSend将详细探讨如何将kettle定时发送邮件功能无缝集成到系统中&#xff0c;让您的数据处理流程更加智…

idea2024设置中文

今天下载idea2024.2版本&#xff0c;发现已经装过中文插件&#xff0c;但是还是不显示中文&#xff0c;找了八天原来还需要设置中文选项 方案一 点击文件 -> 关闭项目 点击自定义 -> 选择语言 方案二 点击文件 -> 设置 外观与行为 -> 系统设置 -> 语言和地区…

C语言迷宫制造

目录 开头程序程序的流程图程序的效果我推荐要制造的迷宫下一篇博客要讲的东西 开头 大家好&#xff0c;我叫这是我58。 程序 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <stdlib.h> #include <string.h> void printmaze(const cha…