QT从入门到实战x篇_22_番外1_Qt事件系统

news2024/11/14 11:33:25

文章目录

  • 1. Qt事件系统简介
    • 1.1 事件的来源和传递
    • 1.2 事件循环和事件分发
      • 1.2.1 QT消息/事件循环机制
        • 1.2.1.1 机制解释
        • 1.2.1.2 两个问题
      • 1.2.2 事件分发
  • 2. 事件过滤基础
    • 2.1 什么是事件过滤器(Event Filter)?
    • 2.2 如何安装事件过滤器
  • 3. 事件过滤实战
    • 3.1 创建自定义事件过滤器
    • 3.2 过滤不同类型的事件
    • 3.3 在多个对象之间共享事件过滤器
  • 4 高级应用
    • 4.1 使用事件过滤器实现拖放功能
    • 4.2 利用事件过滤器优化性能
  • 5 事件过滤的注意事项
    • 5.1 避免过度过滤
    • 5.2 确保事件的正确传递

比本篇好很多更多涉及底层的博文推荐: 【Qt 应用开发 】探索Qt事件处理时机:深入理解事件驱动机制

介绍清晰结构简洁的博文:Qt - QObject事件

以下部分来自:【Qt 元对象系统】深入探索Qt事件过滤:从基础到高级应用-CSDN博客、Qt事件系统:Qt中的事件处理与传递、Qt 事件机制、Qt之事件处理机制

1. Qt事件系统简介

在Qt中,事件(Event)是一个核心概念,它代表了应用程序的一个动作或发生的事情。事件可以是用户的输入,如鼠标点击或键盘按键,也可以是系统生成的,如窗口大小改变或定时器超时。

为了处理这些事件,Qt提供了一个事件循环(Event Loop)。这个循环不断地检查是否有新的事件发生,然后将这些事件发送给相应的对象进行处理。

事件(event)是由系统或者Qt本身在不同时刻发出的。当用户按下鼠标、敲下键盘,或者其它情况时候都会发出一个相应的事件。一些事件在对用户操作做出相应时发出,如键盘事件等;另外一些则是由系统自动发出,如计时事件等。

Qt程序需要在main()函数创建一个QApplication对象,然后调用它的exec()函数。这个函数就是开始Qt的事件循环。在执行exec()函数之后,程序将进入事件循环来监听应用程序的事件,当事件发生时,Qt将创建一个事件对象。Qt中所有事件类都继承自QEvent。在事件对象创建完毕之后,Qt将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是按照事件对象的类型分派给指定的事件处理函数(event handler)进行处理。

  • 事件和信号的区别

需要说明的是,事件与信号并不相同,比如单击一下界面上的按钮,那么就会产生鼠标事件 QMou­seEvent (不是按钮产生的 ),而因为按钮被按下了 ,所以它会发出 clicked() 单击信号(是按钮产生的)。这里一般只关心按钮的单击信号,而不用考虑鼠标事件,但是如果要设计一个按钮,或者当单击按钮时让它产生别的效果,那么就要关心鼠标事件了。可以看到,事件与信号是两个不同层面的东西,发出者不同,作用也不同。在 Qt 中,任何 QObject 子类实例都可以接收和处理事件。摘自:[Qt事件系统:Qt中的事件处理与传递_事件处理系统对于每个学习qt人来说非常重要,可以说,qt是以事件驱动的ui工具集。 大-CSDN博客](Qt事件系统:Qt中的事件处理与传递_件处理系统对于每个学习qt人来说非常重要,可以说,qt是以事件驱动的ui工具集。 大-CSDN博客)

Qt的事件很容易和信号槽混淆。signal由具体对象发出,然后会马上交给由connect函数连接的slot进行处理;

而对于事件,Qt使用一个事件队列对所有发出的事件进行维护,当新的事件产生时,会被追加到事件队列的尾部,前一个事件完成后,取出后面的事件接着再进行处理。

但是,必要的时候,Qt的事件也是可以不进入事件队列,而是直接处理的。并且,事件还可以使用“事件过滤器”进行过滤。

