QT 学习笔记(九)

news2025/5/19 17:09:57

文章目录

  • 一、事件的接收和忽略
    • 1. 准备工作
    • 2. 接收和忽略
  • 二、event() 函数
    • 1. 简介
    • 2. 实例演示
    • 3. 总结
  • 三、事件过滤器
  • 四、总结(细看)
    • 1. 知识点汇总
    • 2. QT 的事件处理
  • 五、事件、事件的接收和忽略、event() 函数和事件过滤器代码
    • 1. 主窗口头文件 mywidget.h
    • 2. 主窗口源文件 mywidget.cpp
    • 3. 标签头文件 mylabel.h
    • 4. 标签源文件 mylabel.cpp
    • 5. 按钮头文件 mybutton.h
    • 6. 按钮源文件 mybutton.cpp

由于每次代码都是在原有程序上修改,因此除了新建项目,不然一般会在学完后统一展示代码。
提示:具体项目创建流程和注意事项见QT 学习笔记(一)
提示:具体项目准备工作和细节讲解见QT 学习笔记(二)

一、事件的接收和忽略

  • 在上文的代码基础上继续进行操作。QT 学习笔记(八)

1. 准备工作

  • 在 ui 界面新建一个按钮,在项目文件当中新建一个 mybutton 的 C++ 类。
  • 将 ui 界面的按钮提升为 mybutton 。自定义控件提升详见QT 学习笔记(七)。
  • 在 主窗口源文件 mywidget.cpp 当中对按钮进行操作,对基本功能进行测验。
  • 注意:要在项目文件 day8.pro 当中添加 CONFIG +=C++11 才可以使 connect 功能正常实现。
    在这里插入图片描述
  • 当我们点击按钮时,会在输出窗口输出按钮被按下,如下图所示:
    在这里插入图片描述

2. 接收和忽略

  • 在上一步的检测操作完成后,在按钮源文件 mybutton.cpp 当中,进行事件的接收和忽略操作。
  • 通过 if 语句,对鼠标左键按下在输出窗口输出按下的是左键,对其他鼠标按键不做处理,调用原函数。
  • 在上述操作当中,鼠标左键对应的就是事件的接收其他按键对应的就是事件的忽略
    在这里插入图片描述
  • 在这里有一个问题,当我们按下鼠标左键时,会输出按下的是左键,但当我们按下其他按键时,并没有调用原函数,即输出按钮被按下。
  • 这是因为当我们按下鼠标左键的时候,事件的信号被 qDebug() 输出语句给拦截了,不会再向后传递,无法走到 else 对应的内容。
  • 因此,在我们编写代码时,事件的忽略不要编写实现代码即可
  • 事件的接收,就不会往下传递。
  • 事件的忽略,事件会继续往下传递。
  • 我们可以把 QT 的事件传递看成链状:如果子类没有处理这个事件,就会继续向其父组件传递。
  • QT 的事件对象有两个函数:accept() 和 ignore() 。
  • accept() 用来告诉 QT,这个类的事件处理函数想要处理这个事件;
  • 如果一个事件处理函数调用了一个事件对象的 accept() 函数,这个事件就不会被继续传播给其父组件。
  • ignore() 用来告诉 QT,这个类的事件处理函数不想要处理这个事件;
  • 如果调用了事件的 ignore() 函数,QT 会从其父组件中寻找另外的接受者。在事件处理函数中,可以使 isAccepted() 来查询这个事件是不是已经被接收了。
  • 我们在主窗口 myWidget.cpp 中,重写鼠标点击事件,每当鼠标按下的时候,输出 ++++++++++,同时,将按钮窗口 mybutton.cpp 当中的 e->ignore() 注释掉,得到如下现象:
    在这里插入图片描述
  • 这样操作并不会输出 ++++++++++。此时,我们取消按钮窗口 mybutton.cpp 当中的 e->ignore() 的注释,得到下面的现象:
    在这里插入图片描述
  • 当我们点击按钮的时候,会同时输出按下的是左键和 ++++++++++,当我们点击按钮外的界面时,只会输出 ++++++++++。
  • 这是因为没有接收到信号,所以没有触发那里的 e->ignore()。而这里的 e->ignore() 可以让这个信号再次传递下去,不过不是传递给 mybutton,而是 父组件 mywidget。
  • 这个 e->ignore() 主要使用在关闭项目当中,也就是窗口右上角大家熟知的红色关闭按钮,在此简单实现一下(只展示实现现象,具体代码会在总体代码当中展示)。
  • 在我们实际关闭窗口的时候,往往会弹出一句 确定关闭吗? 这种类似的提示。
  • 为了实现这样的功能,需要包含头文件 QMessageBox ,使用 question() 函数。question() 函数中的第一个参数是指定父对象,第二个参数是标题,第三个参数是提示内容,第四个参数不写的话默认有两个按钮:yes 和 no 。
  • 为实现功能,只需要一个简单 if 语句即可,如果点击 yes ,则处理关闭窗口事件,接收事件,事件就不会再往下传递;如果点击 no ,则忽略事件,事件继续给父组件传递。
  • 具体现象如下图所示:
    在这里插入图片描述

