[Flutter]页面跳转和传值

一、页面跳转

1.基本页面跳转

Navigator 介绍

在 Flutter 中,Navigator 是一个管理应用视图(页面)的组件,它使用栈(Stack)的方式来控制页面的切换。每当你跳转到一个新页面时,Navigator 会将新页面的 Route 压栈(push),当你返回到之前的页面时,它会将当前页面的 Route 出栈(pop)。

为了使用 Navigator 进行页面跳转,我们需要使用 BuildContext,它表示当前 widget 在 widget 树中的位置。BuildContext 是用于与 Navigator 进行交互的必要参数。

Navigator.push 方法

Navigator.push 方法用于将新的 Route 压入栈中,从而导航到新页面。

Navigator.push(context,MaterialPageRoute(builder: (context) => NewPage()),
);

或这种写法

Navigator.push(context, MaterialPageRoute(builder: (context) {return NewPage();},
));

Navigator.pop 方法

Navigator.pop 方法用于将栈顶的 Route 弹出,返回到前一个页面。

Navigator.pop(context);

MaterialPageRoute 和页面跳转动画

MaterialPageRoute 是一种模态路由,它会根据目标平台的规范,为页面切换提供适当的动画。在 Android 上,它通常是一个从屏幕底部向上滑入的动画,而在 iOS 上,它通常是一个从屏幕右侧滑入的动画。

无参数页面跳转示例代码

import 'package:flutter/material.dart';void main() {runApp(MaterialApp(title: 'Navigation Basics',home: HomePage(),));
}class HomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Home Page'),),body: Center(child: ElevatedButton(child: Text('Open New Page'),onPressed: () {// 使用 Navigator.push 方法来跳转到新页面Navigator.push(context,MaterialPageRoute(builder: (context) => NewPage()),);},),),);}
}class NewPage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('New Page'),),body: Column(children: [Text('Welcome to the new page!'),TextButton(onPressed: () {Navigator.pop(context);},child: Text("pop"))],),);}
}

2.命名路由和路由表

命名路由介绍

命名路由是一种用于管理页面导航的技术,它允许你为每个页面分配一个唯一的名称,并通过这些名称在应用程序中进行页面之间的导航。命名路由,由一对字符串(路由名称)和对应的屏幕(或称为页面/视图)组成。

命名路由的好处

  • 提高代码可维护性命名路由使得路由和它们对应的屏幕解耦,这让查找和修改特定路由相关的代码变得更加容易。
  • 简化路由管理当应用的结构变得更为复杂时,使用命名路由可以帮助集中管理路由,而不是在代码中散布大量的 Navigator.push 和 MaterialPageRoute

配置命名路由

我们可以在 MaterialApp 的 routes 属性中定义所有的命名路由。routes 是一个 Map,它的键是字符串(路由的名称),而值是对应的构造器函数,返回相应的页面 Widget。

MaterialApp(title: 'Navigation with Named Routes',// 初始路由,应用启动时加载的路由initialRoute: '/',// 定义命名路由routes: {'/': (context) => HomePage(),'/newPage': (context) => NewPage(),'/thirdPage': (context) => ThirdPage(),},
)

Navigator.pushNamed 方法

要使用命名路由进行页面跳转,可以调用 Navigator.pushNamed 方法,并传入对应的路由名称。

Navigator.pushNamed(context, '/newPage');

Navigator.pop 方法

Navigator.pop 方法用于将栈顶的 Route 弹出,返回到前一个页面。

Navigator.pop(context);

Navigator.popAndPushNamed 方法

Navigator.popAndPushNamed 方法用于从当前页面返回到上一个页面,并立即导航到指定的命名路由。

该方法的作用是先执行 Navigator.pop 方法返回到上一个页面,然后立即执行 Navigator.pushNamed 方法导航到新的命名路由。

Navigator.popAndPushNamed(context, '/thirdPage');

配置和使用命名路由示例代码