比如一个按钮对象, 我们使用这个按钮对象的时候, 我们只关心它被按下的信号, 至于这个按钮如何接收处理鼠标事件,再发射这个信号,我们是不用关心的。

但是如果我们要重载一个按钮的时候,我们就要面对event了。 比如我们可以改变它的行为,在鼠标按键按下的时候(mouse press event) 就触发clicked()的signal而不是通常在释放的( mouse release event)时候。

总结的说,Qt的事件和Qt中的signal不一样。 后者通常用来使用widget, 而前者用来实现widget。 如果我们使用系统预定义的控件,那我们关心的是信号,如果自定义控件我们关心的是事件。摘自:Qt 事件机制

  • 事件的处理
    一个事件由一个特定的 QEvent 子类来表示,但是有时一个事件又包含多个事件类型,比如鼠标事件又可以分为鼠标按下、双击和移动等多种操作。这些事件类型都由 QEvent 类的枚举型 QEvent::Type 来表示,其中包含了 一百多种事件类型,可以在 QEvent 类的帮助文档中查看。虽然 QEvent 的子类可以表示一个事件,但是却不能用来处理事件,那么应该怎样来处理一个事件呢?在 QCoreApplication 类的 notify() 函数的帮助文档处给出了 5 种处理事件的方法:

    • 方法一:重新实现部件的 paintEvent()、mousePressEvent() 等事件处理函数。这是最常用的一种方法,不过它只能用来处理特定部件的特定事件。
    • 方法二:重新实现 notify() 函数。这个函数功能强大,提供了完全的控制,可以在事件过滤器得到事件之前就获得它们。但是,它一次只能处理一个事件。
    • 方法三:向 QApplication 对象上安装事件过滤器。因为一个程序只有一个 QApplication 对象,所以这样实现的功能与使用 notify() 函数是相同的,优点是可以同时处理多个事件。
    • 方法四:重新实现 event() 函数。QObject 类的 event() 函数可以在事件到达默认的事件处理函数之前获得该事件。
    • 方法五:在对象上安装事件过滤器。使用事件过滤器可以在一个界面类中同时处理不同子部件的不同事件。

在实际编程中,最常用的是方法一,其次是方法五。因为方法二需要继承自 QApplication 类;而方法三要使用一个全局的事件过滤器,这将减缓事件的传递,所以,虽然这两种方法功能很强大,但是却很少被用到。

1.1 事件的来源和传递

在Qt中,事件可以由多种来源生成,包括用户输入、系统事件或自定义事件。一旦事件被生成,它会被发送到一个事件队列(Event Queue)。事件循环会从队列中取出事件,并将其传递给适当的对象进行处理

事件的传递是一个层层递进的过程。首先,事件会被发送到最顶层的对象,如应用程序对象(QApplication)。如果这个对象没有处理该事件,它会继续传递给下一级的对象,如窗口或控件,直到找到一个可以处理该事件的对象为止。

这种事件传递的方式,很像我们在生活中面对决策时的思考过程。当遇到一个问题时,我们首先会尝试自己解决,如果不能解决,我们可能会寻求他人的帮助,直到问题得到解决。

在每个程序的 main() 函数的最后都会调用 QApplication 类的 exec() 函数,它会使 Qt 应用程序进人事件循环,这样就可以使应用程序在运行时接收发生的各种事件。一旦有事件发生,Qt 便会构建一个相应的 QEvent 子类的对象来表示,然后将它传递给相应的 QObject 对象或其子对象。下面通过例子来看一下 Qt 中的事件传递过程。

新建 Qt Gui 应用,项目名称为 myEvent,基类选择 QWidget,然后类名保持 Widget 不变。建立完成后向项目中添加新文件,模板选择 C++ 类,类名为 MyLineEdit,基类手动填写为 QLineEdit,自定义了一个 MyLineEdit 类。

mylineEdit. h 文件:

#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H
 
#include <QLineEdit>
 
class MyLineEdit : public QLineEdit
{
    Q_OBJECT
public:
    explicit MyLineEdit(QWidget *parent = nullptr);
    
