Flutter富文本实现学习
Flutter 代码如何实现一个带有富文本显示和交互的页面。
前置知识点学习
RealRichText
`RealRichText` 和 `ImageSpan` 不是 Flutter 框架中内置的组件,而是自定义的组件或来自第三方库。这些组件的实现可以提供比标准 `RichText` 更丰富的功能,比如在富文本中插入图片、处理点击事件等。由于这些组件在标准 Flutter 中不存在,我将解释如何可能实现类似的功能。
TextSpan
`TextSpan` 是 Flutter 中用于构建富文本的基本组件之一。它允许你在同一个文本组件中混合和匹配不同的文本样式和手势识别功能。`TextSpan` 通常与 `RichText` 组件一起使用,以显示复杂的文本布局。
`TextSpan` 的基本结构
`TextSpan` 是一个不可变的、递归的数据结构,可以包含其他 `TextSpan`,从而允许嵌套不同的文本样式。
TextSpan({TextStyle? style,String? text,List<InlineSpan>? children,GestureRecognizer? recognizer,String? semanticsLabel,
})
关键属性
`style`:
- 指定文本的样式,例如字体大小、颜色、粗细等。
- 类型为 `TextStyle`。
`text`:
- 要显示的文本字符串。
- `text` 和 `children` 之间是互斥的,如果需要在一个 `TextSpan` 中显示多个文本片段,通常使用 `children`。
`children`:
- 一个 `InlineSpan`(通常为 `TextSpan`)的列表,用于嵌套子文本。
- 允许创建复杂的文本结构,如不同样式的文本段落。
`recognizer`:
- 用于处理文本的手势识别,例如点击事件。
- 通常使用 `TapGestureRecognizer` 来处理点击事件。
`semanticsLabel`:
- 为文本提供一个可供屏幕阅读器使用的标签,帮助无障碍访问。
使用示例
下面是一个简单的例子,展示如何使用 `TextSpan` 来创建一个包含多种样式和交互的文本。
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';class RichTextExample extends StatelessWidget {const RichTextExample({super.key});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text("Rich Text Example")),body: Center(child: RichText(text: TextSpan(text: 'Hello ',style: const TextStyle(color: Colors.black, fontSize: 18),children: <TextSpan>[const TextSpan(text: 'bold', style: TextStyle(fontWeight: FontWeight.bold)),const TextSpan(text: ' and ',),const TextSpan(text: 'italic',style: TextStyle(fontStyle: FontStyle.italic),),TextSpan(text: ' clickable ',style: const TextStyle(color: Colors.blue),recognizer: TapGestureRecognizer()..onTap = () {ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Clickable text clicked!')),);},),const TextSpan(text: 'text.',),],),),),);}
}
ImageSpan
`ImageSpan` 是一种在富文本中嵌入图片的技术。在 Flutter 中,虽然没有直接提供一个名为 `ImageSpan` 的组件,但你可以通过使用 `WidgetSpan` 来实现类似的功能。`WidgetSpan` 允许你在 `RichText` 中插入任意的 Flutter 小部件,包括图片。
使用 `WidgetSpan` 实现 `ImageSpan` 的功能
`WidgetSpan` 是 `InlineSpan` 的子类,可以在 `TextSpan` 列表中使用来嵌入小部件。通过这种方式,你可以在文本段落中插入图片或者其他小部件。
示例代码
import 'package:flutter/material.dart';class RichTextWithImageExample extends StatelessWidget {const RichTextWithImageExample({super.key});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text("Rich Text with Image Example")),body: Center(child: RichText(text: TextSpan(style: const TextStyle(color: Colors.black, fontSize: 18),children: <InlineSpan>[const TextSpan(text: 'This is an example of '),WidgetSpan(child: Image.asset("static/demo.png",width: 24,height: 24,)),const TextSpan(text: ' in a rich text widget.'),]),),),);}
}
解释
`RichText` 和 `TextSpan`:
- `RichText` 用于显示复杂的文本布局,`TextSpan` 用于定义文本的样式和内容。
`WidgetSpan`:
- `WidgetSpan` 可以嵌入任何小部件。在这个例子中,它用于插入一个图片。
- `child` 属性接受一个 `Widget`,这里使用 `Image.asset` 来加载本地图片。
图片资源:
- 确保图片路径正确,并在 `pubspec.yaml` 中声明图片资源。
- 例如:
flutter:assets:- assets/demo.png
使用场景
- 图文混排: 当需要在同一个文本段落中展示图片和文本,比如图标、表情符号或其他装饰性元素。
- 动态内容: 在文章或聊天应用中以富文本形式展示内容,图片作为内嵌元素。
- 自定义格式: 创建带有图片的复杂格式文本,比如新闻应用中的插图或注释。
通过 `WidgetSpan`,你可以在 Flutter 的文本组件中灵活地插入图片和其他小部件,实现更复杂的文本布局和丰富的用户界面体验。
TapGestureRecognizer
`TapGestureRecognizer` 是 Flutter 中用于检测点击手势的一个手势识别器。它通常用于处理文本中的点击事件,特别是在 `TextSpan` 中,使得文本中的某些部分可以响应用户的点击操作。
基本使用
`TapGestureRecognizer` 是 `GestureRecognizer` 的一个子类,它专门用于处理点击(tap)事件。通常情况下,它与 `RichText` 和 `TextSpan` 结合使用,以实现文本的可点击功能。
如何使用 `TapGestureRecognizer`
以下是一个简单示例,展示如何在 `TextSpan` 中使用 `TapGestureRecognizer`,使得文本的一部分可以被点击并响应事件:
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
class TapGestureExample extends StatelessWidget {const TapGestureExample({super.key});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text("Tap Gesture Recognizer Example")),body: Center(child: RichText(text: TextSpan(text: 'Click ',style: const TextStyle(color: Colors.black, fontSize: 18),children: <TextSpan>[TextSpan(text: 'here',style: const TextStyle(color: Colors.blue, decoration: TextDecoration.underline),recognizer: TapGestureRecognizer()..onTap = () {ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Text clicked!')),);},),const TextSpan(text: ' to see the effect.',),],),),),);}
}
解释
`RichText` 和 `TextSpan`:
- `RichText` 用于显示富文本。通过 `TextSpan`,你可以定义不同的文本样式和内容。
`TapGestureRecognizer`:
- 创建一个 `TapGestureRecognizer` 实例并将其分配给 `TextSpan` 的 `recognizer` 属性。
- 使用 `..onTap`(级联操作符)来定义 `onTap` 回调函数,当用户点击该文本时调用。
响应点击:
- 在 `onTap` 回调中使用 `ScaffoldMessenger` 显示一个 `SnackBar`,以反馈用户的点击操作。
注意事项
释放资源:
- 如果在有状态的小部件中使用 `TapGestureRecognizer`,请确保在 `dispose` 方法中调用 `dispose` 方法来释放手势识别器,以避免内存泄漏。
多手势识别:
- `TapGestureRecognizer` 可以与其他类型的手势识别器一起使用。使用 `GestureDetector` 可以创建更复杂的手势识别场景。
用户体验:
- 确保可点击的文本有视觉上的提示,如颜色变化或下划线,以便用户能够清楚地识别哪些文本是可交互的。
通过 `TapGestureRecognizer`,你可以为文本添加交互功能,使得应用的用户界面更加动态和响应用户操作。
富文本代码实现学习
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:gsy_flutter_demo/widget/rich/real_rich_text.dart';class RichTextDemoPage extends StatefulWidget {const RichTextDemoPage({super.key});@override_RichTextDemoState createState() => _RichTextDemoState();
}class _RichTextDemoState extends State<RichTextDemoPage> {@overrideWidget build(BuildContext mainContext) {return Scaffold(appBar: AppBar(title: const Text("RichTextDemoPage"),),body: Container(margin: const EdgeInsets.all(10),child: Builder(builder: (context) {return Center(child: RealRichText([TextSpan(text: "A Text Link",style: const TextStyle(color: Colors.red, fontSize: 14),recognizer: TapGestureRecognizer()..onTap = () {show(context, "Link Clicked.");},),ImageSpan(const AssetImage("static/demo.png"),imageWidth: 24,imageHeight: 24,),ImageSpan(const AssetImage("static/demo.png"),imageWidth: 24,imageHeight: 24,margin: const EdgeInsets.symmetric(horizontal: 10)),const TextSpan(text: "哈哈哈",style: TextStyle(color: Colors.yellow, fontSize: 14),),TextSpan(text: "@Somebody",style: const TextStyle(color: Colors.black,fontSize: 14,fontWeight: FontWeight.bold),recognizer: TapGestureRecognizer()..onTap = () {show(context, "Link Clicked.");},),TextSpan(text: " #RealRichText# ",style: const TextStyle(color: Colors.blue, fontSize: 14),recognizer: TapGestureRecognizer()..onTap = () {show(context, "Link Clicked.");},),const TextSpan(text: "showing a bigger image",style: TextStyle(color: Colors.black, fontSize: 14),),ImageSpan(const AssetImage("static/demo.png"),imageWidth: 24,imageHeight: 24,margin: const EdgeInsets.symmetric(horizontal: 5)),const TextSpan(text: "and seems working perfect……",style: TextStyle(color: Colors.black, fontSize: 14),),]),);}),),);}show(context, text) {ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(text),action: SnackBarAction(label: 'ACTION',onPressed: () {ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('You pressed snackbar\'s action.'),));},),));}
}
三方flutter库中的富文本实现源码
import 'dart:ui' as ui show Image;import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';/// According to the related Flutter Issues(#2022) ,
/// Inline-Image-In-Text is a long-time(2 years) missing feature since RichText(or the underlying Paragraph) does only support pure text.
/// But we can solve this problem in a simple/tricky way:
///
/// 1. Regarde the images as a particular blank TextSpan,
/// convert image's width and height to textspan's letterSpacing and fontSize.
/// the origin paragraph will do the layout operation and leave the desired image space for us.
/// 2. Override the paint function,
/// calculate the right offset via the getOffsetForCaret() api to draw the image over the space.
///
/// The only thing you have to do is converting your origin text to a TextSpan/ImageSpan List first.
///
/// {@tool sample}
///
/// ```dart
/// RealRichText([
/// TextSpan(
/// text: "showing a bigger image",
/// style: TextStyle(color: Colors.black, fontSize: 14),
/// ),
/// ImageSpan(
/// AssetImage("packages/real_rich_text/images/emoji_10.png"),
/// width: 40,
/// height: 40,
/// ),
/// TextSpan(
/// text: "and seems working perfect……",
/// style: TextStyle(color: Colors.black, fontSize: 14),
/// ),
/// ])
/// ```
/// {@end-tool}
///
class RealRichText extends Text {final List<TextSpan> textSpanList;const RealRichText(this.textSpanList, {super.key,TextStyle? style,TextAlign textAlign = TextAlign.start,TextDirection? textDirection,bool softWrap = true,TextOverflow overflow = TextOverflow.clip,TextScaler? textScaler,int? maxLines,Locale? locale,}) : super("",style: style,textAlign: textAlign,textDirection: textDirection,softWrap: softWrap,overflow: overflow,textScaler: textScaler,maxLines: maxLines,locale: locale);List<TextSpan> extractAllNestedChildren(TextSpan textSpan) {if (textSpan.children == null || textSpan.children!.isEmpty) {return [textSpan];}List<TextSpan> childrenSpan = [];for (var child in textSpan.children!) {childrenSpan.addAll(extractAllNestedChildren(child as TextSpan));}return childrenSpan;}@overrideWidget build(BuildContext context) {final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context);TextStyle? effectiveTextStyle = style;if (style == null || style!.inherit) {effectiveTextStyle = defaultTextStyle.style.merge(style);}if (MediaQuery.boldTextOf(context)) {effectiveTextStyle =effectiveTextStyle!.merge(const TextStyle(fontWeight: FontWeight.bold));}TextSpan textSpan = TextSpan(style: effectiveTextStyle,text: "",children: extractAllNestedChildren(TextSpan(style: effectiveTextStyle,text: "",children: textSpanList,)));// pass the context to ImageSpan to create a ImageConfigurationfor (var f in textSpan.children!) {if (f is ImageSpan) {f.updateImageConfiguration(context);}}Widget result = _RichTextWrapper(textAlign: textAlign ?? defaultTextStyle.textAlign ?? TextAlign.start,textDirection: textDirection,// RichText uses Directionality.of to obtain a default if this is null.locale: locale,// RichText uses Localizations.localeOf to obtain a default if this is nullsoftWrap: softWrap ?? defaultTextStyle.softWrap,overflow: overflow ?? defaultTextStyle.overflow,textScaler: textScaler ?? MediaQuery.textScalerOf(context),maxLines: maxLines ?? defaultTextStyle.maxLines,text: textSpan);if (semanticsLabel != null) {result = Semantics(textDirection: textDirection,label: semanticsLabel,child: ExcludeSemantics(child: result,));}return result;}
}/// Since flutter engine does not support inline-image for now, we have to support this feature via a tricky solution:
/// convert image to a particular TextSpan whose text always be \u200B(a zero-width-space).
/// set letterSpacing by the required image width
/// set fontSize by the required image height
class ImageSpan extends TextSpan {final double imageWidth;final double imageHeight;final EdgeInsets? margin;final ImageProvider imageProvider;final ImageResolver imageResolver;ImageSpan(this.imageProvider, {this.imageWidth = 14.0,this.imageHeight = 14.0,this.margin,super.recognizer,}) : imageResolver = ImageResolver(imageProvider),super(style: TextStyle(color: Colors.transparent,letterSpacing:imageWidth + (margin == null ? 0 : margin.horizontal),height: 1,fontSize: (imageHeight / 1.15) +(margin == null ? 0 : margin.vertical)),text: "\u200B",children: []);void updateImageConfiguration(BuildContext context) {imageResolver.updateImageConfiguration(context, imageWidth, imageHeight);}double get width => imageWidth + (margin == null ? 0 : margin!.horizontal);double get height => imageHeight + (margin == null ? 0 : margin!.vertical);
}typedef ImageResolverListener = void Function(ImageInfo imageInfo, bool synchronousCall);class ImageResolver {final ImageProvider imageProvider;ImageStream? _imageStream;ImageConfiguration? _imageConfiguration;ui.Image? image;ImageResolverListener? _listener;ImageResolver(this.imageProvider);/// set the ImageConfiguration from outsidevoid updateImageConfiguration(BuildContext context, double width, double height) {_imageConfiguration = createLocalImageConfiguration(context,size: Size(width, height),);}ImageStreamListener? imageStreamListener;void resolve(ImageResolverListener listener) {assert(_imageConfiguration != null);final ImageStream? oldImageStream = _imageStream;_imageStream = imageProvider.resolve(_imageConfiguration!);assert(_imageStream != null);_listener = listener;if (_imageStream!.key != oldImageStream?.key) {if (imageStreamListener != null) {oldImageStream?.removeListener(imageStreamListener!);}imageStreamListener ??= ImageStreamListener(_handleImageChanged);_imageStream!.addListener(imageStreamListener!);}}void _handleImageChanged(ImageInfo imageInfo, bool synchronousCall) {image = imageInfo.image;_listener?.call(imageInfo, synchronousCall);}void addListening() {if (_listener != null) {imageStreamListener ??= ImageStreamListener(_handleImageChanged);_imageStream?.addListener(imageStreamListener!);}}void stopListening() {if (imageStreamListener != null) {_imageStream?.removeListener(imageStreamListener!);}}
}/// Just a subclass of RichText for overriding createRenderObject
/// to return a [_RealRichRenderParagraph] object
///
/// No more special purpose.
class _RichTextWrapper extends RichText {_RichTextWrapper({required TextSpan super.text,super.textAlign,super.textDirection,super.softWrap,super.overflow,super.textScaler,super.maxLines,super.locale,}) : assert(maxLines == null || maxLines > 0);@overrideRenderParagraph createRenderObject(BuildContext context) {assert(textDirection != null || debugCheckHasDirectionality(context));return _RealRichRenderParagraph(text as TextSpan,textAlign: textAlign,textDirection: textDirection ?? Directionality.of(context),softWrap: softWrap,overflow: overflow,textScaler: textScaler,maxLines: maxLines,locale: locale ?? Localizations.localeOf(context),);}
}/// paint the image on the top of those ImageSpan's blank space
class _RealRichRenderParagraph extends RenderParagraph {_RealRichRenderParagraph(TextSpan super.text,{required super.textAlign,required super.textDirection,required super.softWrap,required super.overflow,required super.textScaler,super.maxLines,super.locale});@overridevoid paint(PaintingContext context, Offset offset) {super.paint(context, offset);// Here it is!paintImageSpan(context, offset);}@overridevoid attach(covariant Object owner) {super.attach(owner as PipelineOwner);for (var textSpan in (text as TextSpan).children!) {if (textSpan is ImageSpan) {textSpan.imageResolver.addListening();}}}@overridevoid detach() {super.detach();for (var textSpan in (text as TextSpan).children!) {if (textSpan is ImageSpan) {textSpan.imageResolver.stopListening();}}}@overridevoid performLayout() {super.performLayout();debugPrint("size = $size");}/// this method draws inline-image over blank text space.void paintImageSpan(PaintingContext context, Offset offset) {final Canvas canvas = context.canvas;final Rect bounds = offset & size;debugPrint("_RealRichRenderParagraph offset=$offset bounds=$bounds");canvas.save();int textOffset = 0;for (TextSpan textSpanin (text as TextSpan).children as Iterable<TextSpan>) {if (textSpan is ImageSpan) {// this is the top-center point of the ImageSpanOffset offsetForCaret = getOffsetForCaret(TextPosition(offset: textOffset),bounds,);// found this is a overflowed image. ignore itif (textOffset != 0 &&offsetForCaret.dx == 0 &&offsetForCaret.dy == 0) {return;}// this is the top-left point of the ImageSpan.// Usually, offsetForCaret indicates the top-center offset// except the first text which is always (0, 0)Offset topLeftOffset = Offset(offset.dx +offsetForCaret.dx -(textOffset == 0 ? 0 : textSpan.width / 2),offset.dy + offsetForCaret.dy);debugPrint("_RealRichRenderParagraph ImageSpan, textOffset = $textOffset, offsetForCaret=$offsetForCaret, topLeftOffset=$topLeftOffset");// if image is not ready: wait for async ImageInfoif (textSpan.imageResolver.image == null) {textSpan.imageResolver.resolve((imageInfo, synchronousCall) {if (synchronousCall) {paintImage(canvas: canvas,rect: topLeftOffset & Size(textSpan.width, textSpan.height),image: textSpan.imageResolver.image!,fit: BoxFit.scaleDown,alignment: Alignment.center);} else {if (owner == null || !owner!.debugDoingPaint) {markNeedsPaint();}}});textOffset += textSpan.toPlainText().length;continue;}// else: just paint it. bottomCenter Alignment seems better...paintImage(canvas: canvas,rect: topLeftOffset & Size(textSpan.width, textSpan.height),image: textSpan.imageResolver.image!,fit: BoxFit.scaleDown,alignment: Alignment.center);}textOffset += textSpan.toPlainText().length;}canvas.restore();}
}
相关文章:
Flutter富文本实现学习
Flutter 代码如何实现一个带有富文本显示和交互的页面。 前置知识点学习 RealRichText RealRichText 和 ImageSpan 不是 Flutter 框架中内置的组件,而是自定义的组件或来自第三方库。这些组件的实现可以提供比标准 RichText 更丰富的功能,比如在富文本…...
实现某海外大型车企(T)Cabin Wi-Fi 需求的概述 - 4
大家好,我是Q,邮箱:1042484520qq.com。 今天我们在上几讲的基础上再扩展下 Cabin Wi-Fi 的功能需求,讲讲如何使能 5G TCU Wi-Fi STA Bridge 模式。 参考: 实现某海外大型车企(T)Cabin Wi-Fi 需求…...
【GeekBand】C++设计模式笔记15_Proxy_代理模式
1. “接口隔离” 模式 在组件构建过程中,某些接口之间直接的依赖常常会带来很多问题,甚至根本无法实现。采用添加一层间接(稳定)接口,来隔离本来互相紧密关联的接口是一种常见的解决方案。典型模式 FacadeProxyAdapte…...
项目练习:若依系统的svg-icon功能实现
文章目录 一、svg图片准备二、自定义Svg组件三、svg插件开发四、Svg组件使用 一、svg图片准备 src/assets/icons/svg 其中svg目录里,存放了所需要的图片 index.js import Vue from vue import SvgIcon from /components/SvgIcon// svg component// register glob…...
【踩坑/Linux】Vmware中的Ubuntu虚拟机无法访问互联网
Vmware中的Ubuntu虚拟机无法访问互联网 首先前提是我的系统是Ubuntu 16.04系统,vmware workstation选择的是NAT模式,虚拟机内连不上网络 ping www.baidu.com ping: unknown host www.baidu.com首先检查 DNS 解析服务:在虚拟机中打开命令提示…...
深入了解SpringIoc(续篇)
目录 注入 Bean 的方式有哪些? 构造函数注入还是 Setter 注入? Bean 的作用域有哪些? Bean 是线程安全的吗? Bean 的生命周期了解么? 注入 Bean 的方式有哪些? 依赖注入 (Dependency Injection, DI) 的常见方式: 构造函数注入:通过类的构造函…...
嵌入式硬件面试题
1、请问什么是通孔、盲孔和埋孔?孔径多大可以做机械孔,孔径多小必须做激光孔?请问激光微型孔可以直接打在元件焊盘上吗,为什么? 通孔是贯穿整个PCB的过孔,盲孔是从PCB表层连接到内层的过孔,埋孔…...
散斑/横向剪切/迈克尔逊/干涉条纹仿真技术分析
摘要 本博文提供了多种数据类型的干涉条纹仿真,并展示了它们对应的散斑干涉条纹。还分别给出了横向剪切干涉以及剪切散斑干涉条纹的仿真。 一、迈克尔逊干涉与散斑干涉仿真 下图为干涉条纹与对应的散斑干涉条纹的仿真示意图。其中,干涉条纹可认为是源…...
ViiTor实时翻译 2.2.1 | 完全免费的高识别率同声传译软件
ViiTor实时翻译是一款完全免费的实时语音翻译和同声传译软件,支持即时翻译、对话翻译、语音转文字、文本语音合成和AR翻译等功能。它的语音识别和翻译准确率特别高,速度非常快,音质高,并支持6种音色切换。该软件简单易用ÿ…...
uniapp实现为微信小程序扫一扫的功能
引言 随着微信小程序的快速发展,越来越多的开发者开始关注和学习微信小程序的开发。其中,微信小程序的扫一扫功能是非常常用且实用的功能之一。通过扫描二维码,用户可以获取到相关的信息或者实现特定的功能。 正文 在过去,开发者需要使用微信开发者工具以及相关的开发文档…...
ospf 的 状态机详解
OSPF(开放最短路径优先,Open Shortest Path First)协议的状态机是其核心部分之一,用于确保路由器之间的邻接关系(neighbor relationship)建立和路由信息的交换。OSPF的状态机模型由多个状态组成,…...
ElementPlus 自定义封装 el-date-picker 的快捷功能
文章目录 需求分析 需求 分析 我们看到官网上给出的案例如下,但是不太满足我们用户想要的快捷功能,因为不太多,因此需要我们自己封装一些,方法如下 外部自定义该组件的快捷内容 export const getPickerOptions () > {cons…...
【面试系列】深入浅出 Spring Boot
熟悉SpringBoot,对常用注解、自动装配原理、Jar启动流程、自定义Starter有一定的理解; 面试题 Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?Spring Boot的自动配置原理是什么?你如何理解 Spring Boot 配置…...
太阳能LED路灯智能控制系统(论文+源码)
1系统的功能及方案设计 本次课题为太阳能LED路灯智能控制系统,其系统整体架构如图2.1所示,太阳能板通过TP4056充电模块给锂电池进行充电,电池通过HX3001升压模块进行升压到5V给整个控制系统进行供电,控制系统由AT89C52单片机作为…...
使用 PyQt5 构建高效的文件分类与管理工具
当我们处理大量图片或文件时,经常会需要一款方便、高效的工具来快速分类、整理和管理它们。今天,我将分享一个用 PyQt5 构建的实用项目,涵盖图片分类、文件夹管理、撤销功能,以及动态界面操作的实现。从设计到代码细节,…...
谷歌浏览器 Chrome 提示:此扩展程序可能很快将不再受支持
问题现象 在Chrome 高版本上的扩展管理页面(地址栏输入chrome://extensions/或者从界面进入): , 可以查看到扩展的情况。 问题现象大致如图: 问题原因 出现此问题的根本原因在于:谷歌浏览器本身的扩展机制发生了…...
肿瘤电场仪疗法原理:科技之光,照亮抗癌之路
在医疗科技日新月异的今天,肿瘤电场仪疗法作为一种创新的无创治疗手段,正以其独特的物理机制和生物效应,为患者带来了新的治疗选择和希望。本文将深入探讨肿瘤电场仪疗法的原理,揭示其如何在不伤害正常组织的前提下,精…...
scala基础学习_运算符
文章目录 scala运算符算术运算符关系运算符逻辑运算符位运算符其他运算符赋值运算符 scala运算符 在 Scala 中,运算符通常被定义为方法。这意味着你可以将运算符视为对象上的方法调用。以下是一些常用的运算符及其对应的操作: 算术运算符 :…...
人工智能与区块链的碰撞:双剑合璧的创新前景
引言 人工智能(AI)与区块链技术,这两项曾经各自独立发展的前沿科技,如今正逐步走向融合。人工智能通过强大的数据处理能力和智能决策能力,在各个领域掀起了革命性的变革;而区块链凭借其去中心化、不可篡改的…...
信创数据防泄漏中信创沙箱是什么样的安全方案
在信息化与工业化融合创新(信创)的快速发展中,企业面临着日益复杂的数据安全挑战。SDC沙盒技术以其独特的安全机制和先进的设计理念,为信创环境提供了强有力的数据保护支持。以下是SDC沙盒在信创领域支持能力的几个关键侧重点&…...
在不同操作系统上安装 PostgreSQL
title: 在不同操作系统上安装 PostgreSQL date: 2024/12/26 updated: 2024/12/26 author: cmdragon excerpt: PostgreSQL 是当今最受欢迎的开源关系数据库管理系统之一,由于其强大的功能和灵活性,广泛应用于不同的行业和应用场景。在开始使用 PostgreSQL 之前,用户需要了…...
Linux下编译 libwebsockets简介和使用示例
目录 1:简单介绍: 2:项目地址 3:编译 3.1:集成介绍 3.2:编译 4:客户端服务端示例: 4.1 客户端示例 4.2 服务端示例: 1:简单介绍: Linux下…...
5G CPE接口扩展之轻量型多口千兆路由器小板选型
多口千兆路由器小板选型 方案一: 集成式5口千兆WIFI路由器小板方案二:交换板 + USBwifiUSB WIFI选型一USBwifi选型二:四口千兆选型一四口千兆选型二:四口千兆选型三:部分5G CPE主板不支持Wifi,并且网口数量较少,可采用堆叠方式进行网口和wifi功能 扩展,本文推荐一些路由…...
青少年编程与数学 02-005 移动Web编程基础 02课题、视口与像素
青少年编程与数学 02-005 移动Web编程基础 02课题、视口与像素 一、视口二、布局视口(Layout Viewport)三、视觉视口(Visual Viewport)四、理想视口(Ideal Viewport)五、视口设置关键属性示例代码示例1&…...
深度学习blog-Transformer-注意力机制和编码器解码器
注意力机制:当我们看一个图像或者听一段音频时,会根据自己的需求,集中注意力在关键元素上,以获取相关信息。 同样地,注意力机制中的模型也会根据输入的不同部分,给它们不同的权重,并集中注意力在…...
【论文投稿】Python 网络爬虫:探秘网页数据抓取的奇妙世界
【IEEE出版|广东工业大学主办】第五届神经网络、信息与通信工程国际学术会议(NNICE 2025)_艾思科蓝_学术一站式服务平台 目录 前言 一、Python—— 网络爬虫的绝佳拍档 二、网络爬虫基础:揭开神秘面纱 (一)工作原…...
【总结整理】 神经网络与深度学习 邱锡鹏 课后习题答案 扩展阅读链接
本文主要针对神经网络神经网络邱锡鹏 2~8 章的课后习题进行理解的过程中,搜索到的讲的会比较透彻的链接整理。适合有一定基础但是想了解更细的人阅读。 主要参考书籍 首先是本书pdf可在神经网络与深度学习获取; 主要参考的课后习题答案为nndl/solution…...
华为手机建议使用adb卸载的app
按需求自行卸载 echo 卸载智慧搜索 adb shell pm uninstall -k --user 0 com.huawei.search echo 卸载智慧助手 adb shell pm uninstall -k --user 0 com.huawei.intelligent echo 卸载讯飞语音引擎 adb shell pm uninstall -k --user 0 com.iflytek.speechsuite echo 卸载快应…...
找到一个linux静态库动态库的好资料.2
# 正文 继续整理从这个页面学到的东西:https://tldp.org/HOWTO/Program-Library-HOWTO 这一篇主要参考这俩: https://tldp.org/HOWTO/Program-Library-HOWTO/introduction.html https://tldp.org/HOWTO/Program-Library-HOWTO/static-libraries.html 这…...
存储块的原理与创建
目录 问题概述 malloc和free 固定块大小分配 设计原理 设计实现 为RTOS提供内存管理与回收机制 问题概述 malloc和free extern void *malloc(unsigned int num_bytes); //malloc向系统申请分配指定size个字节的内存空间。 //返回类型是void *类型 extern void free(void *ptr);…...
RabbitMQ工作模式(详解 工作模式:简单队列、工作队列、公平分发以及消息应答和消息持久化)
文章目录 十.RabbitMQ10.1 简单队列实现10.2 Work 模式(工作队列)10.3 公平分发10.4 RabbitMQ 消息应答与消息持久化消息应答概念配置 消息持久化概念配置 十.RabbitMQ 10.1 简单队列实现 简单队列通常指的是一个基本的消息队列,它可以用于…...
电脑提示报错NetLoad.dll文件丢失或损坏?是什么原因?
一、NetLoad.dll文件丢失或损坏的根源 程序安装不完整:某些程序在安装过程中可能因为磁盘错误、网络中断或安装程序本身的缺陷,导致NetLoad.dll文件未能正确安装或复制。 恶意软件攻击:病毒、木马等恶意软件可能会篡改或删除系统文件&#x…...
【物联网技术与应用】实验15:电位器传感器实验
实验15 电位器传感器实验 【实验介绍】 电位器可以帮助控制Arduino板上的LED闪烁的时间间隔。 【实验组件】 ● Arduino Uno主板* 1 ● 电位器模块* 1 ● USB电缆*1 ● 面包板* 1 ● 9V方型电池* 1 ● 跳线若干 【实验原理】 模拟电位器是模拟电子元件,模…...
WPF 绘制过顶点的圆滑曲线(样条,贝塞尔)
项目中要用到样条曲线,必须过顶点,圆滑后还不能太走样,捣鼓一番,发现里面颇有玄机,于是把我多方抄来改造的方法发出来,方便新手: 如上图,看代码吧: -------------------…...
YOLOv9-0.1部分代码阅读笔记-assigner.py
assigner.py utils\tal\assigner.py 目录 assigner.py 1.所需的库和模块 2.def select_candidates_in_gts(xy_centers, gt_bboxes, eps1e-9): 3.def select_highest_overlaps(mask_pos, overlaps, n_max_boxes): 4.class TaskAlignedAssigner(nn.Module): 1.所需的库…...
mybatis-plus自动填充时间的配置类实现
mybatis-plus自动填充时间的配置类实现 在实际操作过程中,我们并不希望创建时间、修改时间这些来手动进行,而是希望通过自动化来完成,而mybatis-plus则也提供了自动填充功能来实现这一操作,接下来,就来了解一下mybatis…...
fgets TAILQ_INSERT_TAIL
If you’re using the macros from <sys/queue.h> to implement a circular doubly linked list (TAILQ), the inversion issue occurs because you’re using LIST_INSERT_HEAD, which inserts at the head of the list. Instead, to maintain the original order (FIFO…...
upload-labs关卡记录12
直接上传一句话木马,发现提示: 很明显这是一个白名单,而且不是前端的js检查,而是服务端的检查,因此我们使用bp抓包,改一下文件类型试试: 找到包之后,我们对content-type进行一个更改…...
服务器被攻击怎么办
当服务器遭受恶意流量攻击,如DDoS(分布式拒绝服务)或CC(Challenge Collapsar)攻击时,传统的防护措施可能不足以应对。此时,采用高防IP服务可以有效缓解攻击压力,确保业务连续性和数据…...
Node.js 助力前端开发:自动化操作实战
前端开发中,重复性任务如新建文件、配置路由、生成组件等,往往耗时且容易出错。借助 Node.js 的强大能力,我们可以实现开发过程中的自动化操作,提高效率。 文章目录 自动生成 router 配置文件自动生成组件模板动态构建导航菜单自…...
MATLAB符号计算-符号表达式基础运算操作
1.1.2符号变量取值域的限定 默认复数域 【例1-1-2】解不等式 1.1.3创建符号表达式 对符号对象进行各种运算(算术运算、关系运算、逻辑运算),即可创建符号表达式。 1.算术运算与转置 【例1-1-3】 f5是f4的共轭转置 f6是f4的转置 2.关系…...
ADB 上传文件并使用脚本监控上传百分比
有个需求,需要测试 emmc的外部连续写入性能,使用 ADB 上传一个巨大的文件。并且在上传到一定值时进行干预。 因此但是 adb push 命令本身会 block 运行并且不返回进度,因此需要一个额外的监控脚本。 上传脚本: echo off setloc…...
深入解析MySQL索引结构:从数组到B+树的演变与优化
前言: 在数据库查询中,索引是一种关键的性能优化工具。然而,索引的失效可能导致查询效率大幅下降。为了更好地理解索引的工作原理及规避其失效,深入了解索引结构的演变过程尤为重要。 MySQL 的索引数据结构从简单到复杂࿰…...
【玩转MacBook】JDK安装
下载 JDK 8 官网:https://www.oracle.com/cn/java/technologies/downloads/archive/ 找到 JDK 8 选择: 安装 JDK 双击 .dmg 文件: 继续双击: “继续” “继续” 走到这里,我发现只能选择这个“为这台电脑上的所有…...
word无法创建工作文件,检查临时环境变量。
word无法创建工作文件,检查临时环境变量。 word preview版本,关联打开文件出现报错。word无法创建工作文件,检查临时环境变量。 打开注册表,删除键 Word Preview: HKCR\CLSID{84F66100-FF7C-4fb4-B0C0-02CD7FB668FE} PowerPoint …...
威联通NAS部署openwrt软路由保姆级教程附镜像文件
创作立场:原创不易,拒绝搬运~ hello 大家好,我是你们的老伙伴,稳重的大王~ 本期教程为大家分享,怎么在NAS里面部署软路由,下面是软路由的镜像文件,有两个版本,400M的是定制版~ Sh…...
MySQL共享锁,排他锁
在 MySQL 中,共享锁(S 锁) 和 排他锁(X 锁) 是两种主要的锁机制,用于处理事务的并发控制。它们的作用和行为如下: 1. 共享锁 (S 锁) 定义: 共享锁允许事务对某一行数据进行读取&am…...
2. FPGA基础了解--全局网络
前言 引入扇出的概念介绍FPGA中的全局网络为后续时序优化埋下伏笔 扇出 在FPGA设计中扇出是一个重要的概念,所谓的扇出就是一个控制信号所能控制的数据信号的总个数,比如ctrl信号的扇出就是16 reg ctrl 0; reg [15:0] out 0; always (posedge c…...
[c++进阶(三)]单例模式及特殊类的设计
1.前言 在实际场景中,总会遇见一些特殊情况,比如设计一个类,只能在堆上开辟空间, 或者是设计一个类只能实例化一个对象。那么我们应该如何编写代码呢?本篇将会详细的介绍 本章重点: 本篇文章着重讲解如何设计一些特殊 的类,包括不能被拷贝,只能在栈/堆上…...
js版本之ES6特性简述【let和const、数组、函数、集合、Symbol】(四)
目录 let [块级作用域] 和const简述 Array.from Array.of Array.prototype中新增的方法 for...of 函数参数调整 集合类型 Map Set WeakMap WeakSet Set WeakSet Map WeakMap Symbol 类型 let [块级作用域] 和const简述 ES6 新增了let命令,用来声明变…...