二、event() 函数

1. 简介

  • 事件对象创建完毕后,QT 将这个事件对象传递给 QObject 的 event() 函数。event() 函数并不直接处理事件,而是将这些事件对象按照它们不同的类型,分发给不同的事件处理器(event handler)。
  • 因此,event() 函数主要用于 事件的分发。所以,如果你希望在事件分发之前做一些操作,就可以重写这个 event() 函数了。
  • 例如,我们希望在一个 QWidget 组件中监听 tab 键的按下,那么就可以继承 QWidget,并重写它的 event() 函数,来达到这个目的。
  • 事件分发如下图所示。
    在这里插入图片描述
  • 与其他的事件返回值不同的是,event() 事件的返回值是 bool 类型。
  • 如果传入的事件已被识别并且处理,则需要返回 true,否则返回 false。如果返回值是 true,那么 QT 会认为这个事件已经处理完毕,不会再将这个事件发送给其它对象, 而是会继续处理事件队列中的下一事件。
  • 在 event() 函数中,调用事件对象的 accept() 和 ignore() 函数是没有作用的,不会影响到事件的传播。
  • 相当于在所有信号接收前进行一个检查,满足要求的停止工作,其他的继续原动作。

2. 实例演示

  • 在此以定时器为例,重写 event() 函数,使得定时器停止工作,其他部件保持原动作。代码和实现结果如下:
//重写event事件
bool myWidget::event(QEvent *e)
{
        if(e->type()==QEvent::Timer)
    {
        //干掉定时器
        //如果返回true,事件停止传播
        return true;
    }
    else
    {
        return QWidget::event(e);
    }
}

在这里插入图片描述

  • 将其恢复正常需要一个强制类型转换,只需在上述代码当中添加如下代码即可:
QTimerEvent *env = static_cast<QTimerEvent *>(e);
        timerEvent(env);
  • 正常现象如下图所示:

在这里插入图片描述

  • 我们在此继续进行一个按键 B 的 event() 函数重写,只有当我们按下按键 B 的时候,事件才继续,其他的事件均终止。代码和实现结果如下:
else if(e->type()==QEvent::KeyPress)
    {
        //类型转换
        QKeyEvent *env = static_cast<QKeyEvent *>(e);
        if(env->key()==Qt::Key_B)
        {
            return QWidget::event(e);
        }
        return true;
    }

在这里插入图片描述