    // event()函数获取事件的类型
	bool event(QEvent *event);    
 
protected:
    // MyLineEdit类的键盘按下事件
    void keyPressEvent(QKeyEvent *event);
};
 
#endif // MYLINEEDIT_H

这里添加了 keyPressEvent() 函数和 event() 函数的声明。

mylineEdit. cpp 文件:

#include "mylineedit.h"
#include <QKeyEvent>
#include <QDebug>
 
MyLineEdit::MyLineEdit(QWidget *parent) :
    QLineEdit(parent)
{
 
}
 
// MyLineEdit类的键盘按下事件
void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
    qDebug() << tr("MyLineEdit键盘按下事件");
    // 让MyLineEdit输入栏能输入字符
    QLineEdit::keyPressEvent(event);          // 执行QLineEdit类的默认事件处理
    event->ignore();                          // 忽略该事件
}
 
//event()函数获取事件的类型
bool MyLineEdit::event(QEvent *event)  
{
    // 判断触发事件类型是否为键盘按下事件
    if(event->type() == QEvent::KeyPress)
        qDebug() << tr("MyLineEdit的event()函数");
    return QLineEdit::event(event);   // 执行QLineEdit类event()函数的默认操作
}

这里自定义了一个 MyLineEdit 类,它继承自 QWidget,并且实现了 MyLineEdit 类的 keyPressEvent() 函数和 event() 函数。event() 函数中使用了 event->type() 来获取事件的类型。如果是键盘按下事件 QEvent::KeyPress,则输出信息,另外返回父类的 event() 函数的操作结果。

widget.h 文件:

#ifndef WIDGET_H
#define WIDGET_H
 
#include <QWidget>
class MyLineEdit;
namespace Ui {
class Widget;
}
 
class Widget : public QWidget
{
    Q_OBJECT
 
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
 
	// Widget类的事件过滤器
    bool eventFilter(QObject *obj, QEvent *event);    
 
private:
    Ui::Widget *ui;
    MyLineEdit *lineEdit;
 
protected:
    // Widget类的键盘按下事件
    void keyPressEvent(QKeyEvent *event);
};
 
#endif // WIDGET_H

这里也添加了keyPressEvent()函数的声明。

widget.cpp 文件:

#include "widget.h"
#include "ui_widget.h"
#include "mylineedit.h"
#include <QKeyEvent>
#include <QDebug>
 
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
        
    lineEdit = new MyLineEdit(this);
    lineEdit->move(100, 100);
}
 
Widget::~Widget()
{
    delete ui;
}
 
// Widget类的键盘按下事件
void Widget::keyPressEvent(QKeyEvent *event)
{
    qDebug() << tr("Widget键盘按下事件");
}
 
// Widget类的事件过滤器
bool Widget::eventFilter(QObject *obj, QEvent *event) // 事件过滤器
{
    // 如果是lineEdit部件上的事件
    if(obj == lineEdit)
    {              
        if(event->type() == QEvent::KeyPress)
            qDebug() << tr("Widget的事件过滤器");
    }
    return QWidget::eventFilter(obj, event);
}

这里也实现了 Widget 类的 keyPressEvent() 函数,并且会调用 MyLineEdit 类的 keyPressEvent() 函数。在事件过滤器中,先判断该事件的对象是不是 lineEdit,如果是,再判断事件类型,最后返回 QWidget 类默认的事件过滤器的执行结果。

运行程序,然后按下键盘的任意键,比如这里按下 a 键,执行结果如下图所示。
在这里插入图片描述

可以看到,事件的传递顺序是这样的:先是事件过滤器,然后是焦点部件的 event() 函数,最后是焦点部件的事件处理函数,例如这里的键盘按下事件函数;如果焦点部件忽略了该事件,那么会执行父部件的事件处理函数,如上图所示。注意,event() 函数和事件处理函数,是在该部件内进行重新定义的,而事件过滤器却是在该部件的父部件中进行定义的。
在这里插入图片描述

1.2 事件循环和事件分发

1.2.1 QT消息/事件循环机制

