tauri2+typescript+vue+vite+leaflet等的简单联合使用(一)
项目目标
主要的目的是学习tauri。
流程
1、搭建项目
2、简单的在项目使用leaflet
3、打包
准备项目
环境准备
废话不多说,直接开始
需要有准备能运行Rust的环境和Node,对于Rust可以参考下面这位大佬的文章,Node不必细说。
Rust 和 Cargo 安装指南-CSDN博客
https://blog.csdn.net/qq_44154915/article/details/139365116
建立项目
进入tauri2
官网
https://tauri.app/start/

笔者将使用pnpm建立项目,项目名称为ttvvl
如下

使用VSCode或者WebStorm打开项目
安装依赖
pnpm install

运行
pnpm tauri dev
然后就在compiling

这笔者感到疑惑,可能是第一次运行,搞了许久

运行结果

没有问题。
看一下文件夹的属性

6个G,有点大。
如果以
pnpm run dev
点击按钮,会出现错误


观察上面的代码,我们可以发现,这个是invoke好像是个方法。第一个参数是个字符串greet
第二个参数是个对象,属性是name。
同时找到src-tauri/src/lib.rs中的代码,如下

fn 是Rust的关键字,相当与定义了一个函数,函数名叫greet,参数name
format!是个格式化字符串的函数
其他不是很懂,但我们可以把这段代码给deepseek,问一问
解答如下

从这里我们可以得到关键信息——被这个宏标记的函数能被前端调用。
因为Rust函数的函数名叫greet,而invoke的第一个参数是字符串greet,我们可以很容易猜测
二者必然有关系,我们可以检验一下
修改函数名为greets,运行
发现报错了

我们可以看到下面还有一个函数
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {tauri::Builder::default().plugin(tauri_plugin_opener::init()).invoke_handler(tauri::generate_handler![greet]).run(tauri::generate_context!()).expect("error while running tauri application");
}
可以问一问deepseek

原来下面那个函数是入口函数,invoke_handler是注册器,因此,把中括号里面的greet改成greets
应该可以运行了,(每次都要编译,有点慢)。
如果点击按钮,下面应该不会出现字

事实确实如此。
那么推断很有可能是正确的,那么我们把字符串greet改成greets,就可以出现字了

事实确实如此,笔者明白了。
再次观察,Rust函数greets返回值是String,

而返回格式化后的字符串,对于App.vue中的TypeScript代码,打印出greetMsg.value的值

在运行后的的tauri中,可以打开开发者工具,打印结果如下。

既然如此,感觉明白了,invoke作为Rust与TypeScript交互的关键函数。
安装leaflet有关依赖
pnpm install leaflet leaflet-geoman-free
因为使用typescipt,还需要安装类型定义包
pnpm install --save @types/leaflet.pm @types/leaflet
显示地图
这也是很麻烦的事情。
安装vue-router
pnpm install vue-router
新建一些目录和文件,如下

在router目录的index.ts中
import {createRouter, createWebHashHistory, Router, RouteRecordRaw, RouterOptions} from "vue-router";
const routes:RouteRecordRaw[]=[{path:"/",redirect:"/map",children:[{path:"map",component:()=>import("../views/Map.vue")}]}
]
const options:RouterOptions={history:createWebHashHistory(),routes
}
const router:Router=createRouter(options)
export default router
暂时先这么写
main.ts的内容
import { createApp } from "vue";
import App from "@/App.vue";
import router from "@/router";
import * as L from "leaflet";
import "leaflet/dist/leaflet.css";
import "@geoman-io/leaflet-geoman-free";
import "@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css";
const app=createApp(App);
app.use(router);
app.config.globalProperties.$L = L;app.mount("#app");
将L作为Vue的全局属性,并且引入插件leaflet-geoman-free及相关样式
关于@符号,不多解释。
在constant/data.ts中
export const MAP_URL= "https://tile-a.openstreetmap.fr/hot/{z}/{x}/{y}.png";
这个是地图瓦片的URL。通过它就能访问地图。
在utils/Map.ts中
import {MAP_URL} from "@/constant/data.ts";
import L from 'leaflet';
const GetMap = (control: any=null, //控件language:any = 'zh' //语言
): L.Map => {const options: L.MapOptions = {center: [30.6667, 104.0667], //中心点minZoom: 0,maxZoom: 30,zoom: 10,zoomControl: true,doubleClickZoom: true,attributionControl: true,dragging: true,boxZoom: true,scrollWheelZoom: true,zoomSnap: 0.5,};const map = L.map('map', options);L.tileLayer(MAP_URL, {attribution: '',}).addTo(map);map.pm.addControls(control); map.pm.setLang(language);return map;
};
export default GetMap;
如果不写
import L from 'leaflet'
Vue: 'L' refers to a UMD global, but the current file is a module. Consider adding an import instead.
在views/Map.vue中
<script setup lang="ts">
import GetMap from "@/utils/Map.ts";
import { onMounted } from 'vue';
let map: any = null
onMounted(() => {map = GetMap();map.on('click', (e: any) => {console.log(e);});
})
</script><template>
<div id="map"></div>
</template><style scoped>
#map {height: 100vh;width: 200vh;
}
</style>
运行,结果如下