import 'package:flutter/material.dart';void main() {runApp(MaterialApp(title: 'Navigation with Named Routes',// 初始路由,应用启动时加载的路由initialRoute: '/',// 定义命名路由routes: {'/': (context) => HomePage(),'/newPage': (context) => NewPage(),'/thirdPage': (context) => ThirdPage(),},));
}class HomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Home Page'),),body: Center(child: ElevatedButton(child: Text('Open New Page'),// 使用命名路由进行页面跳转onPressed: () {Navigator.pushNamed(context, '/newPage');},),),);}
}class NewPage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('New Page'),),body: Column(children: [Text('Welcome to the new page!'),TextButton(onPressed: () {Navigator.popAndPushNamed(context, '/thirdPage');},child: Text("popAndPushNamed"))],),);}
}class ThirdPage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Third Page'),),body: Column(children: [Text('Welcome to the Third page!'),TextButton(onPressed: () {Navigator.pop(context);},child: Text("pop"))],),);}
}

二、页面传值

1.push时向新页面传递数据

(1).通过构造函数传递数据

最直接的方式是通过目标页面的构造函数直接传递数据。

import 'package:flutter/material.dart';void main() {runApp(MaterialApp(home: HomePage(),));
}class HomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Home Page'),),body: Center(child: ElevatedButton(child: Text('Pass Data to New Page'),onPressed: () {// 通过构造函数直接传递数据Navigator.push(context,MaterialPageRoute(builder: (context) => NewPage(data: 'Hello from Home Page!'),),);},),),);}
}class NewPage extends StatelessWidget {final String data;// 接收数据的构造函数NewPage({required this.data});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('New Page'),),body: Center(child: Text(data), // 显示传递过来的数据),);}
}

(2).使用 MaterialPageRoute 的 arguments 属性

另一种传递数据的方式是使用 MaterialPageRoute 的 arguments 属性,这在使用命名路由时尤其有用。