事件循环是Qt事件处理的核心。它不断地检查事件队列,看是否有新的事件需要处理。一旦有事件,事件循环会将其取出,并通过事件分发(Event Dispatching)将其发送给适当的对象。

Qt作为一个可视化GUI界面操作系统,是基于事件驱动的,我们程序执行的顺序不再是线性的,而是由一个个应用程序内部或外部的事件进行驱动的,无事件时便阻塞。这个有点类似于while循环,函数体内不断处理用户的输入,类比到事件循环中,用户点击了鼠标,按下了键盘,便称为事件。
  一般对于带UI窗口的程序来说,“事件”是由操作系统或程序框架在不同的时刻发出的。当用户按下鼠标,敲下键盘,或是窗口需要重新绘制的时候,或是计时器触发的时候,都会发出一个相应的事件。下面是一个抽象的“循环事件”的代码:

 1 function eventloop()
 2 {
 3     initialize();
 4     bool shouldQuit = false;
 5     whlie (false == shouldQuit)
 6     {
 7         var message = get_next_message();
 8         process_message(message);
 9         if (message == QUIT)
10         {
11             shouldQuit = true;
12         }
13     }
14 }
1.2.1.1 机制解释

这样的程序运行流程,叫做“事件驱动”式的程序。一般的Qt程序,main函数中都会有一个QCoreApplication/QGuiApplication/QApplication,并在末尾调用exec。Application中的这个EventLoop,叫做“事件循环”,所有的事件分发、事件处理都从这里开始。

Application还提供了sendEvent和poseEvent两个函数,分别用来发送事件。sendEvent发出的事件会立即被处理,即“同步”执行。poseEvent发送的事件会被加入事件队列,在下一轮事件循环时才处理,即“异步”执行。

1.2.1.2 两个问题

(1) Qt是事件驱动的,怎么理解这句话
  Qt将系统产生的信号(软件中断)转换成Qt事件,并且将事件封装成类,所有的事件类都是由QEvent派生的,事件的产生和处理就是Qt程序的主轴,且伴随整个程序的运行周期。因此说Qt是事件驱动的。

QT将系统产生的消息转化为QT事件,QT事件被封装为对象,所有的QT事件均继承抽象类QEvent,用于描述程序内部或外部发生的动作,任意的QObject对象都具备处理QT事件的能力。

在这里插入图片描述

(2) Qt事件由谁产生的?
  事件有两个来源:程序内部和程序外部,多数情况下来自操作系统并且通过spontaneous()函数返回true来获知事件来自程序外部,当spontaneous()函数返回false时说明事件来自程序内部。

####1.2.1.2 Qt事件处理流程

事件循环:事件是一个类对象,具有特定的类型,多数情况下是被分发到一个队列中(事件队列),当队列中有事件时就不停地将队列中的事件发送给QObject对象,当队列为空时,就阻塞地等待事件。

在这里插入图片描述

QCoreApplication::exec()开启了这种循环,一直到QCoreApplication::exit()被调用才终止,所以说事件循环是伴随着Qt程序的整个运行周期。
另外一种同步处理情形是通过sendEvent()将事件发送出去,直接进入事件的传送和处理流程。

在这里插入图片描述

1.2.2 事件分发

事件分发是事件循环的一个重要环节。当事件被取出后,它需要被分发到正确的对象进行处理。Qt提供了一个事件分发器(QEventDispatcher)来完成这个任务。事件分发器会根据事件的类型和目标对象,将事件发送到正确的处理函数中。

要理解事件分发的底层原理,我们需要深入Qt的源码。在Qt的源码中,QEventDispatcher类负责事件的分发。当一个事件被取出时,QEventDispatcher会首先检查该事件的类型,然后根据事件的类型,调用相应的处理函数。

例如,当一个鼠标点击事件被取出时,QEventDispatcher会调用mousePressEvent()函数进行处理。这确保了每种事件都能被正确处理。

事件类型处理函数
鼠标点击mousePressEvent()
键盘输入keyPressEvent()
窗口大小改变resizeEvent()

2. 事件过滤基础