地图定位到成都市。
显示控件
可以查看leaflet-geoman-free文档
Introduction | Documentation for Leaflet-Geoman
https://geoman.io/docs/leaflet在constant/data.ts中
export const MAP_CONTROL={
}
可以写一些设置,但有默认选项,就不改了。
在views/Map.vue中导入MAP_CONTROL,作为GetMap的参数
map = GetMap(MAP_CONTROL);
,使用控件,运行结果如下

搞点小操作1——计算两点之间的距离
操作过程
点两个点,通过invoke函数发送经纬度到rust函数,返回结果
计算距离函数
使用Haversine 公式
haversine公式计算两经纬度点距离-CSDN博客
https://blog.csdn.net/spatial_coder/article/details/116605509使用Rust实现,src-tauri/src/lib.rs的代码如下
const EARTH_RADIUS_KM: f64 = 6371.0; // 地球半径,单位:公里
#[tauri::command]
// 计算两个经纬度点之间的距离(单位:公里)
fn haversine_distance(start:[f64;2],end:[f64;2]) -> f64 {// 将经纬度从度数转换为弧度let lat1_rad = start[0].to_radians();let lon1_rad = start[1].to_radians();let lat2_rad = end[0].to_radians();let lon2_rad = end[1].to_radians();// 经纬度差值let dlat = lat2_rad - lat1_rad;let dlon = lon2_rad - lon1_rad;// Haversine 公式let a = (dlat / 2.0).sin().powi(2) + lat1_rad.cos() * lat2_rad.cos() * (dlon / 2.0).sin().powi(2);let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());// 计算距离EARTH_RADIUS_KM * c
}#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {tauri::Builder::default().plugin(tauri_plugin_opener::init()).invoke_handler(tauri::generate_handler![haversine_distance]).run(tauri::generate_context!()).expect("error while running tauri application");
}
以公里作为单位
对两个点marker的思考
点了两个点marker,我们通过leaflet和有关插件的某些事件可以获得这两个点的属性,
我们可以修改这些属性。
那应该然后修改?
可以尝试使用tauri的多窗口。
marker位于父窗口,发送信号到子窗口,在子窗口进行修改,返回父窗口。
父子窗口以及发送信号