3. 总结

  • QTimerEvent() 和 QKeyEvent() 这样的函数,就是前面所说的事件处理器 event handler。
  • event() 函数中实际是通过事件处理器来响应一个具体的事件。这相当于 event() 函数将具体事件的处理“委托”给具体的事件处理器。而这些事件处理器是 protected virtual 的,因此,我们重写了某一个事件处理器,即可让 QT 调用我们自己实现的版本。
  • event() 是一个集中处理不同类型的事件的地方。如果你想重写一大堆事件处理器,就可以重写这个 event() 函数,通过 QEvent::type() 判断不同的事件。由于重写 event() 函数需要十分小心注意父类的同名函数的调用,一不留神就可能出现问题。
  • 因此,一般只重写事件处理器(当然,也必须记得是不是应该调用父类的同名处理器)。这其实也表明了 event() 函数的另外一个作用:屏蔽掉某些不需要的事件处理器

三、事件过滤器

  • 很多时候,对象需要查看、甚至要拦截发送到另外对象的事件。例如,对话框可能想要拦截按键事件,不让别的组件接收到;或者要修改回车键的默认处理。
  • 通过前文,我们已经知道,QT 创建了 QEvent 事件对象之后,会调用 QObject 的 event() 函数处理事件的分发。显然,可以在 event() 函数中实现拦截的操作。由于 event() 函数是 protected 的,因此,需要继承已有类。如果组件很多,就需要重写很多个 event() 函数。这当然相当麻烦,更不用说重写 event() 函数还得小心一堆问题。
  • 因此,我们采用 QT 提供的另外一种机制来达到这一目的:事件过滤器。

在这里插入图片描述

  • QObject 有一个 eventFilter() 函数,用于建立事件过滤器。函数原型如下:
virtual bool QObject::eventFilter ( QObject * watched, QEvent * event );
  • 事件过滤器,可以理解成一种过滤代码。事件过滤器会检查接收到的事件。如果这个事件是我们感兴趣的类型,就进行我们自己的处理;如果不是,就继续转发。这个函数返回一个 bool 类型,如果你想将参数 event 过滤出来,比如,不想让它继续转发,就返回 true,否则返回 false。
  • 事件过滤器的调用时间是目标对象(也就是参数里面的 watched 对象)接收到事件对象之前。也就是说,如果你在事件过滤器中停止了某个事件,那么,watched 对象以及以后所有的事件过滤器根本不会知道这么一个事件。
  • 在实现事件过滤器之前,我们要在 ui 界面选取一个合适的标签,在这里选择的是 label_2 。 在选择完成后进行操作安装过滤器,该函数的参数是由哪个函数的父对象进行处理。
//安装过滤器
ui->label_2->installEventFilter(this);
  • 通过事件过滤器,将 label_2 ,转换为鼠标移动,并实时显示出对应的 x 和 y 坐标,其他事件保持不变。(鼠标按下和释放的整体流程与鼠标移动是相同的,按钮的操作方法和标签也是相同的,具体代码在汇总时展示)

在这里插入图片描述

  • 注意:事件过滤器和被安装过滤器的组件必须在同一线程,否则,过滤器将不起作用。如果在安装过滤器之后,这两个组件到了不同的线程,那么,只有等到二者重新回到同一线程的时候过滤器才会有效。

四、总结(细看)