在深入探讨Qt的事件过滤机制之前,我们首先要理解为什么我们会选择某种编程方式。人们在面对问题时,往往会寻找最直观、最简单的方法来解决。这与我们的大脑对于复杂性的处理方式有关。我们的大脑会自动寻找模式,并尝试将新的信息与已知的模式相匹配,以减少认知负担。

2.1 什么是事件过滤器(Event Filter)?

事件过滤器(Event Filter)是Qt事件处理系统中的一个核心组件。它允许开发者在事件被传递给目标对象之前,对其进行拦截和处理。这种机制为我们提供了一个强大的工具,使我们能够在不修改目标对象的代码的情况下,对其行为进行定制。

从底层源码的角度看,当一个事件被发送或者发布时,它首先会被传递给安装在目标对象上的事件过滤器。如果事件过滤器选择处理这个事件,那么这个事件就不会再被传递给目标对象。反之,如果事件过滤器选择忽略这个事件,那么这个事件会继续被传递给目标对象。

这种机制的存在,使我们能够更加灵活地处理事件,而不需要修改已有的代码。

2.2 如何安装事件过滤器

在Qt中,安装事件过滤器是一个简单的过程。首先,你需要创建一个继承自QObject的类,并重写其eventFilter(QObject *watched, QEvent *event)方法。然后,你可以使用QObject::installEventFilter(QObject *filterObj)方法,将你的事件过滤器安装到任何QObject派生的对象上。

从底层原理的角度看,当你安装一个事件过滤器时,Qt会将这个过滤器添加到目标对象的内部事件过滤器列表中。当一个事件被发送到这个对象时,Qt会按照事件过滤器列表中的顺序,依次调用每一个事件过滤器的eventFilter方法。

为了帮助读者更好地理解事件过滤器的工作原理,我们可以从以下几个角度进行总结和对比:

角度事件过滤器常规事件处理
灵活性
代码侵入性
性能开销低至中

3. 事件过滤实战

3.1 创建自定义事件过滤器

当我们想要对特定的事件进行处理或拦截时,自定义事件过滤器(Event Filter)成为了一个非常有力的工具。例如,当用户点击一个按钮(Button)时,我们可能想要在底层捕获这个点击事件并进行一些特殊的处理。

首先,我们需要创建一个继承自QObject的类,并重写其eventFilter(QObject *watched, QEvent *event)方法。在这个方法中,我们可以根据event的类型进行相应的处理。

bool CustomEventFilter::eventFilter(QObject *watched, QEvent *event) {
    if (event->type() == QEvent::MouseButtonPress) {
        // 处理鼠标点击事件
    }
    return QObject::eventFilter(watched, event);
}

在这里,我们可以看到事件过滤的真正力量。我们可以在事件到达目标对象之前捕获并处理它。这种能力使我们能够在底层进行细致的控制,而不仅仅是在高级API上进行操作。

3.2 过滤不同类型的事件

Qt提供了多种事件类型,例如QEvent::KeyPressQEvent::MouseMove等。每种事件类型都与特定的用户交互行为相关联。为了更好地理解这些事件类型,我们可以从以下几个角度进行对比:

事件类型(Event Type)触发条件(Trigger Condition)常见应用(Common Use Case)
QEvent::KeyPress键盘按键被按下快捷键处理
QEvent::MouseMove鼠标移动拖放操作
QEvent::MouseButtonPress鼠标按钮被按下自定义点击行为

3.3 在多个对象之间共享事件过滤器

有时,我们可能希望在多个对象之间共享同一个事件过滤器。这可以通过将事件过滤器安装到多个对象上来实现。这种方法的优势在于,我们可以在一个中心位置处理所有相关的事件,而不是分散在多个地方。

但是,这也带来了一个挑战:如何区分事件的来源?答案是使用watched参数,它指示产生事件的对象。

bool CustomEventFilter::eventFilter(QObject *watched, QEvent *event) {
    if (watched == button1 && event->type() == QEvent::MouseButtonPress) {
        // 处理button1的点击事件
    } else if (watched == button2 && event->type() == QEvent::MouseButtonPress) {
        // 处理button2的点击事件
    }
    return QObject::eventFilter(watched, event);
}

