最新要闻
- 【热闻】马斯克嘲讽人工智能:机器学习本质就是统计学
- 小学生用奶奶手机充值游戏2.9万 法院判决来了 世界视讯
- “龙字辈”成员即将加入!长城发布全新硬派SUV 或命名:“翔龙”
- 河南雷暴大风 半米粗大树连根拔起 外卖小哥伸头躲过一劫
- 世界快播:蔚来宣布重大决定:免费换电权益解绑 全系车型降价3万
- 今日播报!村里种的“软黄金”迎来丰收季
- 两批次食品不符合国家标准上黑榜 全球快资讯
- 俩石柱子被五菱一下子撞飞 附近店家感慨:此乃神车
- 米哈游去年赚了161亿!网友:够再开发十个《原神》了
- 每日快报!时代变了!未来18个月内 传奇瑞等大量国产车企将进入英国市场
- 世界速讯:越南因罕见高温遭遇“停电危机”:佳能等企业轮流停电
- 全球视讯!多种口味:和路雪经典大梦龙多口味雪糕16支88元发车
- 甘肃省加快推进交通项目建设 每日快播
- 《暗黑4》第一件“军帽”在韩服现身 官方证实:最强欧皇诞生 属性无敌
- 苹果回应Mac Pro弃用AMD显卡:压根就不适配_天天微速讯
- VIP体验卡到期!高考后饭菜的反差让人猝不及防:从“吃啥有啥”变“有啥吃啥”
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
环球今日报丨Qt 事件系统总结
参考:
- (35条消息) Qt事件循环及QEventLoop的使用_kupeThinkPoem的博客-CSDN博客
- (35条消息) Qt消息机制:事件分发和事件过滤_qt 消息过滤_SOC罗三炮的博客-CSDN博客
Qt 事件系统总结
Qt 事件
在 Qt 中,事件(event)是一些对象,它们都派生自抽象类
QEvent
事件是应用程序所关心的,程序内部发生的事或是外部行动的结果
(资料图)
当一个事件发生,Qt 会创建一个事件对象,它是一个派生自抽象类
QEvent
的类的实例,用来代表发生的事件有时一个事件包含多个事件类型,比如鼠标事件
QMouseEvent
又可以分为鼠标按下、双击、滚轮滚动和移动等多种操作事件由谁接收:事件可以被任何派生自
QObject
的类型的实例接收和处理- QObject 类的三大核心功能其中之一就是:事件处理。
QObject
通过event()
函数获取和分发事件。
- QObject 类的三大核心功能其中之一就是:事件处理。
事件由谁产生:
- 由操作系统或应用程序内部产生
- 使用
bool QEvent::spontaneous() const
判断事件是否来自于应用程序外部,如果事件来自于外部返回 true,否则返回 false
Qt 事件循环
主事件循环
- 每一个 Qt 程序,main 函数中一般都有唯一的 QCoreApplication/QGuiApplication/QApplication,并在末尾调用
exec()
。这样就开始 Qt 的事件循环 - 事件循环的本质是无限循环,使用
exec()
开启事件循环,如果事件循环不结束,exec()
后面的代码永远不会执行。 - 在执行
exec()
函数之后,程序将进入事件循环来监听应用程序的事件。事件多数情况下是被分发到一个队列中(事件队列),当队列中有事件时就不停的将队列中的事件发送给QObject
对象,当队列为空时就循环等待事件。 - 当事件发生时,Qt 将创建一个事件对象。Qt 中所有事件类都继承于
QEvent
,这也是事件不同于信号(信号与槽中的信号)的一点 —— 事件是类具有特定类型, 而信号是信号函数 QCoreApplication
中提供了一下处理事件的函数:
/// 给任何线程的任何对象发送任何事件都会调用该函数。可以重写该函数来达到全局的事件处理与控制的功能。[virtual] bool QCoreApplication::notify(QObject *receiver, QEvent *event)/// 直接使用 notify() 将事件发送给事件的接收者,返回事件处理程序返回的值。事件被发送后并不会被自动被销毁,因此事件对象常常可以声明在堆栈上作为自动变量。[static] bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event) /// 添加事件到事件队列然后立即返回。事件必须声明在堆上。当控制返回到主事件循环时,所有存储在事件队列中的事件都将使用 notify 函数发送出去。/// 事件按优先级排队,高优先级的事件先入队。事件优先级是一个整机变量。/// 函数是【线程安全】的[static] void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority = Qt::NormalEventPriority) /// 立即分派在事件队列中的所有事件接收对象为 receiver 事件类型为 event_type 的事件。/// 如果 receiver = nullptr ,所有事件类型为 event_type 都会被立即发送给接收者/// 如果 event_type = 0, 所有发送给 receiver 的事件都会被立即发送给它[static] void QCoreApplication::sendPostedEvents(QObject *receiver = nullptr, int event_type = 0) /// 告诉应用以指定的返回码退出事件循环,exec() 将结束并返回该返回码,任何非零返回码意味着错误。[static] void QCoreApplication::exit(int returnCode = 0)/// 告诉应用正常退出事件循环。相当于 exit(0)。通常信号与该槽应该进行[队列连接],因为如果在主事件循环开始之前,信号发送导致的 quit() 回调是无效的(事件循环没有开始,何谈退出)/// 使用队列连接确保槽函数不会再事件循环开始前执行。[static slot] void QCoreApplication::quit()
QEventLoop 类
/// 开启事件循环 int exec(QEventLoop::ProcessEventsFlags flags = AllEvents)void exit(int returnCode = 0)/// 如果事件循环是运行着的,返回 true,否则返回 false。事件循环在 exec() 和 exit() 之间被认为是运行的bool isRunning() const[slot] void QEventLoop::quit()
事件循环是可以嵌套的,当在子事件循环中的时候,父事件循环中的事件实际上处于中断状态。这就相当于循环嵌套。
当子事件循环结束,exec() 返回之后才可以执行父循环中的事件。当然,这不代表在执行子循环的时候,类似父循环中的界面响应会被中断,因为往往子循环中也会有父循环的大部分事件,执行QMessageBox::exec(),QEventLoop::exec()的时候,虽然这些exec()打断了main()中的QApplication::exec(),但是由于GUI界面的响应已经被包含到子循环中了,所以GUI界面依然能够得到响应。
如果某个子事件循环仍然有效,但其父循环被强制跳出,此时父循环不会立即执行跳出,而是等待子事件循环跳出后,父循环才会跳出。
事件的转发与处理流程
Qt 程序需要在 main()
函数创建一个 QApplication
对象,然后调用它的 exec()
函数。这个函数就是开始 Qt 的事件循环。在执行 exec()
函数之后,程序将进入事件循环来监听应用程序的事件。
同步与异步事件
- 同步事件:调用
QCoreApplication::sendEvent()
,会直接使用QCoreApplication::notify
将事件发送给事件接收方,事件会立即被执行。 - 异步事件:调用
QCoreApplication::postEvent()
, 会将事件加入到事件队列,等待事件循环进行处理。
事件分发器
Qt 中每个事件类型都有一个枚举类型 QEvent::Type
的数据成员,通过该枚举类型,在程序中可以区分不同的事件类型,根据不同的事件类型进行不同的动作。如下即为 QObject::event
的源码:
- 事件分发器根据事件的不同,将事件发送给不同的事件处理器进行处理,因此可以通过重写事件处理器函数,让指定事件发生发生时,执行我们想要的事件处理动作。
bool QObject::event(QEvent *e){ switch (e->type()) { case QEvent::Timer: timerEvent((QTimerEvent *)e); break; case QEvent::ChildAdded: case QEvent::ChildPolished: case QEvent::ChildRemoved: childEvent((QChildEvent *)e); break; case QEvent::DeferredDelete: qDeleteInEventHandler(this); break; case QEvent::MetaCall: { QAbstractMetaCallEvent *mce = static_cast(e); if (!d_func()->connections.loadRelaxed()) { QBasicMutexLocker locker(signalSlotLock(this)); d_func()->ensureConnectionData(); } QObjectPrivate::Sender sender(this, const_cast(mce->sender()), mce->signalId()); mce->placeMetaCall(this); break; } case QEvent::ThreadChange: { Q_D(QObject); QThreadData *threadData = d->threadData.loadRelaxed(); QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed(); if (eventDispatcher) { QList timers = eventDispatcher->registeredTimers(this); if (!timers.isEmpty()) { // do not to release our timer ids back to the pool (since the timer ids are moving to a new thread). eventDispatcher->unregisterTimers(this); QMetaObject::invokeMethod(this, "_q_reregisterTimers", Qt::QueuedConnection, Q_ARG(void*, (new QList(timers)))); } } break; } default: if (e->type() >= QEvent::User) { customEvent(e); break; } return false; } return true;}
- 如果希望在事件分发之前做一些操作,就可以重写这个
event()
函数。 - 如果传入的事件已被识别并且处理,则需要返回 true,否则返回 false。如果返回值是 true,那么 Qt 会认为这个事件已经处理完毕,不会再将这个事件发送给其它对象,而是会继续处理事件队列中的下一事件
❗❗❗在
event()
函数中,调用事件对象的accept()
和ignore()
函数是没有作用的,不会影响到事件的传播
事件过滤器
事件过滤器可以对其他组件接收到的事件进行监控
事件过滤器使用步骤如下:
创建一个事件过滤器
任意的
QObject
对象都可以作为事件过滤器使用事件过滤器对象需要重写
eventFilter()
函数eventFilter()
中可以决定是否将事件传递给组件对象,事件处理程序也可以提前写在事件过滤器中。- 不让事件继续转发返回 true, 否则返回 false
被监控对象安装事件过滤器
void QObject::installEventFilter(QObject *filterObj)
事件过滤器的调用时间是目标对象(也就是 eventFilter()
参数里面的 watched 对象)接收到事件对象之前。如果事件被过滤掉(返回 true) 那么组件对象就不会收到该事件。
❗❗❗ 事件过滤器和被安装过滤器的组件必须在同一线程,否则,过滤器将不起作用。另外,如果在安装过滤器之后,这两个组件到了不同的线程,那么,只有等到二者重新回到同一线程的时候过滤器才会有效
全局事件过滤器在 QAppliaction::instance()
或 QCoreApplication::instance()
上安装事件过滤器,那么任何事件在通过 notify()
函数发送给其他对象之前都要先传给事件过滤器。
Qt 事件处理的 5 个层次
- 重写
paintEvent()
、mousePressEvent()
等事件处理函数。最普通、最简单的形式。 - 重写
event()
函数。event()
是任何 Qt 对象的所有事件的入口,默认是根据事件类型的不同将事件分发给不同的事件处理函数 - 在特定对象上安装事件过滤器,该事件过滤器仅过滤该对象接收到的事件
- 使用全局事件过滤器,在
QAppliaction::instance()
或QCoreApplication::instance()
上安装事件过滤器。事件过滤器可以安装多个(多个事件过滤器会按安装顺序逆序激活),相比重写notify()
更加灵活,全局过滤器有一个问题:只能用在主线程。 - 重写
QCoreApplication::notify()
这是最强大的,和全局事件过滤器一样提供完全控制,并且不受线程的限制。但是全局范围内只能有一个被使用(因为QCoreApplication是单例的)。
事件(QEvent)与信号(SIGNAL)的区别
事件 | 信号 | |
---|---|---|
本质区别 | 事件是对象,都是派生自 QEvent 的类的实例 | 信号是QObject 或是其派生类的函数成员 |
与 QObject 的关系 | 事件由 QObject 及其派生类的实例对象接收并进行处理 | 信号由QObject 或是其派生类的实例对象发出(emit ) |
对程序影响 | 改写事件处理函数可能导致程序行为发生改变 | 如果将信号与不同的槽函数连接,会导致不同的行为 |
- 两者的联系:
- 事件的转发和处理,信号与槽实现的对象间通讯,都依靠于 QObject,都依靠 Qt 的事件循环。
- 一些信号,是在事件处理函数中发出的。
QPushButton 事件处理分析
示例代码:
#ifndef MYAPPLICATION_H#define MYAPPLICATION_H#include class MyApplication : QApplication{ Q_OBJECTpublic: MyApplication(int &argc, char **argv); bool notify(QObject *receiver, QEvent *event) override; void installEventFilter(QObject *filter); int exec();protected: bool event(QEvent *e) override;};#endif // MYAPPLICATION_H
#include "myapplication.h"#include "qdebug.h"MyApplication::MyApplication(int &argc, char **argv) : QApplication{argc, argv}{}bool MyApplication::notify(QObject *receiver, QEvent *event){ if(event->type() == QEvent::MouseButtonPress){ qDebug() << "MyApplication::notify():发布鼠标按下事件给类型为 " << receiver->metaObject()->className() << " 的对象;"; } return QApplication::notify(receiver, event);}void MyApplication::installEventFilter(QObject *filter){ QApplication* a = static_cast(this); a->installEventFilter(filter);}int MyApplication::exec(){ return QApplication::exec();}bool MyApplication::event(QEvent *e){ if(e->type() == QEvent::MouseButtonPress){ qDebug() << "MyApplication::event(): 分发鼠标按下事件"; } return QApplication::event(e);}
#ifndef MYBUTTON_H#define MYBUTTON_H#include class MyButton : public QPushButton{ Q_OBJECTpublic: MyButton(QWidget* parent = nullptr); MyButton(QString const& text, QWidget* parent = nullptr);protected: void mousePressEvent(QMouseEvent *e) override; bool event(QEvent* e) override;};#endif // MYBUTTON_H
#include "mybutton.h"#include #include #include MyButton::MyButton(QWidget* parent) : QPushButton{parent}{}MyButton::MyButton(const QString &text, QWidget *parent) : QPushButton{text, parent}{}void MyButton::mousePressEvent(QMouseEvent *e){ qDebug() << "MyButton::mousePressEvent() 按钮按下事件被处理"; QPushButton::mousePressEvent(e);// 默认的事件处理函数中,会发出信号: emit pressed() qDebug() << "槽函数回调返回后,执行发送信号(emit)后面的代码";}bool MyButton::event(QEvent *e){ if(e->type() == QEvent::MouseButtonPress){ qDebug() << "MyButton::event(): 按钮点击事件被分发"; } return QPushButton::event(e);}
#ifndef WIDGET_H#define WIDGET_H#include #include "mybutton.h"class Widget : public QWidget{ Q_OBJECTpublic: Widget(QWidget *parent = nullptr); ~Widget();protected: bool event(QEvent *e) override; bool eventFilter(QObject* watched, QEvent *event) override;private: MyButton *button;private slots: void buttonPressedSlot();};#endif // WIDGET_H
#include "widget.h"#include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent){ button = new MyButton(">>> 按钮 <<<",this); button->installEventFilter(this); connect(button, &MyButton::pressed, this, &Widget::buttonPressedSlot);}Widget::~Widget(){}bool Widget::event(QEvent *e){ if(e->type() == QEvent::MouseButtonPress){ qDebug() << "Widget::event(): 按钮按下事件被分发"; } return QWidget::event(e);}bool Widget::eventFilter(QObject* watched, QEvent *event){ if(watched == this->button && event->type() == QEvent::MouseButtonPress){ qDebug() << "在鼠标按下事件发送给 button 之前,事件过滤器 Widget::eventFilter() 先对事件进行处理"; } return QWidget::eventFilter(watched, event);}void Widget::buttonPressedSlot(){ qDebug() << "Widget::buttonPressedSlot(): 按下按钮的槽函数被调用";}
#include "widget.h"#include "myapplication.h"#include #include class GlobalFilter : public QObject{public: GlobalFilter(QObject *parent = nullptr) : QObject{parent}{}protected: bool eventFilter(QObject* watched, QEvent *event) override{ if(event->type() == QEvent::MouseButtonPress){ qDebug() << "在鼠标按下事件发送给类型为 " << watched->metaObject()->className() << " 的对象之前,全局事件过滤器 GlobalFilter::eventFilter() 先对事件进行处理;"; } return QObject::eventFilter(watched, event); }};int main(int argc, char *argv[]){ MyApplication a(argc, argv); std::unique_ptr uptr_filter(new GlobalFilter); a.installEventFilter(uptr_filter.get()); Widget w; w.show(); return a.exec();}
输出:
# 点击按钮输出如下信息:MyApplication::notify():发布鼠标按下事件给类型为 QWidgetWindow 的对象;在鼠标按下事件发送给类型为 QWidgetWindow 的对象之前,全局事件过滤器 GlobalFilter::eventFilter() 先对事件进行处理;MyApplication::notify():发布鼠标按下事件给类型为 MyButton 的对象;在鼠标按下事件发送给类型为 MyButton 的对象之前,全局事件过滤器 GlobalFilter::eventFilter() 先对事件进行处理;在鼠标按下事件发送给 button 之前,事件过滤器 Widget::eventFilter() 先对事件进行处理MyButton::event(): 按钮点击事件被分发MyButton::mousePressEvent() 按钮按下事件被处理Widget::buttonPressedSlot(): 按下按钮的槽函数被调用槽函数回调返回后,执行发送信号(emit)后面的代码
示例:查看图片的简单应用
功能如下:
- 选择和打开图片:点击按钮,选择打开一个图片
- 缩放图片:通过鼠标滚轮能够缩放图片,缩放中心为图片绘制窗口的几何中心
- 相关事件:
wheelEvent()
,QEvent::Resize
,QEvent::Paint
- 相关事件:
- 拖动图片:通过鼠标左键按住来拖动图片
- 相关事件:
mousePressEvent()
,mouseMoveEvent()
,QEvent::Paint
- 相关事件:
#ifndef WIDGET_H#define WIDGET_H#include QT_BEGIN_NAMESPACEnamespace Ui { class Widget; }QT_END_NAMESPACEclass Widget : public QWidget{ Q_OBJECTpublic: Widget(QWidget *parent = nullptr); ~Widget();protected: /// 重写事件过滤器,在事件过滤器中来处理子窗口的绘图事件 /// 默认的事件过滤器默会把把父窗口下子控件的绘图事件过滤掉,因此重新父窗口的 paintEvent 是无法在子控件上绘图的。 /// 因此,直接在事件过滤器中处理绘图事件 bool eventFilter(QObject *watched, QEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void wheelEvent(QWheelEvent *event) override;private: /// 设置图片的缩放中心 /// 输入缩放中心在图窗中的坐标,来求更新 zoomCenter 和 zoomCenterPic void setZoomCenter(const QPointF& zoomCenter); /// 因为图片缩放默认以图片坐标系原点(图片左上角顶点)为缩放中心 /// 为了以 zoomCenter 为缩放中心,需要修改图片的绘制位置, /// 通过缩放 + 移动使得图片相当于以指定的缩放中心缩放 void correctImagPosition(); Ui::Widget *ui; QPixmap pixmap; double scaleFactor; ///< 缩放因子 QPointF zoomCenter; ///< 图片缩放中心在图窗坐标系下的坐标 QPointF zoomCenterPic; ///< 当缩放因子为 1 时,缩放中心相对于图片坐标系的坐标 QPointF posit; ///< 图片绘制位置(为图片左上角顶点在图窗中的坐标) bool isImgError; ///< 读取图片是否错误的标志 QPoint lastDragPos; ///< 暂存鼠标最新的拖动位置private slots: void openImg();};#endif // WIDGET_H
#include "widget.h"#include "ui_widget.h"#include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) , scaleFactor(1) , isImgError(false){ ui->setupUi(this); ui->widget->installEventFilter(this);// 为图片显示窗口安装事件过滤器 connect(ui->pushButton, &QPushButton::clicked, this, &Widget::openImg);}Widget::~Widget(){ delete ui;}bool Widget::eventFilter(QObject *watched, QEvent *event){ if(watched == ui->widget && event->type() == QEvent::Paint){ // 处理子窗口 ui->widget 的 Paint 事件 QPainter painter(ui->widget); if(pixmap.isNull()){ painter.fillRect(rect(), Qt::black); painter.setPen(Qt::white); if(isImgError){ painter.drawText(rect(), Qt::AlignCenter, tr("无法打开图片")); return true; }else{ painter.drawText(rect(), Qt::AlignCenter, tr("请选择图片")); return true; } } // 缩放图片 QPixmap img = pixmap.scaled(pixmap.width() / scaleFactor, pixmap.height() / scaleFactor, Qt::KeepAspectRatio/*, Qt::SmoothTransformation*/); correctImagPosition();// 修正图片位置 painter.drawPixmap(posit, img);// 绘制图片 }else if(watched == ui->widget && event->type() == QEvent::Resize){ // 处理子窗口 ui->widget 的 Resize 事件 QResizeEvent* re = static_cast(event); setZoomCenter(QPointF(re->size().width() / 2.0, re->size().height() / 2.0));// 更新缩放中心位置 return false; }else{ return QWidget::eventFilter(watched,event);//其它事件交给父类事件过滤器处理 }}void Widget::mousePressEvent(QMouseEvent *event){ if(event->button() == Qt::LeftButton) lastDragPos = event->pos();// 暂存鼠标按下时的位置}void Widget::mouseMoveEvent(QMouseEvent *event){ if (event->buttons() & Qt::LeftButton) { QPoint delta = event->pos() - lastDragPos;// 计算鼠标拖拽时的相对位置变化 posit.rx() += delta.x(); posit.ry() += delta.y(); // 因为 posit 改变,缩放中心相对于图片坐标系的位置也发生了改变 zoomCenterPic -= delta * scaleFactor;//或:setZoomCenter(QPointF(this->width() / 2.0, this->height() / 2.0)); lastDragPos = event->pos(); update(); }}void Widget::wheelEvent(QWheelEvent *event){ // 滚轮朝前推为正,朝后推为负 // 鼠标滚轮每滚动 1°,angleDelta() 值加或减 8 const int numDegrees = event->angleDelta().y() / 8; // 实际中,滚轮每滚动一格,角度变化为 15° const double numSteps = numDegrees / double(15); // 根据滚轮的移动格数修改缩放因子 double tmp = scaleFactor * pow(0.8, numSteps); // 限制缩放因子的范围 if(tmp < 0.1) scaleFactor = pow(0.8, 10); else if(tmp > 10) scaleFactor = pow(0.8, -10); else scaleFactor = tmp; update();}void Widget::setZoomCenter(const QPointF& zoomCenter){ this->zoomCenter = zoomCenter; this->zoomCenterPic = (zoomCenter - posit) * scaleFactor;}void Widget::correctImagPosition(){ // 缩放时修正图片绘制位置 posit = zoomCenter - zoomCenterPic / scaleFactor;}void Widget::openImg(){ QString fileName = QFileDialog::getOpenFileName(this, tr("选择图片"), QDir::homePath(), tr("Images (*.png *.xpm *.jpg)")); if(!pixmap.load(fileName)){ isImgError = true; }else{ isImgError = false; // 每次打开图片,设置初始缩放因子为 1 scaleFactor = 1; // 设置图片初始在图窗中心显示 posit.rx() = (this->width() - pixmap.width()) / 2.0; posit.ry() = (this->height() - pixmap.height()) / 2.0; // 设置图窗中心为缩放中心 setZoomCenter(QPointF(this->width() / 2.0, this->height() / 2.0)); } update();// 更新窗口显示}
关键词:
环球今日报丨Qt 事件系统总结
Web网页端IM产品RainbowChat-Web的v5.0版已发布
【热闻】马斯克嘲讽人工智能:机器学习本质就是统计学
小学生用奶奶手机充值游戏2.9万 法院判决来了 世界视讯
“龙字辈”成员即将加入!长城发布全新硬派SUV 或命名:“翔龙”
河南雷暴大风 半米粗大树连根拔起 外卖小哥伸头躲过一劫
世界快播:蔚来宣布重大决定:免费换电权益解绑 全系车型降价3万
今日播报!村里种的“软黄金”迎来丰收季
每日速读!windows下如何杀掉Tomcat进程
焦点信息:5分钟学会数据结构中的线性链表
Python工具箱系列(三十五) 全球新消息
vue使用 elementUI中el-upload的遇到的问题总结
【新华解读】可转债退市机制逐步完善 未来或迎来“宽进宽出”市场生态_全球新动态
两批次食品不符合国家标准上黑榜 全球快资讯
俩石柱子被五菱一下子撞飞 附近店家感慨:此乃神车
米哈游去年赚了161亿!网友:够再开发十个《原神》了
每日快报!时代变了!未来18个月内 传奇瑞等大量国产车企将进入英国市场
世界速讯:越南因罕见高温遭遇“停电危机”:佳能等企业轮流停电
全球视讯!多种口味:和路雪经典大梦龙多口味雪糕16支88元发车
物联网开源操作系统简介 天天快资讯
Jenkins + Docker 一键自动化部署 Spring Boot 项目,步骤齐全,少走坑路! 全球微动态
甘肃省加快推进交通项目建设 每日快播
《暗黑4》第一件“军帽”在韩服现身 官方证实:最强欧皇诞生 属性无敌
苹果回应Mac Pro弃用AMD显卡:压根就不适配_天天微速讯
VIP体验卡到期!高考后饭菜的反差让人猝不及防:从“吃啥有啥”变“有啥吃啥”
今日报丨windows图片查看器修复(windows图片查看器)
解读投顾新规(一)| 扭转投顾“产品化”倾向 引导行业回归服务本源
【读财报】基金发行透视:年内发行规模同比下降15% 鹏扬、国融基金产品发行失败_全球快资讯
国家助学贷款累计发放超4000亿元 惠及2000多万名学生
曝苹果开发Vision Pro更便宜版本:屏幕、处理器会缩水|世界看热讯
A卡降价太狠 NVIDIA坐不住:RTX 4060将提前上市 2399买吗?|焦点
汽车人险胜蜘蛛侠
产销两旺 新能源车消费涌热潮
读改变未来的九大算法笔记10_读后总结与感想 播报
动力电池回收赛道不断升温 上市公司积极挖掘新蓝海-环球热推荐
全球速读:女子220斤家人为激励减肥奖6万 已减超20斤:网友鼓励加油
当前速递!显卡不买丐版就亏了?到底该怎么选?
电路中的pnp是什么意思(电路中pn结是什么意思) 世界关注
深度学习应用篇-计算机视觉-OCR光学字符识别[7]:OCR综述、常用CRNN识别方法、DBNet、CTPN检测方法等、评估指标、应用场景
面对英特尔大小核CPU AMD调整CPU供货和价格-每日速递
新华三率先推出私域行业大模型:百业灵犀
大师名团密集来京演出,“演艺之都”绽放国际星光 前沿资讯
白蛋白的功效与作用是什么_白蛋白的功效与作用 世界热点
“双万亿”之城、世界工厂……制造业重镇东莞涌现新动能-全球快看
刀锋战士2迅雷下载链接(刀锋战士2迅雷下载)-当前独家
每日热闻!蓝莓树苗怎么种植盆栽_蓝莓树苗怎么种
如果我是清风我将什么续写句子_如果我是清风我将
ps哪个版本最好用2020(ps哪个版本最好用)_全球时快讯
现在满族人的姓氏汉化 满族人的姓氏都有哪些-全球信息
世界观点:电信营业厅电话费_电信营业厅电话
全球热头条丨珠峰被救女士拒绝支付救人费用引争议 登山公司公布遇险原因
引用《道德经》,谈大国分歧,Sam Altman 最新演讲:AI 安全始于足下_环球报道
天天讯息:英媒:经济学家预测美国需至少加息两次才能平息通胀
热推荐:铃木天语sx4二手车(铃木天语sx4隐藏功能是什么?)
从“国家宝藏”到“何以中国”,总台文博类综艺这样创新实践|文化和自然遗产日
【天天播资讯】【技术积累】Java中的泛型【一】
天天亮点!HBase的数据结构原理与使用
Xilinx GTH 简介 ,CoaXpress FPGA PHY 部分-天天短讯
左偏树-环球观点
世界最新:ChatGPT只讲这25个笑话!有90%重复 网友:幽默是人类最后的尊严
环球速讯:火车站按摩椅现大量虫子 商家:每天都有打扫 很少有这种情况
焦点滚动:福建多地为何纷纷成立这一机构?
聚焦:希捷4TB机械硬盘史低 仅售288元
社交综艺为何能成爆款_世界百事通
芯片的战争
这些年,祝勇的“纸上故宫”都在写些什么?|文化观察 天天讯息
List 接口及其常用方法 全球即时看
文心一言 VS 讯飞星火 VS chatgpt (38)-- 算法导论5.4 2题 全球新要闻
吢丕的另一个情侣网名(吢)
环球短讯!最后一艘潜艇电影国语版百度云(最后一艘潜艇电影国语版)
镁条在空气中燃烧发出耀眼的白光(镁条在空气中燃烧)
女朋友不理你怎么办表情包_女朋友不理你怎么办
南京两大厦间现龙卷风:强风至路面闪现火花 每日视点
当前简讯:14代酷睿要来了 英特尔13代酷睿i9包装简化:独特身份消失
预计2025年突破万亿元规模 产学研各方共议储能大赛道
徐州城下城遗址博物馆“上新”
天天热点!金陵十二钗判词及人物(金陵十二钗判词)
每日消息!散水模板工程量怎么计算(算混凝土工程量散水怎么计算)
今日快讯:口腔材料app(口腔材料网)
焦点热议:好高骛远的读音_好高骛远的意思
今日热议:Hbase安装和shell客户端操作
Web安全-渗透测试-信息收集01|全球热文
世界热消息:杯具!上海一小区电动车爆炸起火 家人惨被烧伤:网友吵翻为何电池拿回家充电
莫扎特的一句话(关于莫扎特的话例如说他天真)
世界热点!莫扎特的一句话(关于莫扎特的话例如说他天真)
清远公用品牌IP形象亮相-全球播报
关于铁路计次票、定期票 如何购买使用 环球聚看点
天天视点!多地高温预警 今年618空调没促销降价:还有经销商趁机涨价
龙爸无双100集电视剧免费观看|当前热门
第二届联合国人居大会闭幕 通过“人人享有可负担住房”等决议_百事通
消息!第二届联合国人居大会闭幕 通过“人人享有可负担住房”等决议
中超综合:中超第一阶段结束 上海海港领跑积分榜
中超积分榜:海港领跑三镇仅第8 大连人倒数第一
第34届中国经济新闻奖:21世纪经济报道获评论一等奖、融合报道一等奖 天天精选
全球讯息:武汉到清江画廊旅游攻略_清江画廊旅游攻略
新动态:最美童星长大后惊艳全网!16岁时因“不够性感”被导演刷掉,她霸气怒怼:恶心的猪!
窒息灭火法是指什么_窒息灭火法
全球快资讯:美国旧金山毒品泛滥、暴力犯罪猖獗 市民称正在目睹西方文明崩溃
每日热门:引导资金支持绿色发展 新华碳科技指数发布
这些大胆的古早综艺,真的是不付费就能看的吗? 当前消息