1. 知识点汇总

  • QT 的事件是整个 QT 框架的核心机制之一。涉及到的函数众多,而处理方法也很多。
  • QT 中有很多种事件:鼠标事件、键盘事件、大小改变的事件、位置移动的事件等等。如何处理这些事件,实际有两种选择:
  • (1) 所有事件对应一个事件处理函数,在这个事件处理函数中用一个很大的分支语句进行选择。
  • (2) 每一种事件对应一个事件处理函数。QT 就是使用的这么一种机制:mouseEvent() ,keyPressEvent() 等。
  • QT 具有这么多种事件处理函数,肯定有一个地方对其进行分发,否则,QT 怎么知道哪一种事件调用哪一个事件处理函数呢?这个分发的函数,就是 event()。显然,当 QMouseEvent 产生之后, event() 函数将其分发给 mouseEvent() 事件处理器进行处理。
  • event() 函数会有两个问题:
  • (1) event() 函数是一个 protected 的函数,这意味着我们要想重写 event() ,必须继承一个已有的类。试想,我的程序根本不想要鼠标事件,程序中所有组件都不允许处理鼠标事件,是不是我得继承所有组件,一 一重写其 event() 函数?protected 函数带来的另外一个问题是,如果我基于第三方库进行开发,而对方没有提供源代码,只有一个链接库,其它都是封装好的。我怎么去继承这种库中的组件呢?
  • (2) event() 函数的确有一定的控制,不过有时候需求更严格一些:我希望那些组件根本看不到这种事件。event() 函数虽然可以拦截,但其实也是接收到了 QMouseEvent 对象。我连让它收都收不到。这样做的好处是,模拟一种系统根本没有那个事件的效果,所以其它组件根本不会收到这个事件,也就无需修改自己的事件处理函数。
  • 这两个问题是 event() 函数无法处理的。于是,QT 提供了另外一种解决方案:事件过滤器。事件过滤器给我们一种能力,让我们能够完全移除某种事件。事件过滤器可以安装到任意 QObject 类型上面,并且可以安装多个。如果要实现全局的事件过滤器,则可以安装到 QApplication 或者 QCoreApplication 上面。这里需要注意的是,如果使用 installEventFilter() 函数给一个对象安装事件过滤器,那么该事件过滤器只对该对象有效,只有这个对象的事件需要先传递给事件过滤器的 eventFilter() 函数进行过滤,其它对象不受影响。如果给 QApplication 对象安装事件过滤器,那么该过滤器对程序中的每一个对象都有效,任何对象的事件都是先传给 eventFilter() 函数。
  • 事件过滤器可以解决刚刚我们提出的 event() 函数的两点不足:
  • (1) 事件过滤器不是 protected 的,因此我们可以向任何 QObject 子类安装事件过滤器;
  • (2) 事件过滤器在目标对象接收到事件之前进行处理,如果我们将事件过滤掉,目标对象根本不会见到这个事件。

2. QT 的事件处理

  • QT 的事件处理,实际上是有五个层次:
  • (1) 重写 paintEvent() 、mousePressEvent() 等事件处理函数。这是最普通、最简单的形式,同时功能也最简单。
  • (2) 重写 event() 函数。event() 函数是所有对象的事件入口,QObject 和 QWidget 中的实现,默认是把事件传递给特定的事件处理函数。
  • (3) 在特定对象上面安装事件过滤器。该过滤器仅过滤该对象接收到的事件。
  • (4) 在 QCoreApplication::instance() 上面安装事件过滤器。该过滤器将过滤所有对象的所有事件,因此和 notify() 函数一样强大,但是它更灵活,因为可以安装多个过滤器。全局的事件过滤器可以看到 disabled 组件上面发出的鼠标事件。全局过滤器有一个问题:只能用在主线程。
  • (5) 重写 QCoreApplication::notify() 函数。这是最强大的,和全局事件过滤器一样提供完全控制,并且不受线程的限制。但是全局范围内只能有一个被使用(因为 QCoreApplication 是单例的)。

五、事件、事件的接收和忽略、event() 函数和事件过滤器代码

1. 主窗口头文件 mywidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget>

namespace Ui {
class myWidget;
}

class myWidget : public QWidget
{
    Q_OBJECT

public:
    explicit myWidget(QWidget *parent = nullptr);
    ~myWidget();

protected:
    //键盘按下事件
    void keyPressEvent(QKeyEvent *);
    //计时器事件
    void timerEvent(QTimerEvent *);
    //重写鼠标点击事件
    void mousePressEvent(QMouseEvent *);
    //关闭事件
    void closeEvent(QCloseEvent *);
    //重写event事件
    bool event(QEvent *);
    //事件过滤器
    bool eventFilter(QObject *,QEvent *);

private:
    Ui::myWidget *ui;