在这里,我们使用了watched参数来确定事件的来源,并据此进行相应的处理。

当我们调用installEventFilter方法时,Qt内部会将事件过滤器添加到一个列表中。每当一个事件被分发到对象时,Qt都会首先检查这个对象是否有安装的事件过滤器。如果有,它会按照安装的顺序调用这些事件过滤器。

这种机制确保了事件过滤器总是在事件到达目标对象之前被调用,从而使我们能够在事件到达目标之前进行拦截或处理。

4 高级应用

4.1 使用事件过滤器实现拖放功能

拖放功能(Drag and Drop)是许多应用程序中常见的交互方式。在Qt中,实现这一功能需要对QDrag和QDropEvent有深入的了解。但为什么我们会选择拖放作为交互方式呢?这与人们对直观和简单的追求有关。拖放为用户提供了一种直观的方式来操作对象,而不需要通过复杂的命令或菜单。

从底层源码的角度看,当我们开始拖动一个对象时,QDrag对象会被创建,并开始监听鼠标的移动事件。当对象被放下时,QDropEvent会被触发,我们可以在事件过滤器中捕获这个事件,从而实现自定义的拖放逻辑。

4.2 利用事件过滤器优化性能

在Qt中,事件过滤器可以帮助我们优化性能。例如,我们可以通过事件过滤器拦截并忽略那些不必要的事件,从而减少事件处理的开销。

从底层原理的角度看,每当一个事件被发送到一个对象时,它都会经过事件过滤器。如果事件过滤器决定忽略这个事件,那么这个事件就不会被传递到目标对象,从而节省了处理事件的时间。

优化方法优点缺点
事件过滤减少不必要的事件处理可能会误拦截重要事件
代码优化提高代码执行效率需要深入了解算法和数据结构

事件过滤的工作原理
当我们安装了一个事件过滤器后,每当一个事件被发送到目标对象之前,它都会首先被发送到事件过滤器。事件过滤器可以决定是否继续传递这个事件,或者直接处理并结束这个事件。

这种机制为我们提供了一个在事件到达目标对象之前预处理事件的机会,从而实现更加灵活和高效的事件处理。

5 事件过滤的注意事项

5.1 避免过度过滤

在Qt中,事件过滤器(Event Filter)允许我们拦截并处理特定的事件。但是,过度使用事件过滤器可能会导致代码的复杂性增加,从而降低程序的性能。正如人们在面对信息过载时可能会感到困惑和疲惫,程序也可能因为处理大量不必要的事件而变得缓慢。

事件类型 (Event Type)处理方式 (Handling Method)是否推荐 (Recommendation)
鼠标事件 (Mouse Event)事件过滤器 (Event Filter)是 (Yes)
键盘事件 (Keyboard Event)事件过滤器 (Event Filter)否 (No)
自定义事件 (Custom Event)事件过滤器 (Event Filter)是 (Yes)

5.2 确保事件的正确传递

在Qt中,事件从发送者传递到接收者。如果事件没有被处理,它会继续传递给接收者的父对象。这种传递机制确保了事件能够被正确处理。但是,如果我们在事件过滤器中阻止了事件的传递,可能会导致某些功能无法正常工作。这就好像一个人在面对困难时选择逃避,而不是寻求帮助,最终可能会错过解决问题的机会。

在深入Qt的源码时,我们可以发现事件传递的核心逻辑是在QObject::event函数中实现的。这个函数确保了事件能够按照预定的顺序传递给各个对象。

事件传递的原理
当一个事件被发送时,它首先会被传递给目标对象的事件过滤器。如果事件过滤器没有处理这个事件,它会继续传递给目标对象的event函数。如果event函数也没有处理这个事件,它会继续传递给目标对象的父对象,直到事件被处理或传递到顶层对象。

这种事件传递的机制确保了事件能够被正确处理,同时也提供了灵活性,允许我们在不同的层级处理事件。

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

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

