建设企业网站企业网银/百度浏览器在线打开

建设企业网站企业网银,百度浏览器在线打开,网站建设英文方案,网站排名做不上去浅谈Qt事件子系统——以可拖动的通用Widget为例子 这一篇文章是一个通过实现可拖动的通用Widget为引子简单介绍一下我们的事件对象子系统的事情 代码和所有的文档 1:Qt侧的API介绍和说明 ​ 这个是每一个小项目的惯例,我会介绍大部分Qt程序中使用到的…

浅谈Qt事件子系统——以可拖动的通用Widget为例子

这一篇文章是一个通过实现可拖动的通用Widget为引子简单介绍一下我们的事件对象子系统的事情
代码和所有的文档

1:Qt侧的API介绍和说明

​ 这个是每一个小项目的惯例,我会介绍大部分Qt程序中使用到的细节,比如说,本项目当中就是eventFilter和事件处理队列的Qt编程技术。这个也是我们编程Qt的一个重点。

​ 本项目打算介绍的是——Qt的事件处理机制,以及对象事件监听机制。如果您很熟悉了,可以考虑直接跳过本篇。

所以,Qt的事件处理机制

​ 我喜欢写一个东西的时候,直接说明我要写什么。很简单。

  • Qt是如何实现事件处理的?技术的要点有哪些?
  • 我们作为开发人员,重点关心的接口有哪些?
  • 如何监听,甚至是拦截其他对象的事件处理呢【这个是本项目的实现要点】

Qt是如何实现事件处理的

​ 毫无疑问,事件驱动处理是GUI的一个命根子,我们的GUI接受事件,展示对应的变化;同时我们的用户跟GUI交互,将用户的意图传递给我们的后台。这就是GUI的一个最大的要点。

所以,我们关心事件驱动的对象有哪些呢?

​ 我们的事件队列的处理主要依赖一个重要的概念,叫“事件循环”(Event Loop)。事件循环是一个持续运行的循环,它不断检测、分发并处理各种事件,包括用户输入(如键盘、鼠标事件)、系统消息以及自定义事件。主要过程大致如下:

  1. 事件产生:当用户操作或系统状态变化时,Qt会生成一个对应的事件对象(QEvent的子类实例)。
  2. 事件队列:事件对象被放入事件队列中等待处理。
  3. 事件分发:事件循环依次从队列中取出事件,分发给相应的对象处理。
  4. 事件响应:目标对象在其事件处理函数中对事件作出响应,更新界面或执行其他逻辑。

​ 我们分析事件,也是主要抓手这四个部分进行学习。

​ 我们事件队列处理的开始,在QApplication::exec上,调用这个,我们的全应用程序的事件队列就开始工作了。下面,我们来看看一些API函数:

​ 对于框架层次,你需要知道这员工的一些函数:

QCoreApplication::notify

Qt的事件分发机制主要依赖于QCoreApplication类中的notify()方法。每当一个事件需要传递给某个QObject对象时,都会经过该方法。其主要职责是:

  1. 统一调度:集中管理所有事件的发送和转发。
  2. 异常处理:对事件处理过程中可能出现的异常进行捕获和处理,保证整个事件循环的稳定性。
  3. 事件过滤:在正式分发事件前,提供预处理的机会(见下文的事件过滤机制)。

​ 我们一般不会跑去重写notify(至少笔者没见过特殊到要重写notify的)

事件队列与异步处理

Qt支持将事件异步投递到目标对象中,通过QCoreApplication::postEvent()方法将事件放入事件队列,等待事件循环处理。这种方式使得事件发送和处理解耦,避免在调用过程中产生阻塞,提升了系统响应能力。

与之对应的同步事件发送方式为QCoreApplication::sendEvent(),该方法直接调用目标对象的事件处理函数,在调用者线程中立刻执行。这种方式适用于对时序和结果有严格要求的情况,但需注意同步调用可能会引发递归调用或死锁问题。

事件循环(Event Loop)