import 'package:flutter/material.dart';void main() {runApp(MaterialApp(// 初始路由,应用启动时加载的路由initialRoute: '/',// 定义命名路由routes: {'/': (context) => HomePage(),'/newPage': (context) => NewPage(),},));
}class HomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Home Page'),),body: Center(child: ElevatedButton(child: Text('Pass Data to New Page'),onPressed: () {Navigator.pushNamed(context,'/newPage',arguments: 'Hello from Home Page!',);},),),);}
}class NewPage extends StatelessWidget {@overrideWidget build(BuildContext context) {// 获取传递过来的数据final String data = ModalRoute.of(context)!.settings.arguments as String;return Scaffold(appBar: AppBar(title: Text('New Page'),),body: Center(child: Text(data), // 显示传递过来的数据),);}
}

2.pop时返回数据给前一个页面

使用 Navigator.pop 返回结果

当从一个页面返回到前一个页面时,可以通过 Navigator.pop 方法返回数据:

// 假设这是 NewPage 中的一个按钮,当点击时返回数据给前一个页面
ElevatedButton(onPressed: () {Navigator.pop(context, 'Result from New Page');},child: Text('Return Data to Home Page'),
),

Navigator.push 和 await 结合使用

你可以使用 await 关键字等待一个页面返回结果:

// ... HomePage 中的按钮点击事件
onPressed: () async {final result = await Navigator.push(context,MaterialPageRoute(builder: (context) => NewPage()),);// 使用 ScaffoldMessenger 显示返回的结果ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(result?.toString() ?? 'No result')),);
},

onPressed: () async {final result = await Navigator.pushNamed(context,'/newPage',arguments: 'Hello from Home Page!',);// 使用 ScaffoldMessenger 显示返回的结果ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(result?.toString() ?? 'No result')),);},
),

使用 PopScope 拦截系统返回按钮的行为

如果你不显式的调用Navigator.pop(context, 'xxx'),就拿不到回传结果。比如你从系统导航上点击返回按钮,就没数据传递回去。

如果一定任何返回都回传值,就需要定义导航栏,或者通过使用 PopScope widget 来拦截系统返回按钮的行为,并执行自定义的操作。

class NewPage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('New Page'),),body: PopScope(canPop: false, // 使用canPop提前禁用poponPopInvoked: (bool didPop) {// canPop被设置为false时。didPop参数表示返回导航是否成功。// `didPop`参数会告诉你路由是否成功地pop出if (!didPop) {// 在这里执行你的操作,比如返回数据. 前面不禁用pop的话,这里就会pop两次了。Navigator.pop(context, 'Custom back button result');}},child: Column(children: [TextButton(onPressed: () {Navigator.pop(context, 'Result from New Page');},child: Text("pop"))],),),);}
}

注意:这里用多个地方调用Navigator.pop,从不同地方返回时,回传的值也会不同。如果要求回传的数据一致,就将Navigator.pop方法抽离放到一个方法中,多个返回位置调用同一个方法回传同样的数据。

三、路由生成钩子(onGenerateRoute)

在Flutter中,onGenerateRoute是一个非常强大的钩子,允许开发者对路由进行自定义操作。它在MaterialAppCupertinoApp中定义,并在导航到命名路由时被调用,特别是当使用Navigator.pushNamed时。它可以用于动态生成路由,传递参数到新页面,甚至处理未知的路由。

下面是一个使用onGenerateRoute的示例,其中包括了处理动态路由和传递参数到未知页面的代码:

import 'package:flutter/material.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(// 应用初始路由initialRoute: '/',// onGenerateRoute 用于处理动态路由onGenerateRoute: (RouteSettings settings) {// 获取传递过来的参数,如果参数为null,则提供一个空的Mapfinal arguments = settings.arguments as Map<String, dynamic>? ?? {};// 根据 settings.name 处理不同路由switch (settings.name) {case '/':return MaterialPageRoute(builder: (context) => HomePage());case '/details':// 假设 DetailsPage 接受一个 'data' 参数final String data = arguments['data'] as String? ?? '默认值';return MaterialPageRoute(builder: (context) => DetailsPage(data: data));default:// 如果没有匹配的路由,返回到一个未知页面路由return MaterialPageRoute(builder: (context) => UnknownPage());}},);}
}class HomePage extends StatefulWidget {const HomePage({super.key});@overrideState<HomePage> createState() => _HomePageState();
}class _HomePageState extends State<HomePage> {String _data = "缺省值";@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('首页'),),body: Column(children: [Text(_data), // 显示传递到本页面的数据ElevatedButton(onPressed: () async {// 导航到详情页,并传递数据。同时,使用await等待详情页返回的结果final result = await Navigator.pushNamed(context,'/details',arguments: {'data': '这是一个秘密信息!'},);final arguments = result as Map<String, dynamic>? ?? {};setState(() {if (mounted) {_data = arguments["data"] as String? ?? "";}});},child: Text('前往详情页'),),],),);}
}class DetailsPage extends StatelessWidget {final String data;DetailsPage({required this.data});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('详情页'),),body: Column(children: [Text(data), // 显示传递到本页面的数据TextButton(onPressed: () {// 回传数据数据Navigator.pop(context, {'data': '详情返回数据'});},child: Text("pop"))],),);}
}class UnknownPage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('未知页面'),),body: Center(child: Text('该路由名称不存在。'),),);}
}

 四、路由传值的安全性

1.验证传入数据

当通过路由传递数据时,重要的是要验证接收的数据是否符合预期。你可以使用类型检查、正则表达式或自定义验证函数来确保数据的有效性和安全性。

bool isValidData(dynamic data) {// 在这里添加验证逻辑,例如类型检查、内容检查等return data is String && data.isNotEmpty;
}

在使用数据之前,你可以调用这个函数来验证:

if (isValidData(receivedData)) {// 数据有效,可以安全使用
} else {// 数据无效,可以抛出异常或进行错误处理
}

2.处理空值和异常

处理空值和异常是确保应用程序稳定性的重要部分。当你从路由接收数据时,应该始终假设这些数据可能为空或者不是预期的格式。下面是一些处理这些情况的策略:

处理空值

当你期望的数据可能为空时,可以使用Dart的null-aware运算符来优雅地处理:

String data = receivedData ?? '默认值';

或者在使用之前检查数据是否为null:

if (receivedData != null) {// 使用 receivedData
} else {// 处理空值情况,例如返回错误提示或设置默认值
}

异常处理

如果数据转换或验证过程中可能抛出异常,你应该使用try-catch语句来捕获这些异常:

try {// 尝试使用 receivedData
} catch (e) {// 处理异常,例如记录日志、显示错误信息等
}

五、使用 Provider 管理跨页面的状态

Provider 是一个流行的状态管理库,它依赖于 Flutter 的 InheritedWidget 来向下传递数据。它能够让你在 widget 树中跨越多个层级来传递和修改数据,而无需手动传递回调或数据。

使用 Provider,你可以在应用的顶层提供一个状态,然后在应用的任何其他部分访问或修改这个状态。这适用于跨多个页面传递数据,甚至是整个应用的状态管理。

详细使用参见另一文https://gamin.blog.csdn.net/article/details/136556092

1.使用 Provider 进行状态管理和传值

首先,你需要在 pubspec.yaml 文件中添加 provider 依赖项:

dependencies:flutter:sdk: flutterprovider: ^6.1.2 # 使用适合你的版本

然后,在应用顶层(即要包裹住MaterialApp)引入 Provider

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';void main() {runApp(// 通过 MultiProvider 可以提供多个对象MultiProvider(providers: [// ChangeNotifierProvider 是 Provider 的一种,它可以响应通知ChangeNotifierProvider(create: (context) => DataProvider()),],child: MyApp(),),);
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',home: HomePage(),);}
}
// 定义一个继承自 ChangeNotifier 的数据模型,用来传递和响应变化
class DataProvider extends ChangeNotifier {String _data = "初始数据";String get data => _data;void setData(String newData) {_data = newData;notifyListeners(); // 当更新数据时,通知监听的 widgets 进行重建}
}

HomePage 中的按钮点击时,可以使用 Provider 来更新数据:

class HomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {// 使用 Provider.of 来获取最近的 DataProvider 实例final dataProvider = Provider.of<DataProvider>(context);return Scaffold(appBar: AppBar(title: Text('首页'),),body: Center(child: ElevatedButton(onPressed: () {// 更新数据dataProvider.setData('更新的数据');// 导航到详情页Navigator.push(context,MaterialPageRoute(builder: (context) => DetailsPage()),);},child: Text('前往详情页并传递数据'),),),);}
}class DetailsPage extends StatelessWidget {@overrideWidget build(BuildContext context) {// 监听 DataProvider,当数据变化时重建这个 widgetfinal data = Provider.of<DataProvider>(context).data;return Scaffold(appBar: AppBar(title: Text('详情页'),),body: Center(// 显示从 Provider 获取的数据child: Text(data),),);}
}

2.完整的Provider例子

下面是一个使用Provider进行状态管理和跨页面传值的完整示例,包括异常处理和空值检查:

首先,确保已经添加了provider依赖。

// main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return ChangeNotifierProvider<DataModel>(create: (_) => DataModel(),child: MaterialApp(title: 'Flutter Demo',home: HomePage(),),);}
}class DataModel extends ChangeNotifier {String _data = '';String get data => _data;void updateData(String newData) {if (newData.isNotEmpty) {_data = newData;notifyListeners();} else {throw Exception('Data cannot be empty');}}
}class HomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Home')),body: Center(child: Consumer<DataModel>(builder: (context, dataModel, child) {return ElevatedButton(onPressed: () {try {dataModel.updateData('New Data from Home');Navigator.push(context,MaterialPageRoute(builder: (context) => DetailsPage()),);} catch (e) {// Handle the exceptionScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(e.toString())),);}},child: Text('Go to Details'),);},),),);}
}class DetailsPage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Details')),body: Center(child: Consumer<DataModel>(builder: (context, dataModel, child) {return Text(dataModel.data);},),),);}
}