关于窗口的配置
src-tauri/capabilities/default.json
{"$schema": "../gen/schemas/desktop-schema.json","identifier": "default","description": "Capability for the main window","windows": ["main","marker-name"],"permissions": ["core:default","opener:default","core:window:allow-hide","core:window:allow-show"]
}
在子窗口添加一个路由
src/router/index.ts
{path:"/name",component:()=>import("../views/name.vue")}
src-tauri/tauri.conf.json
"windows": [{"title": "ttvvl","label": "main","width": 800,"height": 600},{"title": "点位窗口","width": 400,"height": 300,"label": "marker-name","resizable": true,"parent": "main","visible": false,"url":"#/name","decorations": false,"center": true}],
参数的具体含义,可以参考官网或者deekssek
{"windows": [{"label": "main", // 窗口的唯一标识符"title": "My Tauri App", // 窗口标题"width": 800, // 窗口宽度"height": 600, // 窗口高度"x": null, // 窗口初始水平位置(null 表示由系统决定)"y": null, // 窗口初始垂直位置(null 表示由系统决定)"minWidth": null, // 窗口最小宽度"minHeight": null, // 窗口最小高度"maxWidth": null, // 窗口最大宽度"maxHeight": null, // 窗口最大高度"resizable": true, // 是否允许调整窗口大小"fullscreen": false, // 是否全屏"focus": true, // 窗口是否在创建时获得焦点"visible": true, // 窗口是否可见"decorations": true, // 是否显示窗口装饰(标题栏、边框等)"alwaysOnTop": false, // 窗口是否始终置顶"maximized": false, // 窗口是否最大化"transparent": false, // 窗口背景是否透明"center": true, // 窗口是否居中"theme": "system", // 窗口主题("system"、"light"、"dark")"url": "index.html", // 窗口加载的页面路径"fileDropEnabled": true, // 是否启用文件拖放功能"skipTaskbar": false, // 是否在任务栏中显示窗口"shadow": true, // 是否显示窗口阴影"acceptFirstMouse": false, // 是否接受首次鼠标点击事件"tabbingIdentifier": null, // macOS 标签页标识符"titleBarStyle": "visible", // macOS 标题栏样式("visible"、"transparent"、"overlay")"hiddenTitle": false // 是否隐藏标题栏标题}]
}
父窗口
src/views/Map.vue
<script setup lang="ts">
//@ts-nocheck
import GetMap from "@/utils/Map.ts";
import {MAP_CONTROL} from "@/constant/data.ts";
import {invoke} from "@tauri-apps/api/core";
import {emit,listen} from "@tauri-apps/api/event";
import {onMounted, ref} from 'vue';
import WindowManager from '@/utils/window';const windowManager = new WindowManager();
let startName=ref<String>('起点');
let endName=ref<String>('终点');
let markerWindow,mainWindow,markerIndex=null;
let map: any = null
let markerList: L.Marker[] = [];
let distance=ref<number>(0);listen('message-to-main-window', (event)=>{ //监听消息let payload:any=event.payloadif(payload.close){windowManager.closeWindow('marker-name')mainWindow.show()}if(markerIndex===null){return}if(markerIndex===0){startName.value='起点'+payload.tooltipContent}else{endName.value='终点'+payload.tooltipContent}markerList[markerIndex].bindTooltip(payload.tooltipContent)
});
async function sendMsg(tooltipContent:String,nowClickMarkerId:Number) { //发送消息markerWindow=await windowManager.getWindowByLabel('marker-name') //子窗口mainWindow=await windowManager.getWindowByLabel('main') //父窗口if(markerWindow) {mainWindow.hide()markerWindow.show();markerIndex=markerList.findIndex((marker:L.Marker)=>marker._leaflet_id===nowClickMarkerId)emit('message-to-second-window', { //发送消息 参数lat: markerList[0].getLatLng().lat,lng: markerList[0].getLatLng().lng,markerIndex:markerIndex,tooltipContent:tooltipContent})}
}async function get_distance(){let start=markerList[0].getLatLng(); //开始点let end=markerList[1].getLatLng(); //终点let startArray=[start.lat,start.lng];let endArray=[end.lat,end.lng];distance.value = await invoke('haversine_distance', { //发送给rust tauristart: startArray,end: endArray});
}
onMounted(() => {// openWindow()map = GetMap(MAP_CONTROL);map.on('pm:create', (e: any) => { // map create事件let marker:L.Marker = e.marker;marker.on('click',(e)=>{ // marker的点击事件let nowClickMarkerId=e.target._leaflet_id // 获取marker的idsendMsg(e.target.getTooltip(),nowClickMarkerId) // 发送消息})markerList.push(marker);let length = markerList.length;if(length==2){ // 起始点 和终点get_distance() //获取距离}else if(length>2){markerList[0].remove(); //移除第一个点markerList.shift();get_distance() // 获取距离}})})
</script><template>
<div id="map"><div id="distance-text" v-if="markerList.length>=2">从{{startName}}到{{endName}}的距离为</div><div><button type="button" id="show" >{{distance}}</button></div><div id="unit">公里</div></div>
</template><style scoped>
#map {margin: 0 auto;width: 100%;height: 900px;
}
#show {max-width: 200px;max-height: 50px;padding: 10px;background-color: blue;color: white;text-align: center;position: absolute;top: 100px;right: 10px;z-index: 999;border-radius: 20px;
}
#distance-text {max-width: 200px;max-height: 50px;padding: 10px;background-color: #af8433;color: white;text-align: center;position: absolute;top: 10px;right: 10px;z-index: 999;border-radius: 20px;
}
#unit {max-width: 200px;max-height: 50px;padding: 10px;background-color: #af8433;color: white;text-align: center;position: absolute;top: 150px;right: 10px;z-index: 999;border-radius: 20px;
}</style>
子窗口
src/views/Name.vue
<script setup>
import {listen,emit} from "@tauri-apps/api/event";
import {onMounted, ref} from "vue";
let lat = ref(0);
let lng = ref(0);
let markerIndex = ref(0); // 0 替换成起点 1 替换成终点
let inputValue = ref('');
let oldTooltip=nullconst handleClicked = () => {emit('message-to-main-window', {tooltipContent:inputValue.value,close: true,});
}
const handleCancel = () => {emit('message-to-main-window', {tooltipContent:oldTooltip,close: true,});
}
onMounted(() => {listen('message-to-second-window', (event) => {let payload = event.payload;lat.value = payload.lat;lng.value = payload.lng;markerIndex.value = payload.markerIndex;inputValue.value=payload.tooltipContent;oldTooltip=payload.tooltipContent});}
)</script>
<template><div data-tauri-drag-region class="titlebar" ><h1>{{markerIndex===0?'起点':'终点'}}</h1><div v-if="lat>0">纬度:{{lat }}</div><div v-if="lng>0">经度:{{lng }}</div><div>名称<br/><input v-model="inputValue"></input></div><br/><button type="button" @click="handleClicked" class="sure">确定</button><button type="button" @click="handleCancel" class="cancel">取消</button></div>
</template>
<style >
.sure{padding: 10px ;margin-right: 10vw;background-color: #5174ff;
}
.cancel{padding: 10px ;margin-right: 10vw;background-color: #ffb43e;}</style>
窗口管理
src/utils/window.ts
import { getAllWebviewWindows } from '@tauri-apps/api/webviewWindow';export class WindowManager {async getWindowByLabel(label: string) {const windows = await getAllWebviewWindows();return windows.find((win) => win.label === label);}async closeWindow(label: string) {const window = await this.getWindowByLabel(label);if (window) {window.hide();}}
}export default WindowManager;
运行结果



运行结果倒是没问题,代码写得不行,算了。不管那些。
打包
本地打包
打包成exe命令
pnpm tauri build
因为笔者不是第一次打包,如果是第一次打包,需要下载一些东西,笔者就不展示了,可参考下面这位大佬的过程。
从零开始的 Tauri 开发 & 打包成 exe 【Windows 平台】_tauri 打包-CSDN博客
https://blog.csdn.net/u010263423/article/details/136006546对于leaflet打包,会出现一个bug,解决过程可看这篇文章
解决Vue+Vite打包后Leaflet的marker图标不显示的问题_leaflet l.marker 没有-CSDN博客
https://blog.csdn.net/qq_63401240/article/details/139972362?spm=1001.2014.3001.5502总之。打包结果

打包运行结果
可以。

上传到github并打包
在github上通过工作流打包
工作流代码参考下面这位大佬
tauri使用github的action自动发布release,让别人也可以看到下载链接_tauri github action-CSDN博客
https://blog.csdn.net/weixin_44786530/article/details/140904091在大佬的基础上做出小的修改

修改了工件的版本,其他改动不大
运行结果如下

发现ubuntu出错了。笔者没有深究。
笔者再次打包,只选择了window系统,结果如下

项目地址
qe-present/ttvvl
https://github.com/qe-present/ttvvl
总结
简单地使用了tauri,使用了信号通信,多窗口,打包。
相关文章:
tauri2+typescript+vue+vite+leaflet等的简单联合使用(一)
项目目标 主要的目的是学习tauri。 流程 1、搭建项目 2、简单的在项目使用leaflet 3、打包 准备项目 环境准备 废话不多说,直接开始 需要有准备能运行Rust的环境和Node,对于Rust可以参考下面这位大佬的文章,Node不必细说。 Rust 和…...
【流程图】在 .NET (WPF 或 WinForms) 中实现流程图中的连线算法
在 .NET (WPF 或 WinForms) 中实现流程图中的连线算法,通常涉及 图形绘制 和 路径计算。常见的连线方式包括 直线、折线 和 贝塞尔曲线。以下是几种方法的介绍和示例代码。 1. 直线连接(最简单) 适用场景: 两个节点之间没有障碍…...
IDEA集成DeepSeek,通过离线安装解决无法安装Proxy AI插件问题
文章目录 引言一、安装Proxy AI1.1 在线安装Proxy AI1.2 离线安装Proxy AI 二、Proxy AI中配置DeepSeek2.1 配置本地部署的DeepSeek(Ollama方式)2.2 通过第三方服务商提供的API进行配置 三、效果测试 引言 许多开发者尝试通过安装Proxy AI等插件将AI能力…...
【流行病学】Melodi-Presto因果关联工具
title: “[流行病学] Melodi Presto因果关联工具” date: 2022-12-08 lastmod: 2022-12-08 draft: false tags: [“流行病学”,“因果关联工具”] toc: true autoCollapseToc: true 阅读介绍 Melodi-Presto: A fast and agile tool to explore semantic triples derived from …...
详细分析KeepAlive的基本知识 并缓存路由(附Demo)
目录 前言1. 基本知识2. Demo2.1 基本2.2 拓展2.3 终极 3. 实战 前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 基本知识推荐阅读:KeepAlive知识点 从实战中学习,源自实战中vue路由的…...
【Go】Go viper 配置模块
1. 配置相关概念 在项目开发过程中,一旦涉及到与第三方中间件打交道就不可避免的需要填写一些配置信息,例如 MySQL 的连接信息、Redis 的连接信息。如果这些配置都采用硬编码的方式无疑是一种不优雅的做法,有以下缺陷: 不同环境…...
zabbix“专家坐诊”第277期问答
在线答疑:乐维社区 问题一 Q:这个怎么解决呢? A:缺少这个依赖。 Q:就一直装不上。 A:装 zabbix-agent2-7.0.0-releasel.el7.x86 64 需要前面提示的那个依赖才可以装。 问题二 Q:大佬,如果agen…...
大模型工程师学习日记(十一):FAISS 高效相似度搜索和密集向量聚类的库
Facebook AI Similarity Search (Faiss /Fez/) 是一个用于高效相似度搜索和密集向量聚类的库。它包含了在任意大小的向量集合中进行搜索的算法,甚至可以处理可能无法完全放入内存的向量集合。它还包含用于评估和参数调整的支持代码。 Faiss 官方文档:We…...
python学习第三天
条件判断 条件判断使用if、elif和else关键字。它们用于根据条件执行不同的代码块。 # 条件判断 age 18 if age < 18:print("你还是个孩子!") elif age 18:print("永远十八岁!") else:print("你还年轻!")…...
深入解析 Svelte:下一代前端框架的革命
深入解析 Svelte:下一代前端框架的革命 1. Svelte 简介 Svelte 是一款前端框架,与 React、Vue 等传统框架不同,它采用 编译时(Compile-time) 方式来优化前端应用。它不像 React 或 Vue 依赖虚拟 DOM,而是…...
C++20 中位移位运算符的统一行为:深入解析与实践指南
文章目录 1. 位移位运算符的基础1.1 左移运算符(<<)1.2 右移运算符(>>) 2. C20 对位移位运算符的统一2.1 移位数量超出操作数位宽2.2 负数移位 3. 实践中的注意事项4. 示例代码5. 总结 在 C 的发展历程中,…...
Linux——基本指令
我们今天学习Linux最基础的指令 ls 指令 语法: ls [选项] [⽬录或⽂件] 功能:对于⽬录,该命令列出该⽬录下的所有⼦⽬录与⽂件。对于⽂件,将列出⽂件名以及其他信 息。 命令中的选项,一次可以传递多个 ,…...
MySql面试总结(二)
WHERE 子句优化 截至2024年7月,MySQL最新稳定版本是8.2,并不存在MySQL 8.4 。下面从常见的几个方面为你介绍 MySQL 8.x 中 WHERE 子句的优化方法: 1. 确保使用索引 原理:索引可以加快数据的查找速度,当 WHERE 子句中的条件列有索引时,MySQL 可以直接定位到符合条件的数…...
Pytorch中的主要函数
目录 一、torch.manual_seed(seed)二、torch.cuda.manual_seed(seed)三、torch.rand(*size, outNone, dtypeNone, layouttorch.strided, deviceNone, requires_gradFalse)四、给大家写一个常用的自动选择电脑cuda 或者cpu 的小技巧五、torch.version.cuda;torch.bac…...
Java实现大数据量导出报表
一、实现方式 在Java中,导出数据到Excel有多种方式,每种方式都有其优缺点,适用于不同的场景。以下是常见的几种方式及其特点: 1.1 Apache POI Apache POI 是 Java 中最流行的库,支持读写 Excel 文件(包括…...
大语言模型 智能助手——既能生成自然语言回复,又能在必要时调用外部工具获取实时数据
示例代码: import json from langgraph.graph import Graph, END,StateGraph from langchain_core.utils.function_calling import convert_to_openai_function from langchain_community.tools.openweathermap import OpenWeatherMapQueryRun from langchain_core…...
PyTorch 系统教程:理解机器学习数据分割
数据分割是机器学习中的一个基本概念,它直接影响模型的性能和泛化。在本文中,我们将深入研究为什么数据分割在机器学习中很重要,并演示如何使用PyTorch有效地实现它。 理解数据分割 数据分割是将数据集划分为单独的组以进行训练、验证和测试…...
分水岭算法(Watershed Algorithm)教程:硬币分割实例
import cv2 import numpy as np# 1. 图像预处理 img cv2.imread("./water/water_coins.jpeg") gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, thresh cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV cv2.THRESH_OTSU) kernel np.ones((3, 3), np.int8)…...
【STM32项目实战系列】基于STM32G474的FDCAN驱动配置
前言:本周工作中用到了CANFD的驱动,由于以前都是用到的CAN2.0,所以过程并不是特别的顺利,所以中间遇到几个比较小的问题导致自己卡住了一段时间,特此记录一下并完全奉上自己的配置的源码。 1,CANFD配置与简…...
shell文本处理
shell文本处理 一、grep 过滤来自一个文件或标准输入匹配模式内容。除了 grep 外,还有 egrep、fgrep。egrep 是 grep 的扩展,相当于 grep -E。fgrep 相当于 grep -f,用的比较少。 用法 grep [OPTION]... PATTERN [FILE]...支持的正则描述…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
如何配置一个sql server使得其它用户可以通过excel odbc获取数据
要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据,你需要完成以下配置步骤: ✅ 一、在 SQL Server 端配置(服务器设置) 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到:SQL Server 网络配…...
《信号与系统》第 6 章 信号与系统的时域和频域特性
目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...
构建Docker镜像的Dockerfile文件详解
文章目录 前言Dockerfile 案例docker build1. 基本构建2. 指定 Dockerfile 路径3. 设置构建时变量4. 不使用缓存5. 删除中间容器6. 拉取最新基础镜像7. 静默输出完整示例 docker runDockerFile 入门syntax指定构造器FROM基础镜像RUN命令注释COPY复制ENV设置环境变量EXPOSE暴露端…...
统计按位或能得到最大值的子集数目
我们先来看题目描述: 给你一个整数数组 nums ,请你找出 nums 子集 按位或 可能得到的 最大值 ,并返回按位或能得到最大值的 不同非空子集的数目 。 如果数组 a 可以由数组 b 删除一些元素(或不删除)得到,…...