每个Qt应用程序通常都有一个主事件循环,通过调用QCoreApplication::exec()启动。事件循环在不断地检测、分发和处理事件的同时,也会处理定时器、信号等异步任务。

  • 阻塞与非阻塞:事件循环既能阻塞等待事件,也能在无事件时进入休眠状态,保证资源利用率。
  • 嵌套事件循环:在某些对话框或模态窗口中,Qt会启动嵌套事件循环,保证界面依然响应用户操作。需要注意的是,嵌套循环可能会带来事件处理顺序和状态管理方面的复杂性。

讨论事件的类型

​ 事件事件,啥事件呢?这就是事件的类型。Qt中的所有事件都以QEvent为基类,其派生类涵盖了丰富的事件类型,如:

  • 用户输入事件:QMouseEvent、QKeyEvent、QWheelEvent等。
  • 窗口系统事件:QResizeEvent、QCloseEvent等。
  • 自定义事件:开发人员可以继承QEvent,定义属于自己的事件类型,实现特定业务逻辑的事件传递。

​ 这些事件呢,就在我们后面的开发接口上埋下了伏笔,所以,让我们马上进入第二个部分

开发人员关心的关键接口

​ 我们的一个大头中的大头,是QObject的一个重要的函数,或者说,QT元对象系统的一个重要的特化于事件处理的核心,就是我们的一个虚函数event(QEvent *event),这是所有事件最终处理的入口函数。每个QObject子类都可以重写这个函数,根据事件类型作出不同的响应。

​ 我们需要注意的是——event()函数并不直接处理事件,而是将这些事件对象按照它们不同的类型,**分发给不同的事件处理器(event handler)。**重写一个event事件,我们往往可能是要特化一部分操作。当然,往往我们的功能是——需要在原先拥有事件处理的基础上,进一步扩展通用事件处理的能力,比如说要做薄记,比如说统一的处理,这个时候重写event就是一个很明智的选择了!

​ 例如,在自定义控件中,可以重写event()函数,对特定事件(如鼠标点击、键盘输入)进行处理,从而实现自定义行为。当然!这只是一个例子,实际上没人这样写!我们会有专门的函数来处理,这是我们下面会提到的议题!

bool MyWidget::event(QEvent *event) {if (event->type() == QEvent::MouseButtonPress) {my_process_of_mouseEvent(event);return true;}// 调用基类的事件处理,保证其他事件正常分发return QWidget::event(event);
}

​ 你需要注意的是——请看,这里函数返回的是一个Bool值,这个bool值的含义是什么呢?答案是——当你返回了true的时候,就说明你的事件已经处理结束,Qt 将会检查这个函数的返回值,如果是true,说明这个事件已经被处理完成,会转而取事件队列的下一个进行预取,如果返回的是false,那么会继续把这个事件传递给其他的组件让他们接着处理

专用事件处理函数

为了简化事件处理,Qt为常见的事件提供了专用的虚函数,举个例子看看:

  • mousePressEvent(QMouseEvent *event):处理鼠标按下事件。
  • keyPressEvent(QKeyEvent *event):处理键盘按下事件。
  • resizeEvent(QResizeEvent *event):处理窗口尺寸变化事件。

这些函数通常在对应的控件类中重写,目的是对特定事件进行精细控制。需要注意的是,如果同时重写了event()函数和专用事件函数,则通常应保证事件在其中一个函数中得到完整处理,避免重复调用。这些在源码中的表先就是:判断事件的Type,然后依据事件的类型转发给对应的回调函数,就是这样简单!

事件发送接口

QCoreApplication::sendEvent()

同步事件发送接口sendEvent()直接调用目标对象的事件处理函数,并返回处理结果。这种方式适用于需要立即获得事件处理结果的情况。但由于它是在当前线程中执行的,因此要注意防止在事件处理过程中产生阻塞或递归调用。

QCoreApplication::postEvent()

异步事件投递接口postEvent()将事件放入目标对象所在线程的事件队列中,由事件循环在合适的时机进行分发。常见的应用场景包括跨线程通信、延迟处理等。由于postEvent()并不会立即调用事件处理函数,开发人员在设计逻辑时应考虑事件延时带来的影响。

自定义事件