在这个例子中,DataModel 是一个简单的数据持有类,它通过Provider允许在应用程序的其他部分访问和修改数据。HomePage 设置新的数据,并导航到DetailsPageDetailsPage 显示当前的数据。如果尝试设置空的数据,DataModel 将抛出一个异常,该异常在HomePage中被捕获并显示为一个SnackBar

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

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

相关文章

os模块篇(十一)

文章目录 os.chdir(path)os.chmod(path, mode, *, dir_fdNone, follow_symlinksTrue)os.chown(path, uid, gid, *, dir_fdNone, follow_symlinksTrue)os.getcwd()os.getcwdb()os.lchflags(path, flags)os.lchmod(path, mode)os.lchown(path, uid, gid) os.chdir(path) os.chdi…

CSS3 实现文本与图片横向无限滚动动画

文章目录 1. 实现效果2.html结构3. css代码 1. 实现效果 gif录屏比较卡&#xff0c;实际很湿滑&#xff0c;因为是css动画实现的 2.html结构 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"…

Java中的装饰器模式

在Java中&#xff0c;装饰器模式允许我们动态地给对象添加新的行为或责任&#xff0c;而无需修改原有类。以下是一个简单的装饰器模式示例&#xff0c;我们将模拟一个咖啡销售系统&#xff0c;其中基础饮料类&#xff08;Component&#xff09;是Coffee&#xff0c;装饰器类&am…

VC++、GCC、CLANG,INT128有符号整数编译器关键字

注意INT128为目标平台扩展关键字&#xff0c;不属于C/C语言本身支持特性&#xff0c;每个C/C编译器平台支持上都略有不同&#xff0c;甚至不支持。 可以详细参考本人此篇文章&#xff1a; GUN C/C (GCC/CLANG) 对于 __int128_t &#xff08;128位有符号大整数的扩展支持平台限…

vue快速入门(三)差值表达式

注释很详细&#xff0c;直接上代码 上一篇 新增内容 插值表达式基本用法插值表达式常用公式 源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-wid…

M91HV-EX防爆布控球

防爆EX说明 产品介绍 布控球是专为户外无线网络及无供电环境而又需要现场录像取证和远程实时视频监控而打造的一款便携式的智能装备。布控球采用稳定的Linux嵌入式操作系统&#xff0c;运用先进的AI算法技术、5G无线通信技术、AGPS辅助定位技术及H.265视频压缩技术&#xff1b;…

语言模型进化史(上)

由于篇幅原因&#xff0c;本文分为上下两篇&#xff0c;上篇主要讲解语言模型从朴素语言模型到基于神经网络的语言模型&#xff0c;下篇主要讲解现代大语言模型以及基于指令微调的LLM。文章来源是&#xff1a;https://www.numind.ai/blog/what-are-large-language-models 一、语…

【Linux】进程控制详解

目录 前言 进程创建 认识fork 写时拷贝 再谈fork 进程终止 进程退出码 用代码来终止进程 常见的进程终止的方式 exit _exit 进程等待 进程等待的必要性 进程等待的方式 wait waitpid 详解status参数 详解option参数 前言 本文适合有一点基础的人看的&#…

5.3.2 实验2:配置交换机端口安全

1、实验目的 通过本实验可以掌握&#xff1a; 交换机管理地址配置及接口配置。查看交换机的MAC地址表。配置静态端口安全、动态端口安全和粘滞端口安全的方法。 2、实验拓扑 配置交换机端口安全的实验拓扑如图所示。 配置交换机端口安全的实验拓扑 3、实验步骤 &#xff…

Excel中文显示问号

直接上操作步骤&#xff1a; 1&#xff09;打开Excel -> 文件 -> 选项 -> 语言 2&#xff09;Office 显示语言&#xff0c;“中文(简体)”设置为首选。 3&#xff09;Office创作语言和校对&#xff0c;“中文(简体)”设置为首选。 网上用记事本转换的方法&#xff0c;…