    int timeid;
    int timeid2;
};

#endif // MYWIDGET_H

2. 主窗口源文件 mywidget.cpp

#include "mywidget.h"
#include "ui_mywidget.h"
#include <QDebug>
#include <QKeyEvent>
#include <QCloseEvent>
#include <QMessageBox>
#include <QEvent>

myWidget::myWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::myWidget)
{
    ui->setupUi(this);

    //启动计时器
    timeid = this->startTimer(1000);  //毫秒为单位。每隔1s触发一次定时器
    timeid2 = this->startTimer(500);  //毫秒为单位。每隔0.5s触发一次定时器

    connect(ui->pushButton,&mybutton::clicked,
            [=]()
    {
        qDebug()<<"按钮被按下";
    }
            );

    //安装过滤器
    ui->label_2->installEventFilter(this);
    //设置鼠标追踪
    ui->label_2->setMouseTracking(tr);
}

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

//键盘按下事件
void myWidget::keyPressEvent(QKeyEvent *e)
{
    qDebug()<<(char)e->key();
    if(e->key()==Qt::Key_A)
    {
        qDebug()<<"Qt::Key_A";
    }
}

//计时器事件
void myWidget::timerEvent(QTimerEvent *e)
{
    if(e->timerId()==this->timeid)
    {
        static int sec = 0;
        ui->label->setText(
            QString("<center><h1>time out:%1</h1></center>").arg(sec++)
               );

        //停止计时器
        /*if(5==sec)
        {
            this->killTimer(this->timeid);
        }    */
    }
    else if (e->timerId()==this->timeid2)
    {
        static int sec = 0;
        ui->label_2->setText(
            QString("<center><h1>time out:%1</h1></center>").arg(sec++)
               );

        //停止计时器
        /*if(5==sec)
        {
            this->killTimer(this->timeid);
        }    */
    }
}

//重写鼠标点击事件
void myWidget::mousePressEvent(QMouseEvent *e)
{
    qDebug()<<"++++++++++";
}

//重写鼠标点击事件
void myWidget::closeEvent(QCloseEvent *e)
{
    int ret = QMessageBox::question(this,"question","是否需要关闭窗口");
    //question 第一个参数是指定父对象,第二个参数是标题,
    //第三个参数是提示内容,第四个参数不写的话默认有两个按钮:yes和no。
    if(ret==QMessageBox::Yes)
    {
        //关闭窗口
        //处理关闭窗口事件,接收事件,事件就不会再往下传递
        e->accept();
    }
    else
    {
        //不关闭窗口
        //忽略事件,事件继续给父组件传递
        e->ignore();
    }
}

//重写event事件
bool myWidget::event(QEvent *e)
{
    if(e->type()==QEvent::Timer)
    {
        //干掉定时器
        //如果返回true,事件停止传播
        //QTimerEvent *e
        //QTimerEvent *env = static_cast<QTimerEvent *>(e);
        //timerEvent(env);
        return true;
    }
    else if(e->type()==QEvent::KeyPress)
    {
        //类型转换
        QKeyEvent *env = static_cast<QKeyEvent *>(e);
        if(env->key()==Qt::Key_B)
        {
            return QWidget::event(e);
        }
        return true;
    }
    else
    {
        return QWidget::event(e);
    }
}

//事件过滤器
bool myWidget::eventFilter(QObject *obj,QEvent *e)
{
    if(obj==ui->label_2)
    {
        //类型转换
        QMouseEvent *env=static_cast<QMouseEvent *>(e);
        //判断事件
        if(e->type()==QEvent::MouseMove)
        {
            ui->label_2->setText
                    (QString("mouse move:(%1,%2)").arg(env->x()).arg(env->y()));
            return true;
        }
        else
        {
            return QWidget::eventFilter(obj,e);
        }
    }
    else
    {
        return QWidget::eventFilter(obj,e);
    }
}

