【Qt开发流程】之拖放操作1:介绍
描述
Drag and drop
提供了一种简单的可视化机制,用户可以使用它在应用程序之间和应用程序内部传输信息。拖放的功能类似于剪贴板的剪切和粘贴机制。
本文描述了基本的拖放机制,并概述了在自定义控件中启用该机制的方法。Qt的许多控件也支持拖放操作,例如the item views and graphics view framework
项目视图和图形视图框架,以及Qt Widgets和Qt Quick的编辑控件。
Drag 和 Drop 类
以下类处理拖放和必要的mime类型编码和解码。
类 | 描述 | 解释 |
---|---|---|
QDrag | Support for MIME-based drag and drop data transfer | 支持基于MIME的拖放数据传输 |
QDragEnterEvent | Event which is sent to a widget when a drag and drop action enters it | 当拖放操作进入窗口部件时发送的事件 |
QDragLeaveEvent | Event that is sent to a widget when a drag and drop action leaves it | 当拖放操作离开窗口部件时发送的事件 |
QDragMoveEvent | Event which is sent while a drag and drop action is in progress | 在拖放操作进行中时发送的事件 |
QDropEvent | Event which is sent when a drag and drop action is completed | 当拖放操作完成时发送的事件 |
配置
QStyleHints
对象提供与拖放操作相关的一些属性:
QStyleHints::startDragTime()
描述用户在按住鼠标按钮在一个对象上多长时间后,拖动操作开始的毫秒数。QStyleHints::startDragDistance()
指示用户在按住鼠标按钮时移动鼠标的距离,这之后移动才会被解释为拖动。QStyleHints::startDragVelocity()
指示用户必须移动鼠标的速度(以像素/秒计)以启动拖动。值为0意味着没有这样的限制。
这些量提供了合理的默认值,如果控件中提供拖放支持,可以使用它们,这些值符合底层窗口系统的要求。
Drag
要开始拖动,请创建一个QDrag对象,并调用其exec()函数。在大多数应用程序中,最好只在鼠标按钮被按下并且光标移动一定距离后才开始拖放操作。但是,启用从小部件拖动的最简单方法是重新实现小部件的mousePressEvent()函数并开始拖放操作:
void MainWindow::mousePressEvent(QMouseEvent *event){if (event->button() == Qt::LeftButton&& iconLabel->geometry().contains(event->pos())) {QDrag *drag = new QDrag(this);QMimeData *mimeData = new QMimeData;mimeData->setText(commentEdit->toPlainText());drag->setMimeData(mimeData);drag->setPixmap(iconPixmap);Qt::DropAction dropAction = drag->exec();...}}
尽管用户可能需要一些时间来完成拖放操作,但对于应用程序而言,exec()
函数是一个阻塞函数,返回下面几个值之一。这些值表示操作的结束方式,并在下面更详细地描述。
常量 | 值 | 描述 | 解释 |
---|---|---|---|
Qt::CopyAction | 0x1 | Copy the data to the target. | 将数据复制到目标。 |
Qt::MoveAction | 0x2 | Move the data from the source to the target. | 将数据从源移到目标。 |
Qt::LinkAction | 0x4 | Create a link from the source to the target. | 从源到目标创建一个链接。 |
Qt::ActionMask | 0xff | ||
Qt::IgnoreAction | 0x0 | Ignore the action (do nothing with the data). | 忽略动作(不对数据执行任何操作)。 |
Qt::TargetMoveAction | 0x8002 | On Windows, this value is used when the ownership of the D&D data should be taken over by the target application, i.e., the source application should not delete the data. On X11 this value is used to do a move. TargetMoveAction is not used on the Mac. | 在Windows上,当目标应用程序应该接管D&D数据的所有权时使用此值,即,源应用程序不应删除数据。在X11上,此值用于执行移动操作。TargetMoveAction在Mac上不使用。 |
请注意,exec()
函数不会阻塞主事件循环。
对于需要区分鼠标点击和拖动的小部件,重新实现小部件的mousePressEvent()
函数以记录拖动的起始位置非常有用:
void DragWidget::mousePressEvent(QMouseEvent *event){if (event->button() == Qt::LeftButton)dragStartPosition = event->pos();}
随后,在mouseMoveEvent()
中,我们可以确定是否应该开始拖动,并构造拖动对象来处理操作:
void DragWidget::mouseMoveEvent(QMouseEvent *event){if (!(event->buttons() & Qt::LeftButton))return;if ((event->pos() - dragStartPosition).manhattanLength()< QApplication::startDragDistance())return;QDrag *drag = new QDrag(this);QMimeData *mimeData = new QMimeData;mimeData->setData(mimeType, data);drag->setMimeData(mimeData);Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction);...}
这种方法使用QPoint::manhattanLength()
函数来获取鼠标单击发生位置和当前光标位置之间距离的大致估计值。此函数以精度为代价提高了速度,并且通常适用于此目的。
Drop
要能够接收放置在小部件上的媒体,为小部件调用setAcceptDrops(true)
,并重新实现dragEnterEvent()
和dropEvent()
事件处理程序函数。
例如,以下代码在QWidget子类
的构造函数中启用了放置事件,使其可以有用地实现放置事件处理程序:
Window::Window(QWidget *parent): QWidget(parent){...setAcceptDrops(true);}
dragEnterEvent()
函数通常用于通知Qt小部件接受的数据类型。如果想在dragMoveEvent()
和dropEvent()
的重新实现中接收QDragMoveEvent
或QDropEvent
,则必须重新实现此函数。
以下代码显示了如何重新实现dragEnterEvent()
以告知拖放系统我们仅能处理纯文本:
void Window::dragEnterEvent(QDragEnterEvent *event){if (event->mimeData()->hasFormat("text/plain"))event->acceptProposedAction();}
dropEvent()
用于解包放置的数据并以适合于您的应用程序的方式处理它。
在以下代码中,事件中提供的文本被传递到QTextBrowser
,并使用描述数据的MIME
类型列表填充QComboBox
:
void Window::dropEvent(QDropEvent *event){textBrowser->setPlainText(event->mimeData()->text());mimeTypeCombo->clear();mimeTypeCombo->addItems(event->mimeData()->formats());event->acceptProposedAction();}
在这种情况下,我们接受所建议的操作而不检查它是什么。在现实世界的应用程序中,如果操作不相关可能需要从dropEvent()
函数中返回而不接受所建议的操作或处理数据。例如,如果我们的应用程序不支持链接到外部源,我们可以选择忽略Qt::LinkAction
操作。
覆盖建议动作
我们也可以忽略建议的操作,对数据执行其他操作。为此,我们会在调用 accept()
之前使用 Qt::DropAction
中的首选操作调用事件对象的 setDropAction()
。这样确保使用替换的放置操作而不是建议的操作。
对于更复杂的应用程序,重新实现 dragMoveEvent()
和dragLeaveEvent()
将使您能够使组件的某些部分对拖放事件敏感,并在应用程序中更好地控制拖放。
子类化控件
某些标准的 Qt 组件提供了自己的拖放支持。当子类化这些组件时,除了重新实现 dragEnterEvent()
和dropEvent()
之外,可能还需要重新实现 dragMoveEvent()
,以防止基类提供默认的拖放处理,并处理感兴趣的任何特殊情况。
Drag and Drop 动作
在最简单的情况下,拖放操作的目标将接收被拖动的数据的副本,源则决定是否删除原始数据。这由 CopyAction
操作描述。目标还可以选择处理其他操作,特别是 MoveAction
和 LinkAction
操作。如果源调用 QDrag::exec()
,并且返回 MoveAction
,则源负责删除任何原始数据(如果选择删除)。源窗口小部件创建的 QMimeData
和 QDrag
对象不应被删除 - 它们将被 Qt 销毁。目标负责接管拖放操作中发送的数据的所有权;通常是通过保留对数据的引用来完成的。
如果目标理解 LinkAction
操作,则应将自己的引用存储到原始信息中;源无需进一步处理数据。拖放操作最常见的用法是在同一个小部件中执行 Move
操作;
拖动操作的另一个主要用途是使用ext/uri-list
等引用类型,其中拖动的数据实际上是文件或对象的引用。
添加新的 Drag and Drop 类型
拖放并不仅限于文本和图像。任何类型的信息都可以在拖放操作中传输。要在应用程序之间拖动信息,这些应用程序必须能够互相指示它们可以接受哪些数据格式和可以生成哪些数据格式。这是使用 MIME 类型
实现的。源构建的QDrag
对象包含一个 MIME 类型列表
,它用于表示数据(从最合适到最不合适的顺序),而放置目标使用其中一个来访问数据。对于通用数据类型,方便函数会透明地处理使用的 MIME 类型
,但对于自定义数据类型,必须明确说明它们。
要为QDrag
方便函数未涵盖的信息类型实现拖放操作,首要重要的步骤是查找适合的现有格式:互联网分配的数字机构(IANA)在信息科学研究所(ISI)提供了一种层次结构的 MIME 媒体类型列表
。使用标准 MIME 类型
可以最大化您的应用程序与现在和将来的其他软件的互操作性。
要支持其他一种媒体类型,只需使用setData()
函数在QMimeData
对象中设置数据,提供完整的 MIME 类型
和一个 QByteArray
,其中包含适当格式的数据。以下代码从标签中获取一个 pixmap
,并将其存储为可携带网络图形(PNG)文件在 QMimeData
对象中:
QByteArray output;QBuffer outputBuffer(&output);outputBuffer.open(QIODevice::WriteOnly);imageLabel->pixmap()->toImage().save(&outputBuffer, "PNG");mimeData->setData("image/png", output);
当然,对于该情况,可以简单地使用setImageData()
来提供各种格式的图像数据:
mimeData->setImageData(QVariant(*imageLabel->pixmap()));
在这种情况下,QByteArray
方法仍然很有用,因为它可以更好地控制存储在QMimeData
对象中的数据量。
请注意,item view
中使用的自定义数据类型
必须声明为元对象,并且必须实现它们的流操作符。
Drop动作
在剪贴板模型中,用户可以剪切或复制源信息,然后稍后粘贴它。同样,在拖放模型中,用户可以拖动信息的副本或者他们可以将信息本身拖动到一个新位置(移动它)。对于程序员来说,拖放模型有一个额外的复杂性:在操作完成之前,程序不知道用户是要剪切还是复制这些信息。当在应用程序之间拖动信息时,通常这没有区别,但在应用程序内部,检查使用了哪些放置操作很重要。
可以重新实现小部件的mouseMoveEvent()
方法,并使用可能的放置操作组合来启动拖放操作。例如,可能希望确保拖动对象时,在小部件中始终移动对象:
void DragWidget::mouseMoveEvent(QMouseEvent *event){if (!(event->buttons() & Qt::LeftButton))return;if ((event->pos() - dragStartPosition).manhattanLength()< QApplication::startDragDistance())return;QDrag *drag = new QDrag(this);QMimeData *mimeData = new QMimeData;mimeData->setData(mimeType, data);drag->setMimeData(mimeData);Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction);...}
如果信息被拖放到另一个应用程序中,exec()
函数返回的操作可能默认为 CopyAction
。但是如果它被拖放到同一应用程序中的另一个小部件中,则可能会获得不同的放置操作。
建议的放置操作可以在小部件的 dragMoveEvent()
函数中进行过滤。但是,可以在 dragEnterEvent()
中接受所有建议的操作,让用户稍后决定想要接受哪个:
void DragWidget::dragEnterEvent(QDragEnterEvent *event){event->acceptProposedAction();}
当小部件中发生拖放时,会调用dropEvent()
处理程序函数,可以依次处理每个可能的操作。首先,处理在同一小部件内的拖放操作:
void DragWidget::dropEvent(QDropEvent *event){if (event->source() == this && event->possibleActions() & Qt::MoveAction)return;
在这种情况下,拒绝处理移动操作。会逐一检查和处理每种接受的拖放操作:
if (event->proposedAction() == Qt::MoveAction) {event->acceptProposedAction();// Process the data from the event.} else if (event->proposedAction() == Qt::CopyAction) {event->acceptProposedAction();// Process the data from the event.} else {// Ignore the drop.return;}...}
请注意,上面的代码中检查了各个单独的拖放操作。如上面在关于重写拖放操作的建议中提到的,有时需要重写所建议的拖放操作,并从可能的拖放操作中选择不同的操作。为此,需要检查事件possibleActions()
返回值中是否存在每个操作,使用setDropAction()
设置拖放操作,并调用accept()
函数。
Drop 区域
widget
的dragMoveEvent()
可以用于通过仅在光标位于那些区域时接受建议的放置操作,来限制放置操作到小部件的某些部分。例如,以下代码在光标悬停在子组件(dropFrame)上时接受任何建议的放置操作:
void Window::dragMoveEvent(QDragMoveEvent *event){if (event->mimeData()->hasFormat("text/plain")&& event->answerRect().intersects(dropFrame->geometry()))event->acceptProposedAction();}
如果需要在拖放操作期间给予可视反馈、滚动窗口或进行其他适当的操作,dragMoveEvent()
也可以用于此目的。
剪切
应用程序还可以通过将数据放入剪贴板来彼此通信。要访问此内容,需要从QApplication
对象获取QClipboard
对象。
QMimeData类
用于表示传输到和自剪贴板的数据。为了将数据放入剪贴板,可以使用setText()
、setImage()
和setPixmap()
方便函数来处理常见的数据类型。这些函数类似于QMimeData类
中的函数,但它们还采用一个附加参数,用于控制数据存储的位置:如果指定了Clipboard
,则数据被放置在剪贴板上;如果指定了Selection
,则数据被放置在鼠标选择中(仅在X11上)。默认情况下,数据被放入剪贴板。
例如,可以使用以下代码将QLineEdit的内容复制到剪贴板中:
QGuiApplication :: clipboard()->setText(lineEdit->text(),QClipboard :: Clipboard);
还可以在剪贴板上放置具有不同MIME类型的数据。构造一个QMimeData
对象,并按照前面部分所述的方式使用setData()
函数设置数据;然后可以使用setMimeData()
函数将此对象放入剪贴板。
QClipboard
类可以通过其dataChanged()
信号通知应用程序其所包含数据的更改。例如,可以通过将此信号连接到窗口小部件中的插槽来监视剪贴板:
connect(clipboard,SIGNAL(dataChanged()),this,SLOT(updateClipboard()));
连接到此信号的槽可以使用可用于表示其的MIME类型之一之一读取剪贴板上的数据:
void ClipWindow :: updateClipboard()
{QStringList formats = clipboard->mimeData()->formats();QByteArray data = clipboard->mimeData()->data(format);…
}
在X11上,可以使用selectionChanged()信号来监视鼠标选择。
相关文章:
【Qt开发流程】之拖放操作1:介绍
描述 Drag and drop 提供了一种简单的可视化机制,用户可以使用它在应用程序之间和应用程序内部传输信息。拖放的功能类似于剪贴板的剪切和粘贴机制。 本文描述了基本的拖放机制,并概述了在自定义控件中启用该机制的方法。Qt的许多控件也支持拖放操作&a…...

招募引流模式是实体门店吸引顾客的一种有效策略
在如今激烈的市场竞争和庞大的客户需求中,应该采取什么样的方式来应对,才能找到自己的一席之地。招募引流模式是实体门店吸引顾客的一种有效策略,通常招募体验官或合作伙伴,让他们协助门店进行推广活动,达到增加客流量…...

macos安装小软件 cmake
一,cmake下载主页 Download CMake 二,下载,解压,配置,编译,安装 0. 假设macos中已经存在了 clang和make工具 1. 通过网页下载最新的稳定版 cmake***.tar.gz 源代码 2. tar zxf cmake***.tar 3. cd cmake***…...

思伟老友记 | 厦门路桥翔通海砼建材有限公司与思伟软件携手走过23年
23年 感恩相伴 携手成长 2001年-2023年,厦门路桥翔通海砼建材有限公司已携手上海思伟软件有限公司走过23年。从最初的半手动生产模式到如今的自动生产一体化系统,海砼公司通过思伟软件生产混凝土累计超过1000万m,思伟软件则借助海砼公司的实…...

SpringCloud 微服务全栈体系(十七)
第十一章 分布式搜索引擎 elasticsearch 七、搜索结果处理 搜索的结果可以按照用户指定的方式去处理或展示。 1. 排序 elasticsearch 默认是根据相关度算分(_score)来排序,但是也支持自定义方式对搜索结果排序。可以排序字段类型有&#…...

基于ThinkPHP8 + Vue3 + element-ui-plus + 微信小程序(原生) + Vant2 的 BBS论坛系统设计【PHP课设】
一、BBS论坛功能描述 我做的是一个论坛类的网页项目,每个用户可以登录注册查看并发布文章,以及对文章的点赞和评论,还有文件上传和个人签名发布和基础信息修改,管理员对网站的数据进行统计,对文章和文件的上传以及评论…...

苹果cms搭建教程附带免费模板
准备工作: 一台服务器域名源码安装好NGINX+PHP7.0+MYSQL5.5 安装php7.0的扩展,fileinfo和 sg11,不安装网站会搭建失败。 两个扩展都全部安装好了之后 点击-服务-重载配置 这样我们的网站环境就配置完成啦 下载苹果cms 苹果cms程序github链接:选择mac10!下载即可 http…...

【LeetCode:828. 统计子串中的唯一字符 | 贡献法 乘法原理】
🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…...

字符串和内存函数(2)
文章目录 2.13 memcpy2.14 memmove2.15 memcmp2.16 memset 2.13 memcpy void* memcpy(void* destination, const void* source, size_t num); 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。这个函数在遇到 ‘\0’ 的时候并不会停下来。如果so…...

毅速:复杂零件制造首选3D打印
确金属3D打印技术在制造行业的应用日益广泛,为制造业带来了巨大的变革和机遇。这种增材制造技术相较于传统制造工艺具有许多优势,尤其在制造复杂形状零件方面表现出色。 传统制造工艺在制造复杂形状零件时往往面临诸多挑战,如加工难度大、周期…...

【数据中台】开源项目(2)-Moonbox计算服务平台
Moonbox是一个DVtaaS(Data Virtualization as a Service)平台解决方案。 Moonbox基于数据虚拟化设计思想,致力于提供批量计算服务解决方案。Moonbox负责屏蔽底层数据源的物理和使用细节,为用户带来虚拟数据库般使用体验࿰…...

代理模式(常用)
代理模式(代理设计模式) 在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。例如,购买火车票不一定要去火车站买,可以通过 123…...

redis(Remote Dictionary Service) 底层数据结构
redis 底层数据结构 动态字符串SDS 优点 获取字符串长度的时间复杂度O(1) 支持动态扩容,减少内存分配次数 新字符串小于1M – 新空间为扩展后字符串长度的两倍 1 新字符串大于1M – 新空间为扩展后字符串长度 1M 1. 内存预分配 二进制安全(记录了…...

电子学会C/C++编程等级考试2021年06月(三级)真题解析
C/C++等级考试(1~8级)全部真题・点这里 第1题:数对 给定2到15个不同的正整数,你的任务是计算这些数里面有多少个数对满足:数对中一个数是另一个数的两倍。 比如给定1 4 3 2 9 7 18 22,得到的答案是3,因为2是1的两倍,4是2个两倍,18是9的两倍。 时间限制:1000 内存限制…...
冥想第九百八十五天
1.周四,最近几天刷题的节奏太紧张了,放松一点,不能太大压力了,认证看,慢慢看效果会更好一点。 2.发现了一个跑步比较好的地方,沿着凯旋路,然后昭化路,种德桥路。一圈,刚好…...
Qt OpenGL固定管线与可编程管线
作者:令狐掌门 技术交流QQ群:675120140 csdn博客:https://mingshiqiang.blog.csdn.net/ 文章目录 在Qt框架中,你可以使用Qt的OpenGL模块(包括QOpenGLWidget和QOpenGLFunctions等类)来使用OpenGL进行图形渲染。以下是一个简单的示例,展示了如何在Qt应用程序中使用OpenGL绘…...

冯·诺依曼体系结构和操作系统
目录 一、冯诺依曼体系结构 1、初见结构 2、对体系结构的理解 3、总结 二、操作系统 1、概念 2、作用 一、冯诺依曼体系结构 1、初见结构 数学家冯诺依曼提出了计算机制造的三个基本原则,即采用二进制逻辑、程序存储执行以及计算机由五个部分组成(…...

Nginx(资源压缩)
建立在动静分离的基础之上,如果一个静态资源的Size越小,那么自然传输速度会更快,同时也会更节省带宽,因此我们在部署项目时,也可以通过Nginx对于静态资源实现压缩传输,一方面可以节省带宽资源,第…...
数据结构与算法之二叉树: LeetCode 226. 翻转二叉树 (Typescript版)
翻转二叉树 https://leetcode.cn/problems/invert-binary-tree/ 描述 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 示例 1 4 4/ \ / \2 7 >…...

lightdb-ignore_row_on_dupkey_index
LightDB 支持 ignore_row_on_dupkey_index hint LightDB 从23.4 开始支持oracle的 ignore_row_on_dupkey_index hint, 这个hint是用来忽略唯一键冲突的。类似与mysql的 insert ignore。 语法如下: 在LightDB中ignore_row_on_dupkey_index的效果等同于o…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...