【c++】STl-list使用list模拟实现

主页&#xff1a;醋溜马桶圈-CSDN博客 专栏&#xff1a;c_醋溜马桶圈的博客-CSDN博客 gitee&#xff1a;mnxcc (mnxcc) - Gitee.com 目录 1. list的介绍及使用 1.1 list的介绍 1.2 list的使用 1.2.1 list的构造 1.2.2 list iterator的使用 1.2.3 list capacity 1.2.4 …

点大商城V2版 2.5.7全开源版 全插件+百度+支付宝+QQ+头条+小程序端+uniapp开源端

点大商城V2是一款采用全新界面设计支持多端覆盖的小程序应用&#xff0c;支持H5、微信公众号、微信小程序、头条小程序、支付宝小程序、百度小程序&#xff0c;本程序是点大商城V2独立版&#xff0c;包含全部插件&#xff0c;代码全开源&#xff0c;并且有VUE全端代码。分销&am…

【Java基础】Java基础知识整合

文章目录 1. 转义字符2. 变量2.1 字符串与整型相加2.2 byte和short的区别2.3 float和double的区别2.4 char类型2.5 boolean类型2.6 自动类型转换及运算2.7 强制类型转换2.8 String的转换2.9 除法运算2.10 取模规则 3. 自增4. 逻辑运算符5. 赋值运算 6. 三元运算符&#xff1a;7…

babyAGI(7)-babyCoder源码阅读3(任务执行相关agent)

1. 任务分配agent 该agent会根据&#xff0c;objective和task的内容自动分配要执行的agent code_writer_agent 编写新代码或增加新功能使用该agentcode_reactor_agent 任务涉及到修改或优化执行该agentcommand_executor_agent 任务涉及到文件操作执行该agent 整个任务分配的…

前端的拖拽序列(drag)

html和css代码如下 <style>.item {width: 200px;height: 50px;background: rgb(15, 226, 219);margin: 10px 0;padding-left: 20px;border-radius: 10px;line-height: 50px;}.item.move {background: transparent;color: transparent;border: 1px dashed #ccc;}</sty…

关于ubuntu18.04 ARM架构更换源失败的问题

更换源后报错&#xff1a; E: Failed to fetch http://mirrors.tuna.tsinghua.edu.cn/ubuntu/dists/trusty-security/main/binary-arm64/Packages 404 Not Found [IP: 2402:f000:1:400::2 80] E: Failed to fetch http://mirrors.tuna.tsinghua.edu.cn/ubuntu/dists/trusty-…

C++(12): std::mutex及其高级变种的使用

1. 简述 在多线程或其他许多场景下&#xff0c;同时对一个变量或一段资源进行读写操作是一个比较常见的过程&#xff0c;保证数据的一致性和防止竞态条件至关重要。 C的标准库中为我们提供了使用的互斥及锁对象&#xff0c;帮助我们实现资源的互斥操作。 2. std::mutex及其衍…

QT - 日志:qDebug/qInfo/qWarning/qCritical

篇一、日志打印函数 头文件&#xff1a; #include <QDebug> 代码&#xff1a;qDebug()<<"hello world!"; 其他打印级别&#xff1a; qInfo(): 普通信息 qDebug(): 调试信息 qWarning(): 警告信息 qCritical(): 严重错误 qFatal(): 致命错误 1. qDebug…

【Leetcode】279.完全平方数

一、题目 1、题目描述 给你一个整数 n ,返回 和为 n 的完全平方数的最少数量。 完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。 示例1: 输入:n = 12 输出:3 解释:1…

Vue ElementPlus Form、Form-item 表单

Form 表单 由输入框、选择器、单选框、多选框等控件组成&#xff0c;用以收集、校验、提交数据&#xff0c;组件升级采用了 flex 布局&#xff0c;以替代旧版本的 float 布局。 在 Element Plus 中&#xff0c;el-form 是一个表单组件&#xff0c;用于创建表单以便用户填写和提…