3. 标签头文件 mylabel.h

#ifndef MYLABEL_H
#define MYLABEL_H

#include <QLabel>

class mylabel : public QLabel
{
    Q_OBJECT
public:
    explicit mylabel(QWidget *parent = nullptr);

protected:
    //鼠标点击事件
    void mousePressEvent(QMouseEvent *ev);
    //鼠标释放事件
    void mouseReleaseEvent(QMouseEvent *ev);
    //鼠标移动事件
    void mouseMoveEvent(QMouseEvent *ev);
    //进入窗口区域
    void enterEvent(QEvent *);
    //离开窗口区域
    void leaveEvent(QEvent *);

signals:

public slots:
};

#endif // MYLABEL_H

4. 标签源文件 mylabel.cpp

#include "mylabel.h"
#include <QMouseEvent>

mylabel::mylabel(QWidget *parent) : QLabel(parent)
{

}

//鼠标点击事件
void mylabel::mousePressEvent(QMouseEvent *ev)
{
    int i=ev->x();
    int j=ev->y();
    //sprinf 字符串格式化命令
    /*
     * QString str = QString("abc %1 ^_^ %2").arg(123).arg("mike");
     * str = abc 123 ^_^ mike
    */

    QString text = QString("<center><h1>mouse press:(%1,%2)</h1></center>")
            .arg(i).arg(j);
    // center 居中,h1 一级标题
    this->setText(text);
}

//鼠标释放事件
void mylabel::mouseReleaseEvent(QMouseEvent *ev)
{
    QString text = QString("<center><h1>mouse release:(%1,%2)</h1></center>")
            .arg(ev->x()).arg(ev->y());
    this->setText(text);
}

//鼠标移动事件
void mylabel::mouseMoveEvent(QMouseEvent *ev)
{
    QString text = QString("<center><h1>mouse move:(%1,%2)</h1></center>")
            .arg(ev->x()).arg(ev->y());
    //this->setText(text);
}

//进入窗口区域
void mylabel::enterEvent(QEvent *e)
{
    QString text = QString("<center><h1>mouse enter</h1></center>");
    this->setText(text);
}

//离开窗口区域
void mylabel::leaveEvent(QEvent *e)
{
    QString text = QString("<center><h1>mouse leave</h1></center>");
    this->setText(text);
}

5. 按钮头文件 mybutton.h

#ifndef MYBUTTON_H
#define MYBUTTON_H

#include <QPushButton>

class mybutton : public QPushButton
{
    Q_OBJECT
public:
    explicit mybutton(QWidget *parent = nullptr);

protected:
    void mousePressEvent(QMouseEvent *e);

signals:

public slots:
};

#endif // MYBUTTON_H

6. 按钮源文件 mybutton.cpp

#include "mybutton.h"
#include <QMouseEvent>
#include <QDebug>

mybutton::mybutton(QWidget *parent) : QPushButton(parent)
{

}

void mybutton::mousePressEvent(QMouseEvent *e)
{

    if(e->button() == Qt::LeftButton)
    {
        //如果是左键按下
        qDebug()<<"按下的是左键";
        //事件接收后,就会往下传递

        e->ignore();
        //忽略,事件继续往下传递,事件传递给了父组件,不是给父类(基类)
    }
    else
    {
        //不做处理
        QPushButton::mousePressEvent(e);
        //事件的忽略,事件继续往下传递
    }
}

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

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

相关文章

英语文本转语音软件哪个好?分享三个新手也能学会的工具

大家平时都是怎么学习英语的呢&#xff1f;课上老师让我们熟悉单词意思、巩固语法、多练阅读理解&#xff1b;其实通过练习听力来加强语感也很重要。很多小伙伴的阅读理解很好&#xff0c;但是听力却跟不上。这里教大家一个小技巧&#xff0c;就是在做阅读理解的时候&#xff0…