在许多场景中,内置的事件类型无法满足特定需求,开发者可以通过继承QEvent来定义自定义事件。常见步骤如下:

  1. 定义新的事件类型(通常选用Qt::User 类型及之后的值)。
  2. 创建自定义事件类,包含特定数据和处理逻辑。
  3. 通过postEvent()或sendEvent()将自定义事件投递到目标对象中。
  4. 在目标对象的event()函数中进行识别和处理。

这种方式提供了极大的扩展性,使得复杂的应用逻辑可以通过事件机制进行模块化解耦。

事件过滤器

Qt还提供了事件过滤器机制,使得开发人员可以在事件传递前拦截、监控或修改事件。关键接口是QObject的installEventFilter(QObject *filterObj)eventFilter(QObject *watched, QEvent *event)函数。通过在某个对象上安装事件过滤器,过滤器对象可以提前捕获并处理目标对象的事件。

例如,在全局日志记录、调试或临时修改事件响应逻辑时,事件过滤器是一种非常有效的手段。下列代码展示了如何为一个窗口安装事件过滤器:

// 在构造函数中安装过滤器
myWidget->installEventFilter(this);// 重写eventFilter函数
bool MyClass::eventFilter(QObject *watched, QEvent *event) {if (watched == myWidget && event->type() == QEvent::KeyPress) {// 对键盘事件进行特殊处理qDebug() << "捕获到键盘事件";return true;  // 返回true表示事件已经被处理,不再传递}// 调用基类实现,确保其他事件可以正常传递return QObject::eventFilter(watched, event);
}

通过上述接口,开发者可以在不改动原有对象代码的前提下,实现对事件的监听和拦截。


如何监听和拦截其他对象的事件(本次文档的重点)

在实际开发中,经常需要对已有控件或对象的事件进行监听、修改甚至拦截。Qt提供了非常方便的事件过滤机制,使得这一需求得以高效实现。

​ 事件过滤器的核心在于:每个QObject对象都有一个内部列表,用于存储安装到该对象上的过滤器。当事件到达目标对象前,系统会先依次调用每个过滤器对象的eventFilter()方法。

  • 如果某个过滤器返回true,表示该事件已经被处理,后续的过滤器和目标对象本身将不再接收到此事件。
  • 如果所有过滤器都返回false,事件则继续传递给目标对象进行正常处理。

这种机制使得开发人员可以在不侵入原对象逻辑的情况下,对事件进行预处理,甚至阻断事件传递。

安装和使用事件过滤器

要实现对其他对象事件的监听和拦截,主要步骤如下:

  1. 编写过滤器类
    通常通过继承QObject并重写eventFilter()方法,编写自定义过滤器类。在该方法中,根据watched参数判断当前捕获的事件属于哪个对象,并根据事件类型进行处理。
  2. 安装过滤器
    在需要监控的对象上调用installEventFilter()方法,将自定义过滤器对象注册到该对象上。一个对象可以安装多个过滤器,调用顺序与安装顺序有关。
  3. 事件拦截与传递控制
    在eventFilter()中,当检测到感兴趣的事件后,可以选择返回true(表示事件已处理,不继续传递),也可以返回false(让目标对象继续处理)。

例如,假设我们需要拦截某个QLineEdit控件中的鼠标事件,可以这样实现:

class MyEventFilter : public QObject {Q_OBJECT
protected:bool eventFilter(QObject *watched, QEvent *event) override {if (watched->inherits("QLineEdit")) {if (event->type() == QEvent::MouseButtonDblClick) {// 拦截双击事件qDebug() << "QLineEdit双击事件被拦截";return true;  // 阻止事件继续传递}}// 其他情况继续传递事件return QObject::eventFilter(watched, event);}
};

在程序初始化时,为目标对象安装过滤器:

QLineEdit *edit = new QLineEdit(this);
MyEventFilter *filter = new MyEventFilter();
edit->installEventFilter(filter);

这样,当用户对该QLineEdit进行双击操作时,MyEventFilter将捕获并拦截该事件,而QLineEdit本身不会收到双击事件。

动态监听与跨对象事件监控

有时,我们不仅需要拦截单个对象的事件,还需要在全局范围内对多个对象进行统一监控。例如,在大型应用中调试或记录日志时,可以为整个应用安装一个全局事件过滤器。通常的做法是将过滤器安装在QCoreApplication对象上,这样所有事件都会先经过该过滤器的检测。

class GlobalEventFilter : public QObject {Q_OBJECT
protected:bool eventFilter(QObject *watched, QEvent *event) override {// 可以对所有对象和事件进行日志记录或特定处理qDebug() << "全局过滤器捕获到事件:" << event->type() << "来自对象:" << watched;// 根据需求选择是否拦截或继续传递return QObject::eventFilter(watched, event);}
};// 在main()函数中安装全局过滤器
int main(int argc, char *argv[]) {QApplication app(argc, argv);GlobalEventFilter *globalFilter = new GlobalEventFilter();app.installEventFilter(globalFilter);// 后续创建的所有对象的事件均会经过globalFilter的检测// …return app.exec();
}

这种全局过滤器的使用,尤其适用于调试阶段,对复杂交互过程中的事件进行全面记录和分析,或在某些特殊情况下统一拦截某类事件。

注意事项与最佳实践

​ 当然这里说一些重点的事情。在使用事件过滤器时,还需要注意以下几点:

  • 性能问题:全局事件过滤器会处理所有事件,因此在实现中要避免执行过于耗时的操作,防止影响界面响应。
  • 返回值控制:返回true表示事件被完全拦截,可能导致目标对象无法得到响应;返回false则允许事件继续传递。开发人员需要仔细判断实际需求。
  • 层次关系:如果一个对象安装了多个事件过滤器,事件会按照安装顺序依次经过各过滤器,过滤器之间可能存在相互影响,因此在设计时要考虑好先后次序。
  • 安全释放:当过滤器对象不再需要时,必须及时调用removeEventFilter()方法,或者在对象销毁时自动移除,避免悬挂指针问题。

本项目的实现的重要文档思路

​ 注意,这个文档可能不会跟我们的源码有一定保证的同步,只是提供一种参考!

如何让Widgets跟随鼠标移动呢

​ 一种办法,是让我们创建一个SubWidget,这个SubWidget负责一对一的维护一个目标控件。比如说一个按钮,或者是任何一个其他的控件,当我们的的目标事件传递到这个控件的时候,会优先的投射到我们的这个widgets上来。通过调用控件的 installEventFilter() 方法,将当前对象(this)作为过滤器安装到 holding_widget 上。安装事件过滤器后,该控件产生的所有事件都会首先传递到当前对象的 eventFilter() 方法中进行预处理。如果在 eventFilter() 中返回了 true,那么该事件就不会继续传递到控件自身的事件处理函数中;如果返回 false,则事件会继续传递。

​ 这样,我们就可以写自己的一个eventFilter来控制目标widget的行为。而不需要重载我们的对象添加一个Movable或者是其他任何的属性,这样看就会非常的方便。

​ 下面我们要做的就是准备处理我们的move行为

bool CCMovableWidget::eventFilter(QObject *watched, QEvent *event) {if (!holding_widget || watched != holding_widget) {return false;}QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent *>(event);if (!mouseEvent) {return false;}// here we handle the mouse events// this will promise the future extensionsswitch (event->type()) {case QEvent::MouseButtonPress:handling_mousePressEvent(mouseEvent);break;case QEvent::MouseButtonRelease:handling_mouseReleaseEvent(mouseEvent);break;case QEvent::MouseMove:handling_mouseMoveEvent(mouseEvent);break;default:break;}// back the default behaviorreturn QObject::eventFilter(watched, event);
}

​ 这是笔者的处理方式,依次对这个事件的MouseButtonPress,MouseButtonRelease和MouseMove进行了传递。这也就意味着这里它的事件就传递进来了进行了处理,当然处理结束后,我们还希望让它做进一步的处理,所以我们让他进一步维护其默认的实现。不要更改控件原来的行为。

剩下的内容

​ 剩下的内容就没什么新鲜的了,这里就让AI帮我代劳吧!

// widget is pressed by the mouse, so this means we shell start our moving
void CCMovableWidget::handling_mousePressEvent(QMouseEvent *event) {qDebug() << "Mouse pressed";if (!holding_widget)return; // no widget to hold, reject processif (accept_buttons.size() > 0 && !accept_buttons.contains(event->button()))return;                            // the button is not acceptable, reject processwidget_state.lastPoint = event->pos(); // memorize the last pointwidget_state.pressed   = true;
}

handling_mousePressEvent(QMouseEvent *event) 是用户按下鼠标时触发的事件处理函数,是整个拖动行为的起点。当鼠标点击到控件上时,首先通过日志输出来表明事件已经被捕获。接着,程序判断 holding_widget 是否存在,如果为空,则说明当前没有设置任何需要被移动的目标控件,因此直接返回,放弃此次操作。随后,如果开发者为这个类设定了一个特定可接受的鼠标按钮列表 accept_buttons,而当前触发事件的按钮不在该列表中,也同样视为无效事件,拒绝处理。只有当这些条件都满足后,事件才被视为有效操作。此时程序记录当前鼠标点击的位置,保存在 widget_state.lastPoint 中,用于后续计算移动偏移量,并将 widget_state.pressed 标志设为 true,表明控件已被点击按住,准备进行拖动。

void CCMovableWidget::handling_mouseReleaseEvent(QMouseEvent *event) {qDebug() << "Mouse released";if (!holding_widget)return; // no widget to hold, reject processwidget_state.pressed = false;
}

handling_mouseReleaseEvent(QMouseEvent *event) 则是用户释放鼠标按钮时调用的函数,它的作用相对简单。同样以日志开始,表示捕获了释放事件。随后依旧先检查是否存在 holding_widget,如果当前并未绑定任何控件,则此次释放事件无需处理。若控件存在,则将 widget_state.pressed 设为 false,这一行为本质上是标记当前已结束拖动操作,后续的鼠标移动将不再引起控件的位置变化。

void CCMovableWidget::handling_mouseMoveEvent(QMouseEvent *event) {qDebug() << "Mouse moved";if (!holding_widget)return; // no widget to hold, reject processif (!widget_state.pressed)return; // the widget is not pressed, reject process// calculate the offsetint offsetX = event->pos().x() - widget_state.lastPoint.x();int offsetY = event->pos().y() - widget_state.lastPoint.y();// calculate the new positionint x = holding_widget->x() + offsetX;int y = holding_widget->y() + offsetY;// check if the widget should be in the parentif (widget_state.inParent) {QWidget *w = dynamic_cast<QWidget *>(holding_widget->parent());if (w && (sizeIsOutlier(QPoint(x, y), w) || positionIsOutlier(QPoint(x, y)))) {return;}// move the widgetholding_widget->move(x, y);}
}

handling_mouseMoveEvent(QMouseEvent *event) 是核心函数,它在用户拖动鼠标时不断被调用,从而持续地更新控件位置,完成“随鼠标移动”的视觉效果。函数首先打印出“鼠标移动”的日志,确认事件的发生。紧接着,它做出两个防御性检查。第一,是否存在 holding_widget,否则自然不该响应移动。第二,判断是否存在 widget_state.pressed 为真的状态,这是防止控件在未被按住的情况下跟随鼠标移动,确保只有在“鼠标按下后并且未释放”的情形下才进入后续逻辑。接下来,程序通过当前位置与上次记录的鼠标按下点 lastPoint 计算出一个偏移量 offsetXoffsetY,这是拖动过程中控件应该移动的距离。然后,根据当前控件的原始位置加上偏移量,计算出控件新的坐标 xy

但并非所有位置更新都是合理的,因此函数中还加入了一道逻辑判断,即如果当前设置了 widget_state.inParent 为真(意味着控件应保持在其父组件内),就需要判断新位置是否越界。这里调用了 sizeIsOutlier(QPoint(x, y), w)positionIsOutlier(QPoint(x, y)) 两个函数,前者大概是判断控件在给定位置上是否尺寸越界,后者则可能是判断位置是否超出允许的边界。这一检查使得控件不能被拖出其父容器或显示区域之外。如果这两个函数判定位置无效,则不执行移动操作,函数直接返回。

最后,如果所有条件都满足,程序调用 holding_widget->move(x, y) 将控件平滑地移动到新位置上。这一行为便是“拖动”体验的实现者,控件就随着鼠标游走而流畅移动。

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

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

相关文章

[入门]NUC13配置Ubuntu20.04详细步骤

文章目录 1. 安装Ubuntu20.041.1 制作系统启动盘1.1.1 下载镜像文件1.1.2 配置启动盘 1.2 安装内存条、硬盘1.3 安装系统 2. 网卡驱动配置2.1 关闭安全启动2.2 安装intel官方网卡驱动backport2.2.1 第四步可能会出现问题 2.3 ubuntu官方的驱动2.4 重启 3. 软件安装3.1 录屏软件…

(七)Reactor响应式编程框架

一、简介 Reactor 是运行在 JVM 上的编程框架&#xff0c;最大特点是完全非阻塞&#xff0c;能高效控制 “背压”&#xff0c;简单来说就是处理数据传输时速度不匹配的问题 。它能和 Java 8 里的一些功能直接搭配使用&#xff0c;像处理异步结果的 CompletableFuture、处理数据…

【Linux】Ubuntu 24.04 LTS 安装 OpenJDK 8

目录 通过 apt-get 直接安装 JDK 1. 更新 apt 软件源 2. 检查 JDK 是否已安装 3. 安装OpenJDK 4. 检查 JDK 是否成功安装 5. 设置 JAVA_HOME 环境变量 找到需要设置的 Java 路径 使用文本编辑器打开/etc/environment文件 添加 Java 安装路径 应用更改和验证配置 通过…

Linux系统管理与编程08:任务驱动综合应用

兰生幽谷&#xff0c;不为莫服而不芳&#xff1b; 君子行义&#xff0c;不为莫知而止休。 [环境] windows11、centos9.9.2207、zabbix6、MobaXterm、Internet环境 [要求] zabbix6.0安装环境&#xff1a;Lamp&#xff08;linux httpd mysql8.0 php&#xff09; [步骤] 3 …

数据结构之基本队列-顺序结构实现-初始化-判断队列是否为空(front=rear)-出队-入队-队尾满了,调整队列-获取队头元素

数据结构之基本队列-顺序结构实现-初始化-判断队列是否为空(frontrear)-出队-入队-队尾满了&#xff0c;调整队列-获取队头元素——完整可运行代码 #include <stdio.h>#define MAXSIZE 100 typedef int ElemType;typedef struct {ElemType data[MAXSIZE];int front;int…

基于LabVIEW的Windows平台高速闭环控制

在Windows系统下&#xff0c;通过LabVIEW实现高速闭环控制面临两大核心挑战&#xff1a;非实时操作系统的调度延迟与硬件接口的传输速度限制。以USB-6351&#xff08;NI USB-6351 DAQ卡&#xff09;为例&#xff0c;其理论采样率可达1.25 MS/s&#xff08;单通道&#xff09;&a…

【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring Boot 中的 RESTful API 设计:从上手到骨折

<前文回顾> 点击此处查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12907601&sharereferPC&sharesourceFoyoDesigner&sharefromfrom_link <今日更新> 一、开篇整活…

scrapy入门(深入)

Scrapy框架简介 Scrapy是:由Python语言开发的一个快速、高层次的屏幕抓取和web抓取框架&#xff0c;用于抓取web站点并从页面中提取结构化的数据&#xff0c;只需要实现少量的代码&#xff0c;就能够快速的抓取。 新建项目 (scrapy startproject xxx)&#xff1a;新建一个新的…

FastGPT 社区版快速部署指南

产品简介 FastGPT 是基于大语言模型的智能知识库系统&#xff0c;提供以下核心能力&#xff1a; ✅ 开箱即用 - 内置数据预处理、多模型对接、权限管理 ✅ 可视化编排 - 通过 Flow 工作流实现复杂问答逻辑设计 ✅ 多场景适配 - 支持客服机器人/知识检索/数据分析等场景 &…

【css酷炫效果】纯CSS实现科技感网格背景

【css酷炫效果】纯CSS实现科技感网格背景 缘创作背景html结构css样式完整代码基础版进阶版(3D光线扫描版) 效果图 想直接拿走的老板&#xff0c;链接放在这里&#xff1a;上传后更新 缘 创作随缘&#xff0c;不定时更新。 创作背景 刚看到csdn出活动了&#xff0c;赶时间&a…

vue3:十一、主页面布局(左侧菜单折叠展开设置)

一、实现效果 二、基本实现 1、菜单容器增加展开收缩方法 在菜单容器中开启这个方法&#xff0c;值设置为一个变量 :collapseiscollapse 2、定义菜单收缩与否的变量 在js中初始化是否收缩的变量&#xff0c;初始值为不收缩(也就是展开) //左侧菜单展开与收缩 const iscolla…

Chapter 4-15. Troubleshooting Congestion in Fibre Channel Fabrics

show zone member: Shows the name of the zone to which a device belongs to. This command can be used to find the victims of a culprit device or vice versa. 显示设备所属的区域名称。该命令可用于查找罪魁祸首设备的受害者,反之亦然。 show zone active: Shows the…

网络爬虫【爬虫库request】

我叫不三不四&#xff0c;很高兴见到大家&#xff0c;欢迎一起学习交流和进步 今天来讲一讲爬虫 Requests是Python的一个很实用的HTTP客户端库&#xff0c;完全满足如今网络爬虫的需求。与Urllib对比&#xff0c;Requests不仅具备Urllib的全部功能&#xff1b;在开发使用上&…

MTKAndroid12 解决SystemUI下拉框中,长按WIFI图标会导致崩溃问题

解决SystemUI下拉框中&#xff0c;长按WIFI图标会导致崩溃问题 文章目录 场景参考资料修改文件解决方案日志源码分析 总结 场景 在部分产品中偶发性发现&#xff0c; SystemUI下拉框下拉后长按WIFI图标会导致崩溃问题&#xff0c;有时候是截屏、点击Home 按键后&#xff0c;长…

XSS基础靶场练习

目录 1. 准备靶场 2. PASS 1. Level 1&#xff1a;无过滤 源码&#xff1a; 2. level2&#xff1a;转HTML实体 htmlspecialchars简介&#xff1a; 源码 PASS 3. level3:转HTML深入 源码&#xff1a; PASS 4. level4:过滤<> 源码&#xff1a; PASS: 5. level5:过滤on 源码…

熔断降级(Sentinel解决)

问题概述 在微服务架构中一定要预防微服务雪崩问题&#xff0c;微服务雪崩问题就是指在微服务架构中&#xff0c;当一个服务出现故障时&#xff0c;由于服务之间的依赖关系&#xff0c;故障可能会传播到其他服务&#xff0c;从而导致了大规模的服务失败&#xff0c;系统无法正…

TPCTF 2025 web 复现

文章目录 baby layoutsafe layoutSafe Layout Revengesupersqli baby layout 在index.js文件中&#xff0c;看到了有使用DOMPurify库来防止XSS操作 在package.json里可以看到版本是3.2.4,关于3.2.3是有绕过策略的。它会把script标签清除掉&#xff0c;去看bot可以看到flag是放…

Agent Team 多智能体系统解析

引言 在人工智能技术高速发展的今天&#xff0c;"多智能体协作系统"&#xff08;Agent Team&#xff09;正成为突破效率瓶颈的关键技术。与传统的单体AI不同&#xff0c;这种由多个专业化智能体组成的协同网络&#xff0c;通过分工协作和动态调整&#xff0c;展现出…

bootstrap 表格插件bootstrap table 的使用经验谈!

最近在开发一个物业管理软件&#xff0c;其中用到bootstrap 的模态框。同时需要获取表格数据。用传统的方法&#xff0c;本人不想用&#xff0c;考虑到bootstrap应该有获取表格数据的方法&#xff0c;结果发现要想实现获取表格数据功能&#xff0c;需要通过bootstrap的插件实现…

循环不变量原则——螺旋矩阵

题目&#xff1a;螺旋矩阵 本题相较于螺旋矩阵II的不同之处是&#xff1a;螺旋矩阵II的矩阵是n行n列的方阵&#xff0c;而本题的矩阵并不一定是方阵。所以在遵循循环不变量原则遍历完矩阵后&#xff0c;还会有一行或者一列没有遍历。 1、行多列少&#xff08;多一列没遍历&am…