相关文章

深入探讨回流焊技术:电子制造业的核心工艺

在现代电子制造领域&#xff0c;回流焊技术被广泛认为是实现高效率和高质量电子组件装配的关键工艺之一。本文将针对回流焊的基本原理、设备构成、过程细节以及过程优化进行全面解析&#xff0c;为电子制造业的技术人员提供实用的参考和指导。 1. 回流焊基本原理解析 回流焊主…

【Redis 开发】(长篇学习)掌握Redis的用法,各种客户端下的操作

Redis 前言RedisRedis的安装Redis启动Redis客户端 Redis常见命令Redis的java客户端jedis学习简单的jedis 入门流程Jedis连接池 SpringDataRedisSpringDataRedis快速入门 前言 我们在作者之前的文章: 快速掌握Redis安装与基本语法的基础上进行系统的学习&#xff0c;学习自黑马…

Pytorch 之torch.nn初探 池化--Pooling Layers

任务描述 本关任务&#xff1a;本关提供了一个Variable 类型的变量x&#xff0c;要求按照条件创建一个Conv2d变量conv&#xff0c;一个MaxPool2d变量pool&#xff0c;对x应用卷积和最大池化操作并赋值给变量outpout_pool&#xff0c;并输出outpout_pool 的大小。 相关知识 P…

k8s日常动手实践 ~~ pod访问 pod请求 k8s api ~ 含新版带curl的busybox镜像

前言&#xff1a; 可以使用 Kubernetes API 获取集群信息。使用 Service Account&#xff08;SA&#xff09;进行身份验证&#xff0c;可以以安全的方式访问 Kubernetes API&#xff0c;而无需在 Pod 中使用明文凭据。 以下是一个使用 Service Account 访问 Kubernetes API 获…

XV6源码阅读——进程地址空间

文章目录 前言页表实际情况 前言 一个本硕双非的小菜鸡&#xff0c;备战24年秋招。打算尝试6.S081&#xff0c;将它的Lab逐一实现&#xff0c;并记录期间心酸历程。 代码下载 官方网站&#xff1a;6.S081官方网站 页表 每个进程都有一个单独的页表&#xff0c;当xv6在进程之…

数据库变更时,OceanBase如何自动生成回滚 SQL

背景 在开发中&#xff0c;数据的变更与维护工作一般较频繁。当我们执行数据库的DML操作时&#xff0c;必须谨慎考虑变更对数据可能产生的后果&#xff0c;以及变更是否能够顺利执行。若出现意外数据丢失、操作失误或语法错误等情况&#xff0c;我们必须迅速将数据库恢复到变更…

2024王鹍申论重难点:材料的概括与处理

2024王鹍申论重难点&#xff1a;材料的概括与处理&#xff0c;是备考公务员申论考试的关键一环。王鹍老师以其深厚的理论功底和丰富的实践经验&#xff0c;深入剖析了申论材料的特点和概括方法&#xff0c;同时传授了有效的材料处理技巧。通过王鹍老师的讲解&#xff0c;考生们…

Winseeing汇信外贸软件行业版,助力面辅料外贸公司实现降本增效

面辅料外贸出口&#xff0c;一直是国民经济发展中的重要组成部分。在当前全球贸易环境动荡不安的背景下&#xff0c;面辅料外贸出口面临着诸多挑战和机遇。亚洲是我面料出口的主要市场&#xff0c;据海关数据统计显示&#xff0c;2024年1-2月我对亚洲国家累计出口面料69.3亿美元…

leetcode多个测试用例之间相互影响导致提交失败

背景 在做一道easy题&#xff0c;二叉树的中序遍历&#xff0c;我提交的代码如下 from typing import (Optional,List )# Definition for a binary tree node. class TreeNode:def __init__(self, val0, leftNone, rightNone):self.val valself.left leftself.right right…

利用FCL实现更加精准的碰撞检测