第十章TomCat详解

文章目录Tomcat的部署和启动Tomcat扮演的角色①对外&#xff1a;Web服务器②对内&#xff1a;Servlet容器深入理解为什么需要TomCat从目的开始出发遇到的问题总过程部署前提解压TomCat的目录文件启动Tomcat并访问首页如何部署一个项目访问对应的web资源专业版IDEA创建一个JavaW…

力扣(718.1143)补9.12

718.最长重复子数组 这题真的想不到。 看图的话会好懂很多。 class Solution { public int findLength(int[] nums1, int[] nums2) { int nnums1.length; int n2nums2.length; int[][] dpnew int[n1][n21]; int result0; for(int…

【区块链-智能合约工程师】第二篇:Solidity入门

文章目录Solidity极简入门HelloWorld数值类型三种函数类型函数输出变量作用域引用类型参考文章&#xff1a;一文速览2022十大智能合约开发工具 资料地址&#xff1a;WTF学院 Solidity极简入门 HelloWorld remix&#xff1a;在线智能合约开发IDE&#xff08;Integrated Deve…

DBCO-PEG-Aminooxy, Aminooxy-PEG-DBCO,氨甲基聚乙二醇环辛炔

DBCO-PEG-Aminooxy &#xff0c; Aminooxy-PEG-DBCO&#xff0c;二苯并环辛炔-聚乙二醇-氨甲基&#xff0c;氨甲基聚乙二醇环辛炔 Product specifications&#xff1a; 1.CAS No&#xff1a;N/A 2.Molecular weightMV&#xff1a;1000&#xff0c;2000&#xff0c;34000&#x…

小侃设计模式(十八)-发布订阅模式

1.概述 发布订阅模式又叫观察者模式&#xff08;Observer Pattern&#xff09;&#xff0c;它是指对象之间一对多的依赖关系&#xff0c;每当那个特定对象改变状态时&#xff0c;所有依赖于它的对象都会得到通知并被自动更新&#xff0c;它是行为型模式的一种。观察者模式内部…

被吹爆的JVM笔记,一招教会什么是JVM调优,资深架构师强推!

面试经常被问 JVM 如何调优&#xff1f;这个问题该怎么回答&#xff1f;没有实际调优经验怎么办&#xff1f; 一般面试时问JVM调优&#xff0c;主要是因为&#xff0c;这个技术并不是懂了Java就能自然懂的&#xff0c;需要明白一些底层原理&#xff0c;有一些深度。所以比较适合…

传奇客户端文件介绍注解教程,GM必备知识

传奇客户端文件介绍注解教程&#xff0c;GM必备知识 很多朋友架设微端&#xff0c;或者说修改传奇版本素材方面的内容的时候对于客户端很懵逼&#xff01; 尤其是新手朋友他并不知道传奇客户端里面哪个文件是对应什么内容的&#xff01; 今天我们将这些发出来分享给支持奇速的朋…

高压放大器在IDE压电元件及其在仿生翼中的应用

实验名称&#xff1a;IDE压电元件及其在仿生翼中应用研究 研究方向&#xff1a;仿生学 测试目的&#xff1a; 优化IDE压电元件结构和组分出发&#xff0c;目的是为了获得大驱动位移、综合性能良好的IDE驱动件。着重研究IDE压电元件的力学和电学性能、驱动特性和在仿生翼上的集成…

LVGL学习笔记(一)--- 环境搭建

LVGL全程LittleVGL&#xff0c;是一个轻量化的&#xff0c;开源的&#xff0c;用于嵌入式GUI设计的图形库。并且配合LVGL模拟器&#xff0c;可以在电脑对界面进行编辑显示&#xff0c;测试通过后再移植进嵌入式设备中&#xff0c;可以高效地进行开发。 一.嵌入式设备的移植 L…

企业请体育冠军明星代言,为何要在年前邀请

行业形势好&#xff0c;要把握住消费升级的机会&#xff1b;行业调整时&#xff0c;要抓住结构性增长的机会。实力背书、冠军代言、让品牌成为品类创新&#xff0c;中小型这几个概念与品牌自身的卖点&#xff0c;每一个放在光中小型企业的品牌上都能独当一面&#xff0c;当一款…

C/C++ 内存分布---变量所在哪个内存区域以及变量所占空间大小是多少?

C/C内存区域划分&#xff1a; 变量所在哪个内存区域以及变量所占空间大小是多少&#xff1f; int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] { 1, 2, 3, 4 };char char2[] "abcd";const …

基于JavaFX+Mysql实现(PC)足球联赛评分系统【100010048】

一、引言 1. 编写目的 本文档是概要设计文档的组成部分&#xff0c;编写数据库设计文档的目的是&#xff1a;明确数据库的表名、字段名等数据信息&#xff0c;用来指导后期数据库脚本的开发。本文档的读者对象是需求人员、系统设计人员、开发人员、测试人员。 2. ### 术语表 …

GPT3动口,RT-1动手,智能机器人开卷; 代码开源!

机器学习 (ML) 研究的多个子领域&#xff08;例如计算机视觉和自然语言处理&#xff09;的最新重大进展是通过一种共享的通用方法实现的&#xff0c;该方法利用大型、多样化的数据集和能够有效吸收所有数据的表达模型。尽管已经有各种尝试将这种方法应于机器人技术&#xff0c;…

绘制雪夜圣诞树并封装为小程序

绘制雪夜圣诞树并封装为小程序 使用turtle绘制一颗雪夜圣诞树&#xff0c;然后封装成exe小程序送给你的朋友吧&#xff01; PS&#xff1a;只能在windows运行。 转载注明本文链接和作者 先看效果图&#xff1a; 绘制雪夜圣诞树 由于代码有三百多行&#xff0c;我放在下面的两…

Web前端105天-day45-DOM

DOM01 目录 前言 一、DOM 二、DOM树 三、class 总结 前言 DOM01学习开始 一、DOM DOM: Document Object Model 文档 : HTML代码 -- 超文本标记语言对象 : 网页真正显示的是 HTML 转换出来的 对象类型 -- document模型 : 固定的规则 -- 代表把 HTML代码 转 JS对象网页真…

Jmeter(十七):利用jmeter插件收集性能测试结果汇总报告和聚合报告,利用PerfMon插件收集监控服务器资源指标

利用jmeter插件收集性能测试结果 汇总报告&#xff08;Summary Report &#xff09; 用来收集性能测试过程中的请求以及事务各项指标。通过监听器--汇总报告 可以添加该元件。界面如下图所示 汇总报告界面介绍&#xff1a; 所有数据写入一个文件&#xff1a;保存测试结果到本地…

全产业链落实循环减碳实践 宝马在华持续推进绿色转型

作为率先推出“循环减碳”理念的汽车企业&#xff0c;宝马集团将循环经济理念贯彻到产品生命周期的各个阶段&#xff0c;并以“再思考、再精减、再利用、再回收”为指导原则&#xff0c;在产业链上下游不断壮大“循环减碳朋友圈”。“可持续发展是宝马集团的战略支点之一”&…

【爬虫】JS调试解决反爬问题系列1

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ &#x1f434;作者&#xff1a;秋无之地 &#x1f434;简介&#xff1a;CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作&#xff0c;主要擅长领域有&#xff1a;爬虫、后端、大数据…

AlibabaP8,耗时182天肝出来1015页分布式全栈手册

前言 到底什么是分布式&#xff1f;这个话题一直以来就在各大平台论坛上被热议。一千个读者里面就有一千个哈姆雷特。官方这边给出的结论是&#xff1a;分布式就是将相同或相关的程序运行在多台计算机上&#xff0c;从而实现特定目标的一种计算方式。而从分布式技术的起源来看…