当前位置: 首页 > news >正文

Compose Multiplatform+Kotlin Multiplatfrom 第五弹跨平台

截图功能

  Compose Multiplatform+Kotlin Multiplatfrom下实现桌面端的截图功能,起码搞了两星期,最后终于做出来了,操作都很流畅,截取的文件大小也正常,可参考支持讨论!

功能效果

windows截图
mac截图
截图缓存目录

代码实现

//在jvmMain下创建TestCapture11.kt,完整的截图核心功能代码package com.hwj.ai.captureimport androidx.compose.foundation.Canvas
import androidx.compose.foundation.focusable
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.awt.ComposeWindow
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.input.pointer.PointerEventType
import androidx.compose.ui.input.pointer.isSecondaryPressed
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.rememberWindowState
import com.hwj.ai.global.printD
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.awt.GraphicsEnvironment
import java.awt.Rectangle
import java.awt.Robot
import java.awt.Toolkit
import java.awt.image.BufferedImage
import java.io.File
import javax.imageio.ImageIO//UI 拖拽得到的坐标 * scaleFactor ≠ 实际屏幕坐标
//macOS 多屏/高DPI 下 Robot 截图区域
//效果suc,windows/macOS 主屏幕
class ScreenshotState11 {var startOffset by mutableStateOf(Offset.Zero)var endOffset by mutableStateOf(Offset.Zero)val selectionRect: Rectget() = Rect(startOffset, endOffset)var isSelecting by mutableStateOf(false)
}val LocalMainWindow = staticCompositionLocalOf<ComposeWindow> { error("No Window provided") }@Composable
fun ScreenshotOverlay11(mainWindow: ComposeWindow,onCapture: (BufferedImage) -> Unit,onCancel: () -> Unit
) {var showActBtn by remember { mutableStateOf(false) }var capturedRect by remember { mutableStateOf<Rect?>(null) }val state = remember { ScreenshotState11() }val screenSize = Toolkit.getDefaultToolkit().screenSizeval windowState = rememberWindowState(position = WindowPosition(0.dp, 0.dp),size = DpSize(screenSize.width.dp, screenSize.height.dp))val subScope = rememberCoroutineScope()val focusReq = remember { FocusRequester() }LaunchedEffect(Unit) {mainWindow.isVisible = false}Window(onCloseRequest = {onCancel()mainWindow.isVisible = true},state = windowState,transparent = true,undecorated = true,alwaysOnTop = true,focusable = true,resizable = false) {LaunchedEffect(Unit) {window.requestFocus() //触发快捷键focusReq.requestFocus()}Box(modifier = Modifier.fillMaxSize().focusRequester(focusReq).focusable().pointerInput(Unit) { //识别鼠标右键取消awaitPointerEventScope {while (true) {val event = awaitPointerEvent()val pressed = event.buttons.isSecondaryPressedif (event.type == PointerEventType.Press && pressed) {onCancel()mainWindow.isVisible = true}}}}.onPreviewKeyEvent { keyEvent ->
//                printD("keyEvent>${keyEvent.key} ${Key.Escape}")if (keyEvent.key == Key.Escape) { //快捷键取消onCancel()mainWindow.isVisible = truetrue} else {false}}.pointerInput(Unit) {detectDragGestures(onDragStart = { offset ->state.isSelecting = truestate.startOffset = offsetstate.endOffset = offset},onDrag = { change, _ ->state.endOffset = change.position},onDragEnd = {capturedRect = state.selectionRect.normalize()//如果只是点了两下,宽高都很少,不足以被认定为截图!showActBtn = true})}) {Canvas(modifier = Modifier.fillMaxSize()) {// 背景遮罩drawRect(Color.Black.copy(alpha = 0.3f))// 选区范围和尺寸if (state.isSelecting) {val rect = state.selectionRect.normalize()// 半透明填充drawRect(color = Color.White.copy(alpha = 0.05f),topLeft = rect.topLeft,size = rect.size)// 白色描边drawRect(color = Color.White,topLeft = rect.topLeft,size = rect.size,style = Stroke(width = 2.dp.toPx()))}}//在截图框下放按钮if (showActBtn && capturedRect != null) {val isFullCapture =capturedRect!!.width > screenSize.width * 0.8f && capturedRect!!.height > screenSize.height * 0.8fval myModifier: Modifierif (isFullCapture) {myModifier = Modifier.align(Alignment.TopEnd).padding(23.dp)} else {val offx = with(LocalDensity.current) { capturedRect!!.right.toDp() - 180.dp }val offy = with(LocalDensity.current) { capturedRect!!.bottom.toDp() + 0.dp }myModifier = Modifier.offset(x = offx, y = offy)}Box(modifier = myModifier) {Row(modifier = Modifier.align(Alignment.BottomCenter).padding(13.dp)) {Button(onClick = {showActBtn = falsemainWindow.isVisible = truestate.isSelecting = false //有必要吗capturedRect = null //点击取消没有退出onCancel() //关闭}) {Text("取消", color = Color.White)}Spacer(modifier = Modifier.width(10.dp))Button(onClick = {if (null != capturedRect) {subScope.launch {captureSelectedArea(capturedRect!!) { pic ->//                                        val thumbnail =
//                                            BufferedImage(
//                                                200,
//                                                200,
//                                                BufferedImage.TYPE_INT_ARGB
//                                            ).apply {
//                                                createGraphics().drawImage(
//                                                    pic.getScaledInstance(
//                                                        200,
//                                                        200,
//                                                        java.awt.Image.SCALE_SMOOTH
//                                                    ),
//                                                    0, 0, null
//                                                )
//                                            }
//                                        onCapture(thumbnail) //传缩略图onCapture(pic)}withContext(Dispatchers.Main) {showActBtn = falsemainWindow.isVisible = trueonCancel()}}} else {showActBtn = falsemainWindow.isVisible = trueonCancel()}}) {Text("确定", color = Color.White)}}}}}}
}private suspend fun captureSelectedArea(rect: Rect, onSuccess: (BufferedImage) -> Unit) {val normalizedRect = rect.normalize()val screenDevices = GraphicsEnvironment.getLocalGraphicsEnvironment().screenDevicesvar targetDevice: java.awt.GraphicsDevice? = null//    // 找到选区落在哪块屏幕上for (device in screenDevices) {val bounds = device.defaultConfiguration.boundsif (bounds.contains(normalizedRect.left.toInt(), normalizedRect.top.toInt())) {targetDevice = devicebreak}}//多屏不让用
//    if (screenDevices.size>1){
//        NotificationsManager().showNotification("不支持多屏截图!","不支持多屏截图")
//        return
//    }//    targetDevice=screenDevices[0]if (targetDevice == null) {targetDevice =java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice}val config = targetDevice!!.defaultConfigurationval screenBounds = config.bounds // 屏幕偏移(多屏布局下重要)val transform = config.defaultTransformval scaleX = transform.scaleXval scaleY = transform.scaleY
//    printD("屏幕 bounds: $screenBounds, scaleX: $scaleX, scaleY: $scaleY")// 关键:Compose 逻辑坐标 → 物理像素坐标 ,超级大坑,用chatgpt写代码一直反馈是乘scaleX,实际是除以,不然容易黑屏val captureX = (normalizedRect.left / scaleX).toInt()val captureY = (normalizedRect.top / scaleY).toInt()val captureW = (normalizedRect.width / scaleX).toInt()val captureH = (normalizedRect.height / scaleY).toInt()//    printD("最终截图区域 (物理像素): x=$captureX, y=$captureY, w=$captureW, h=$captureH")if (captureW <= 0 || captureH <= 0) returntry {// 隐藏截图窗口,防止蒙层被截进去val awtWindow = java.awt.KeyboardFocusManager.getCurrentKeyboardFocusManager().activeWindowawtWindow?.isVisible = falseThread.sleep(100) // 等隐藏生效val robot = Robot(targetDevice)val screenRect = Rectangle(captureX, captureY, captureW, captureH)val image = robot.createScreenCapture(screenRect)onSuccess(image)} catch (e: Exception) {e.printStackTrace()}
}fun saveToFile11(image: BufferedImage): String? {//     val desktopPath = System.getProperty("user.home") + File.separator + "Desktop"
//     val file = File(desktopPath, "screenshot_${System.currentTimeMillis()}.png")val cacheDir = getPlatformCacheImgDir()if (!cacheDir.exists()) cacheDir.mkdirs()val file = File(cacheDir, "screenshot_${System.currentTimeMillis()}.png")ImageIO.write(image, "PNG", file)printD("截图已保存到:${file.absolutePath}")ImageIO.write(image, "PNG", file).also {if (it) return file.absolutePath}return null
}//截图已保存到缓存目录:/Users/你的用户名/Library/Caches/com.hwj.ai.capture/screenshot_1710918988888.png
//截图已保存到缓存目录:C:\Users\你的用户名\AppData\Local\com.hwj.ai.capture\cache\screenshot_1710918988888.png
//截图已保存到缓存目录:/home/你的用户名/.cache/com.hwj.ai.capture/screenshot_1710918988888.png
private fun getPlatformCacheImgDir(): File {val osName = System.getProperty("os.name").lowercase()return if (osName.contains("mac")) {File(System.getProperty("user.home"), "Library/Caches/com.hwj.ai.capture")} else if (osName.contains("win")) {File(System.getenv("LOCALAPPDATA"), "com.hwj.ai.capture/cache")} else {File(System.getProperty("user.home"), ".cache/com.hwj.ai.capture")}
}/*** 扩展方法:统一 start/end,避免负数尺寸*/
private fun Rect.normalize(): Rect {val left = minOf(this.left, this.right)val top = minOf(this.top, this.bottom)val right = maxOf(this.left, this.right)val bottom = maxOf(this.top, this.bottom)return Rect(left, top, right, bottom)
}
//commonMain 下声明接口
@Composable
expect fun ScreenShotPlatform(onSave: (String?) -> Unit)//在jvmMain实现接口内容,其他Android直接空就行了
@Composable
actual fun ScreenShotPlatform(onSave: (String?) -> Unit) {val mainWindow = LocalMainWindow.currentval chatViewModel = koinViewModel(ChatViewModel::class)val isShotState = chatViewModel.isShotState.collectAsState().valueif (isShotState && onlyDesktop()) {ScreenshotOverlay11(mainWindow = mainWindow, onCapture = { pic ->val file = saveToFile11(pic)onSave(file)}, onCancel = {chatViewModel.shotScreen(false)})}
}//调用方式
//在ChatViewModel.kt文件声明截图操作状态,方便全局拉起功能
//是否触发截图private val _isShotObs = MutableStateFlow(false)val isShotState = _isShotObs.asStateFlow()//在composable函数使用val isShotState = chatViewModel.isShotState.collectAsState().value
if (isShotState) {ScreenShotPlatform(onSave = { filePath ->filePath?.let {subScope.launch {conversationViewModel.addCameraImage(PlatformFile(filePath))}}})return}

技术讨论

1.整个思路概述,截图就是新建一个window,在新window进行手势操作,画布绘制,完成截图再把放在单例viewModel的状态变量重置,关闭新window显示主window,不是多window一 开始做手势操作都在应用内,没法在应用外截图。

2.我的截图需求分析是基于java原生api实现的,目前只考虑单显示器,即Windows,Macbook的Retina高分屏,触发截图功能时应用隐藏,主屏幕一层带黑色透明的背景,可多次使用鼠标拖拽绘制选择框,选择框由白色的边框和带白色透明的背景组成,拖拽结束矩形框下方出现操作菜单取消或保存,如果是全屏截图那么菜单按钮则内嵌到选择框的右上角。截图完成可压缩后再保存,但是我看截图文件都不大就注释了,图片路径getPlatformCacheImgDir()注释说明 了。点击保存应用显示,截图功能参数重置,缓存图片并回调图片路径。

3.看预览图windows/mac其实都是共用一套代码,但是菜单按钮显示位置不同时我代码还没同步,修改了下边距,逻辑没问题,然后还有优化点 是某些状态值不是很准确,导致菜单按钮多次取消,后面再修复,大家也可提意见修。

4.实现了快捷键的识别,对Esc可取消截图,鼠标右键也可取消。

5.多屏扩展问题,因为我没有多个显示器,不方便处理这个功能,要注意一个很恶心的问题,mac电脑是高分屏Retina,它的逻辑像素和物理像素有个2倍关系,但是windows是1倍,单屏其实不考虑屏幕偏移量,我在chatgpt示例代码都是把逻辑坐标乘缩放因子,导致我Mac截图一直错位,截黑屏,当时所有AI模型写的都是乘,后来是自己全部截图和测试缩放因子的实际图片发现的问题。

6.macOs系统截图触发会弹权限请求,用户要在系统设置-》隐私与安全性-》屏幕与系统音频录制-》添加应用即可,不然截图就是空白也不报错,调试时发现启用了权限但是线刷程序一样没权限,所以有时我是打包再测,有时又没问题。

7.截图api调用前要等待下线程,不然会把白色的蒙层也截取进去,还有就是注意线程的切换,不然容易造成卡顿 。

总结

  此次是实现java虚拟机的截图功能,很多是思路选择问题,这网上查了没人用compose multiplatform实现截图桌面端,可参考下此文,最近实现豆包的划词工具,也是在Compose Multiplatform下实现,但是目前只实现了剪切板获取用户鼠标选中文字,但是没法恢复用户之前的复制文件,后面解决了再出新文章。也实现了微软的自动化Automataion,不太行,也实现了系统钩子但是只能做到win32的notepad,其他应用不行,有大牛有思路可提意见。

第四弹指达

相关文章:

Compose Multiplatform+Kotlin Multiplatfrom 第五弹跨平台

截图功能 Compose MultiplatformKotlin Multiplatfrom下实现桌面端的截图功能&#xff0c;起码搞了两星期&#xff0c;最后终于做出来了&#xff0c;操作都很流畅&#xff0c;截取的文件大小也正常&#xff0c;可参考支持讨论&#xff01; 功能效果 代码实现 //在jvmMain下创…...

linux安装ollama

俩种方式都可 一、linux通过docker安装ollama镜像 1.下载安装ollama镜像 # 安装 Docker sudo yum install docker sudo systemctl start docker#docker查看所有容器 docker ps -a # 查看所有容器# docker查看指定容器 docker ps -a |grep ollama# 创建模型存储目录&#xff…...

113. 在 Vue 3 中使用 OpenLayers 实现鼠标移动显示坐标信息

✨ 写在前面 在地图类项目开发中&#xff0c;一个常见需求就是&#xff1a;实时获取用户鼠标在地图上的经纬度坐标&#xff0c;并展示在地图上。 本文将通过一个简单的案例&#xff0c;手把手带大家在 Vue 3 项目中集成 OpenLayers 地图库&#xff0c;并实现以下功能&#xf…...

跳跃游戏的最优解法——贪心算法的智慧与实践

跳跃游戏的最优解法——贪心算法的智慧与实践 跳跃游戏是一类经典的算法题&#xff0c;既有趣又充满挑战&#xff0c;不仅能锻炼思维能力&#xff0c;还能直观展现贪心算法的核心思想。今天&#xff0c;我们从题目入手&#xff0c;拆解贪心算法的原理&#xff0c;用通俗易懂的…...

搭建docker registry私服,并且支持https推送

搭建docker registry私服&#xff0c;并且支持https推送 一、为什么写这篇文章二、搭建过程三、验证 一、为什么写这篇文章 网上关于搭建docker registry的文章一大把&#xff0c;但是都是配置为http方式推送&#xff0c;且需要显示端口&#xff0c;这个在真正项目使用中&…...

UniApp Vue 3 中的网络请求封装及用法

在UniApp中&#xff0c;结合Vue 3的强大特性&#xff0c;进行网络请求的封装是项目中常见的需求。这样的封装不仅提高了代码的可维护性&#xff0c;还使得在组件中使用网络请求更加简洁。本文将详细介绍UniApp Vue 3中的网络请求封装&#xff0c;并提供一个简单的用法示例。 创…...

策略模式结合模板方法模式

之前学习了策略模式加模板方法模式 策略模式单独详解 模板方法模式单独详解 这里回忆起完全可以进行策略和模板方法模式的组合。 import java.util.HashMap; import java.util.Map;// 上下文对象&#xff08;解决参数传递问题&#xff09; class OrderContext {private final…...

每日算法-250407

记录一下今天刷的三道 LeetCode 题目。 2389. 和有限的最长子序列 题目 思路 排序 前缀和 二分查找 解题过程 理解题意: 题目要求我们对于 queries 数组中的每个查询值 q&#xff0c;找出 nums 数组中元素和 小于等于 q 的 最长子序列 的长度。注意&#xff0c;是子序列&am…...

【Git “ls-tree“ 命令详解】

本章目录: 1. 命令简介2. 命令的基本语法和用法基本语法常见使用场景示例 1&#xff1a;查看当前提交的文件树示例 2&#xff1a;查看某个分支的文件树示例 3&#xff1a;查看特定路径下的文件树 3. 命令的常用选项及参数常用选项&#xff1a; 4. 命令的执行示例示例 1&#xf…...

Text-to-SQL技术深度解析:从理论突破到工程实践

引言:Text-to-SQL的技术演进与当代价值 在当今数据驱动的商业环境中,结构化数据查询语言(SQL)仍然是访问和分析企业数据的核心工具。然而,SQL的专业性要求构成了数据民主化的主要障碍——据统计,仅约35%的开发人员接受过系统的SQL培训,而超过51%的专业岗位需要SQL技能。T…...

Spring Boot 整合 Servlet三大组件(Servlet / Filter / Listene)

Spring Boot 整合 “Servlet三大组件“ ( Servlet / Filter / Listene ) 目录如下&#xff1a; pom.xml配置 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.…...

react 18 可中断的理解以及应用

React 的“可中断&#xff08;interruptible&#xff09;”渲染&#xff0c;指的是 React 在执行渲染过程中可以暂停、中断、再继续或放弃更新。这是 React 18 引入的并发特性的一部分&#xff0c;目的是让界面响应更流畅&#xff0c;防止“卡顿”。 &#x1f4d6; 举个例子&am…...

C++使用Qt Charts可视化大规模点集

引言 数据可视化是数据分析和决策过程中的重要环节。随着数据量的不断增长&#xff0c;如何高效地可视化大规模数据集成为了一个挑战。Qt Charts 提供了一个强大的工具集&#xff0c;用于创建直观的数据可视化图表。本文将探讨如何使用 C 和 Qt Charts 可视化大规模点集&#…...

第一部分——Docker篇 第二章 Docker安装

关于系统的改造探索 开篇&#xff1a;系统改造的调研报告 第一部分——Docker篇 第一章 Docker容器 第二章 Docker安装 第三章 构建自定义镜像 第四章 搭建镜像仓库 第五章 容器编排 第六章 容器监控 文章目录 关于系统的改造探索第一部分——Docker篇 前言一、在线环境二、…...

Transformer - 多头自注意力机制复现

一、数学原理 1. 多头注意力机制 多头注意力机制允许模型在不同的表示子空间中关注输入序列的不同部分。它通过并行计算多个注意力头来实现这一点&#xff0c;每个头学习序列的不同部分。 2. 注意力分数计算 3. 掩码机制 掩码机制用于防止模型访问某些位置的信息。例如&…...

SpringCloud-快速通关(一)

本文是基于【雷丰阳老师&#xff1a;尚硅谷2025最新SpringCloud - 快速通关】进行实践操作&#xff0c;并对雷神的笔记做一个更详细的补充&#xff0c;供大家学习参考&#xff0c;一起加油&#xff01; 视频地址&#xff1a;SpringCloud快速通关_教程简介_哔哩哔哩_bilibili …...

Ansible Playbook详解:自动化配置管理的核心

1. 引言 Ansible Playbook是Ansible自动化系统的核心,它使用YAML格式描述一系列要在远程系统上执行的任务。通过Playbook,我们可以将复杂的IT操作转化为可重复、可版本控制的代码。本文将深入探讨Playbook的结构、语法和高级特性,帮助读者掌握编写高效、可维护的Playbook的…...

【实践总结】如何编写“多角色适配”的高质量技术文档?

一份文档想要“一稿多用”?先别急着开写!先读完这篇总结,你将学会如何拆解目标、设计结构、提升可读性,让文档不再顾此失彼。 🔍 背景:一文多用,常常适得其反 在实际的软件项目中,我们往往希望通过一份设计文档,同时完成以下多个目标: ✅ 描述系统结构,便于团队成…...

Ansible 入门教程:从零开始掌握自动化运维

1. 引言 在当今快速发展的IT环境中,自动化运维已成为提高效率、减少人为错误的关键。Ansible作为一个简单yet强大的自动化工具,正受到越来越多DevOps工程师的青睐。本文将带领读者从零开始,逐步掌握Ansible的核心概念和基本用法,为自动化运维之路打下坚实基础。 2. Ansible简…...

WSL2迁移教程:如何备份和转移Ubuntu子系统到新位置

WSL2迁移教程&#xff1a;如何备份和转移Ubuntu子系统到新位置 文章目录 WSL2迁移教程&#xff1a;如何备份和转移Ubuntu子系统到新位置前言环境准备迁移步骤详解1. 查看当前WSL发行版状态2. 关闭所有WSL实例3. 导出WSL发行版4. 注销原有WSL发行版5. 导入WSL发行版到新位置6. 验…...

【备赛】eeprom

简介 EEPROM即电可擦可编程只读存储器&#xff0c;属于非易失存储芯片。 它能电擦除、多次编程&#xff0c;支持字节级操作。 掉电后数据不丢失。 蓝桥杯嵌入式的eeprom使用AT24C02&#xff0c;使用IIC通信协议。 驱动的函数官方已经写好&#xff0c;我们只需要移植并使用就…...

Pytorch torch.utils.data.dataloader.default_collate 介绍

torch.utils.data.dataloader.default_collate 是 PyTorch 中 DataLoader 默认的 collate_fn 函数&#xff0c;用于将一个批次的样本数据合并成张量&#xff08;Tensor&#xff09;或其他结构化数据格式。以下是关于 default_collate 的详细介绍&#xff1a; 1. 功能 default…...

Github最新AI工具汇总2025年4月份第2周

根据GitHub官方动态及开发者生态最新进展&#xff0c;以下是2025年4月第二周&#xff08;截至4月7日&#xff09;值得关注的AI工具与技术更新汇总&#xff1a; 1. GitHub Copilot Agent Mode全量发布 核心功能&#xff1a;在VS Code中启用Agent模式后&#xff0c;Copilot可自主…...

2013年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析

2013年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析 全国大学生数学建模竞赛(China Undergraduate Mathematical Contest in Modeling)是国家教委高教司和中国工业与应用数学学会共同主办的面向全国大学生的群众性科技活动,目的在于激励学生学习数学的积极性,提高学…...

LabVIEW 开发如何降本增效

在 LabVIEW 开发领域&#xff0c;如何在确保项目质量的同时降低开发成本&#xff0c;是众多企业和开发者共同关注的焦点。这不仅关乎资源的高效利用&#xff0c;更影响项目的投资回报率和市场竞争力。下面&#xff0c;我们将从多个维度深入剖析降本策略&#xff0c;并结合具体案…...

云存储服务器的作用都有哪些?

云存储服务器是一种用来存储和管理企业数据信息的服务器&#xff0c;可以为企业与组织提供一个可靠、安全和可扩展的存储平台&#xff0c;能够帮助个人和企业将数据信息存储在云端&#xff0c;以此来实现数据信息的备份、共享和访问功能。 云存储服务器支持多个用户共同访问和共…...

可编辑33页PPT | AI智能智慧工厂厂区完全整体解决方案

荐言摘要&#xff1a;AI智能智慧工厂厂区完全整体解决方案是一种集成了先进的人工智能技术、工业自动化系统和创新管理理念的综合性方案&#xff0c;旨在提升生产效率、降低成本、实现灵活生产&#xff0c;并推动工厂的智能化发展。 随着技术的不断进步&#xff0c;工厂架构经…...

vmware虚拟机上Ubuntu或者其他系统无法联网的解决方法

一、检查虚拟机是否开启了网络服务 打开方式&#xff1a;控制面板->-管理工具--->服务 查找 VMware DHCP Service 和VMware NAT Service &#xff0c;确保这两个服务已经启动。如下图&#xff0c;没有启动就点击启动。 二、设置网络类型 我们一般使用前两种多一些&…...

python中pyside6多个py文件生成exe

网上见到的教程大多数都是pyinstaller安装单个py文件,针对多个py文件的打包,鲜有人提及;有也是部分全而多的解释,让人目不暇接,本次记录自己设置一个声波捕捉界面的打包过程。 1.pycharm中调用pyinstaller打包 参考链接:https://blog.csdn.net/weixin_45793544/articl…...

P1006 [NOIP 2008 提高组] 传纸条 题解

题目传送门 前言 每次准备摸鱼时都在这道题的界面。 今天有空做做&#xff0c;顺便写一波题解&#xff0c;毕竟估值蹭蹭往下跳。 双倍经验&#xff1a;P1004 [NOIP 2000 提高组] 方格取数&#xff0c;P1006 [NOIP 2008 提高组] 传纸条。 题意简述 现有一个 m m m 行 n …...

linux下编译Websocketpp,适用x86和armv8

编译boost库 下载源文件&#xff1a;Version 1.79.0 编译&#xff1a; sudo ./bootstrap.sh sudo ./b2 install 安装websocketpp git clone https://github.com/zaphoyd/websocketpp.git cd websocketpp #进入目录 mkdir build cd build cmake .. make sudo make ins…...

skynet.dispatch 使用详解

目录 skynet.dispatch 函数详解1. 函数定义与参数2. 消息处理流程3. 使用示例示例 1&#xff1a;处理 Lua 协议消息示例 2&#xff1a;处理自定义协议消息 4. 关键机制(1) 协程与阻塞操作(2) 消息响应 5. 与 skynet.register_protocol 的协作6. 注意事项7. 典型应用场景 总结 s…...

CondaError: Run ‘conda init‘ before ‘conda activate‘

CondaError: Run conda init before conda activate&#xff0c;表明 Conda 环境未正确初始化&#xff0c;导致无法激活目标环境。以下是具体解决方案&#xff1a; 1. 初始化 Conda Conda 需要先初始化才能使用 activate 命令。根据Linux系统&#xff0c;运行以下命令初始化 B…...

从代码学习深度学习 - 序列到序列学习数据预处理 PyTorch 版

文章目录 前言一、数据读取二、文本预处理三、词元化四、构建词表五、截断和填充六、转换为张量七、数据迭代器总结前言 在深度学习领域,序列到序列(Seq2Seq)模型是一种非常重要的架构,广泛应用于机器翻译、文本摘要和对话生成等任务。在实现 Seq2Seq 模型时,数据的预处理…...

SQL:Primary Key(主键)和Foreign Key(外键)

目录 1. Key&#xff08;键&#xff09; 2. Index&#xff08;索引&#xff09; 3.Key和Index的区别 4. Primary Key&#xff08;主键&#xff09; 5. Foreign Key&#xff08;外键&#xff09; 6.主键和外键的关系 温馨提示&#xff1a; 闪电按钮不同的执行功能 首先&…...

ClickHouse接入prometheus监控

ClickHouse接入prometheus监控 在 ClickHouse 集群环境下&#xff08;假设你有 3 台服务器&#xff09;&#xff0c;使用自带的 Prometheus 端点来监控是完全可行的。集群部署意味着你需要为每台服务器配置 Prometheus 端点&#xff0c;并确保 Prometheus 能够从所有节点采集数…...

轻量级UDP流量重放工具的技术实现与场景应用(C/C++代码实现)

在网络协议测试、安全攻防演练、性能调优等领域&#xff0c;精确控制数据包传输行为是核心需求。udp_replay作为一款专注于UDP流量的开源工具&#xff0c;通过简洁的设计实现了对pcap文件中UDP数据流的灵活重放。本文将从技术实现原理、核心功能亮点及典型应用场景三个维度展开…...

时序数据库 TDengine × Excel:一份数据,两种效率

在日常工作中&#xff0c;很多人都离不开 Excel。不论是设备运维工程师、数据分析师&#xff0c;还是业务人员&#xff0c;一份熟悉的电子表格往往就是他们的“第一张报表”。 现在&#xff0c;TDengine 也可以与 Excel 实现无缝连接&#xff0c;用户可以直接在 Excel 中查询时…...

video自动播放

文章目录 前言在iOS系统中&#xff0c;H5页面的自动播放功能受到了一些限制&#xff0c;为了提升用户体验和保护用户隐私&#xff0c;Safari浏览器对于自动播放的行为做了一些限制。 一、自动播放的限制二、解决方案 前言 在iOS系统中&#xff0c;H5页面的自动播放功能受到了一…...

如何利用AI智能生成PPT,提升工作效率与创意表现

如何利用AI智能生成PPT&#xff0c;提升工作效率与创意表现&#xff01;在这个信息爆炸的时代&#xff0c;制作一份既专业又富有创意的PPT&#xff0c;已经不再是一个简单的任务。尤其是对于每天都需要做报告、做展示的职场人士来说&#xff0c;PPT的质量直接影响着工作效率和个…...

Java8+Spring Boot + Vue + Langchain4j 实现阿里云百炼平台 AI 流式对话对接

1. 引言 在本文中&#xff0c;我们将介绍如何使用 Spring Boot、Vue.js 和 Langchain4j&#xff0c;实现与 阿里云百炼平台 的 AI 流式对话对接。通过结合这些技术&#xff0c;我们将创建一个能够实时互动的 AI 聊天应用。 这是一个基于 Spring Boot Vue.js Langchain4j 的智…...

【scikit-learn基础】--『数据加载』之外部数据集

这是scikit-learn数据加载系列的最后一篇&#xff0c;本篇介绍如何加载外部的数据集。 外部数据集不像之前介绍的几种类型的数据集那样&#xff0c;针对每种数据提供对应的接口&#xff0c;每个接口加载的数据都是固定的。 而外部数据集加载之后&#xff0c;数据的字段和类型是…...

Redis原理:keys命令

语法&#xff1a; keys pattern 返回所有符合pattern的key 支持 glob-style patterns: h?llo matches hello, hallo and hxlloh*llo matches hllo and heeeelloh[ae]llo matches hello and hallo, but not hilloh[^e]llo matches hallo, hbllo, ... but not helloh[a-b]llo ma…...

4.7学习总结 可变参数+集合工具类Collections+不可变集合

可变参数&#xff1a; 示例&#xff1a; public class test {public static void main(String[] args) {int sumgetSum(1,2,3,4,5,6,7,8,9,10);System.out.println(sum);}public static int getSum(int...arr){int sum0;for(int i:arr){sumi;}return sum;} } 细节&#xff1a…...

高级java每日一道面试题-2025年3月24日-微服务篇[Nacos篇]-使用Nacos如何实现配置管理?

如果有遗漏,评论区告诉我进行补充 面试官: 使用Nacos如何实现配置管理&#xff1f; 我回答: 在Java高级面试中讨论如何使用Nacos实现配置管理的综合回答 在Java高级面试中&#xff0c;关于如何使用Nacos实现配置管理&#xff0c;可以从以下几个方面进行全面、深入的阐述&am…...

Exce格式化批处理工具详解:高效处理,让数据更干净!

Exce格式化批处理工具详解&#xff1a;高效处理&#xff0c;让数据更干净&#xff01; 1. 概述 在数据分析、报表整理、数据库管理等工作中&#xff0c;数据清洗是不可或缺的一步。原始Excel数据常常存在格式不统一、空值、重复数据等问题&#xff0c;影响数据的准确性和可用…...

CExercise_06_1指针和数组_1查找数组的最大值和最小值

题目&#xff1a; 查找数组的最大值和最小值&#xff0c;但要将最大值作为返回值返回&#xff0c;最小值则依靠传入的指针完成赋值。 要求不能使用"[]"运算符。 函数的声明如下&#xff1a; int max_min(int *arr, int len, int *pmin); 关键点 1) * 运算符用于解引用…...

redis中的hash

Redis中的hash是什么 Hash: 哈希&#xff0c;也叫散列&#xff0c;是一种通过哈希函数将键映射到表中位置的数据结构&#xff0c;哈希函数是关键&#xff0c;它把键转换成索引。 Redis Hash&#xff08;散列表&#xff09;是一种 field-value pairs&#xff08;键值对&#x…...

【学习笔记】李沐斯坦福21秋季:实用机器学习中文版

这里写自定义目录标题 数据处理数据获取数据标注数据清洗特征工程 数据处理 数据获取 爬虫 实际工作中大部分都是从数据库里取数 数据标注 只有一小部分有标签 大部分无标签的话 半监督学习&#xff1a;没标注数据和有标注数据共同使用 做法1:半监督学习 基于有标签的小部分…...

UE5学习笔记 FPS游戏制作43 UI材质

文章目录 实现目标制作UI材质使用UI材质 实现目标 把图片变为灰色 制作UI材质 右键新建一个材质 左侧细节栏&#xff0c;材质域改为用户界面&#xff0c;混合模式改为半透明 此时输出节点应该有两个属性 在内容浏览器里找到要用的图片&#xff0c;然后向上拖动到材质标题…...