一&#xff0c;需求 利用OSG结合FCL实现实现精准的碰撞检测。 二&#xff0c;效果 看这里 利用FCL实现更加精准的碰撞检测 – Qt hello 三&#xff0c;分析 我们看如下这张图&#xff0c;碰撞的逻辑就是&#xff0c;在一个三维场景中&#xff0c;构造一个实体&#xff0c;…

机器学习笔记(二)回归

一、线性回归 线性回归是一种用于预测的统计方法&#xff0c;特别适用于连续值预测。&#x1f4c8;线性回归通过最小化误差的平方和来寻找一个线性关系&#xff0c;用于预测一个变量&#xff08;因变量&#xff09;基于一个或多个其他变量&#xff08;自变量&#xff09;的值。…

远程控制安卓手机:便捷、高效与安全的方法

在移动设备的领域里&#xff0c;远程控制安卓手机的能力也变得越来越重要。这种技术可以让我们在远程地点方便地操作手机&#xff0c;无论是处理紧急事务、帮助他人解决问题&#xff0c;还是仅仅为了享受科技带来的便利。本文将为你介绍2种便捷、高效且安全的方法&#xff0c;让…

笔试狂刷--Day6(岛屿数量+模拟)

大家好,我是LvZi,今天带来笔试狂刷--Day6 一.在字符串中找出连续最⻓的数字串 1.题目链接 在字符串中找出连续最⻓的数字串 2.题目分析 使用双指针模拟 3.代码实现 import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {p…

Linux的学习之路:20、进程信号(2)

摘要 本章讲一下进程信号的阻塞信号和捕捉信号和可重入函数 目录 摘要 一、阻塞信号 1、阻塞信号 2、信号集操作函数 二、捕捉信号 1、内核如何实现信号的捕捉 2、代码实演 三、可重入函数 一、阻塞信号 1、阻塞信号 实际执行信号的处理动作称为信号递达(Delivery) …

文末送资料 | AI大模型接入指南:免费畅聊公众号新时代!附搭建教程

目录 今天内容有点意思&#xff01; 福利&#xff1a;拉到最后&#xff0c;免费送资料&#xff0c;你想要的全都有 我把公号接入了&#xff0c;字节跳动的云雀AI大模型&#xff01; 先给大家看几个案例 重点来了 如何将公号接入AI大模型呢&#xff1f; 1、创建AI聊天机器…

海南封关怎么看?win战略会任志雄解析

今年海南自由贸易港建设也进入了新阶段:将在2025年年底前适时启动全岛封关运作,封关后的海南将以全新姿态迎接更广泛的发展机遇。 封关在即,企业有何感受?还有哪些准备工作?封关后的海南将呈现怎样的状态?近日,红星资本局记者深入实地了解海南自贸港如何成型起势。 利好当…

快手不发作品ip地址会变吗

在数字时代&#xff0c;我们每个人的在线行为都留下了独特的痕迹。这些痕迹不仅仅是我们的言论或行为&#xff0c;还包括我们的IP地址——一个在网络世界中标识我们位置的数字标签。近年来&#xff0c;随着短视频平台的兴起&#xff0c;如快手这样的应用已经深入人们的日常生活…

sentinel-1.8.7与nacos-2.3.0实现动态规则配置、双向同步

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; sentinel-1.8.7与nacos-2.3.0实现动态规则配置、双向同步 ⏱️ 创作时…

2024年大数据应用、智能控制与软件工程国际会议(BDAICSE2024)

2024年大数据应用、智能控制与软件工程国际会议(BDAICSE2024) 会议简介 我们诚挚邀请您参加2024年大数据应用、智能控制和软件工程国际会议&#xff08;BDAICSE2024&#xff09;。这次会议将在美丽的长沙市举行。 本次大会旨在汇聚全球大数据应用、智能控制、软件工程等领…

常见大厂面试题(SQL)02

小鹏面试题: 小鹏汽车充电每辆车连续快充最大次数 原表charging_data idcharge_timecharge_typeXP10012023/11/20 8:45快充XP10012023/11/21 20:45快充XP10012023/11/22 8:45快充XP10012023/11/23 8:45慢充XP10012023/11/25 8:45快充XP10022023/11/25 8:45快充XP10022023/11/…