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

C# wpf 实现桌面放大镜

文章目录

  • 前言
  • 一、如何实现?
    • 1、制作无边框窗口
    • 2、Viewbox放大
    • 3、截屏显示
      • (1)、截屏
      • (2)、转BitmapSource
      • (3)、显示
    • 4、定时截屏
  • 二、完整代码
  • 三、效果预览
  • 总结


前言

做桌面截屏功能时需要放大镜,显示鼠标所在位置的放大图像,在wpf中使用Bursh的ViewBox属性可以实现图像放大,桌面的画面则需要截屏了,总的来说还是比较容易实现的。


一、如何实现?

1、制作无边框窗口

推荐使用WindowChrome

<Window Background="{x:Null}" ResizeMode="NoResize"  WindowStyle="None">

WindowChrome放在Window 标签内

<WindowChrome.WindowChrome><WindowChrome GlassFrameThickness="-1"   CaptionHeight="0"   />
</WindowChrome.WindowChrome>

2、Viewbox放大

定义一个Ellipse 控件作为放大镜,Viewbox默认为相对单位,即范围时0-1,值越小放大比例越大

<Ellipse Stroke="LightBlue"><Ellipse.Fill><ImageBrush x:Name="ib" Viewbox="0,0,0.5,0.5" /></Ellipse.Fill>
</Ellipse>

3、截屏显示

(1)、截屏

参考《C# wpf 使用GDI+实现截屏》里的简单截屏即完成。获取的数据类型为Bitmap。

(2)、转BitmapSource

参考《C# wpf Bitmap转换成WriteableBitmap(BitmapSource)的方法》将Bitmap转换为转换成wpf对象。

(3)、显示

获取到BitmapSource给控件赋值即可。

//显示到界面
ib.ImageSource = wb;

4、定时截屏

显示桌面必然需要实时的画面,所以需要定时截屏。

//启动定时器,截屏
var dispatcherTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(33), };
dispatcherTimer.Tick += (s, e) =>
{//截屏并显示
};
dispatcherTimer.Start();

二、完整代码

完整代码依赖System.Drawing,添加引用方法可以参考《C# wpf 使用GDI+实现截屏》。

MainWindow.xaml

<Window x:Class="WpfMagnifier.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WpfMagnifier"mc:Ignorable="d"Background="{x:Null}"ResizeMode="NoResize"WindowStyle="None"ShowInTaskbar="False"Topmost="True"Title="MainWindow" Height="200" Width="200" MouseLeftButtonDown="Window_MouseDown"><WindowChrome.WindowChrome><WindowChrome GlassFrameThickness="-1"   CaptionHeight="0"   /></WindowChrome.WindowChrome><Ellipse Stroke="LightBlue"><Ellipse.Fill><ImageBrush x:Name="ib" Viewbox="0,0,0.5,0.5" /></Ellipse.Fill></Ellipse>
</Window>

MainWindow.xaml.cs

using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace WpfMagnifier
{/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();//启动定时器,截屏var dispatcherTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(33), };dispatcherTimer.Tick += (s, e) =>{//gdi+截屏,截取窗口左边的区域(可根据具体使用场景调整截屏位置),使用PointToScreen消除dpi影响var leftTop = PointToScreen(new Point(-Width, 0));var rightBottom = PointToScreen(new Point(0, Height));var bm = Snapshot((int)leftTop.X, (int)leftTop.Y, (int)(rightBottom.X - leftTop.X), (int)(rightBottom.Y - leftTop.Y));var wb = BitmapToWriteableBitmap(bm);//显示到界面ib.ImageSource = wb;};dispatcherTimer.Start();}private void Window_MouseDown(object sender, MouseButtonEventArgs e){DragMove();}/// <summary>/// 截取一帧图片/// </summary>/// <param name="x">x坐标</param>/// <param name="y">y坐标</param>/// <param name="width">宽</param>/// <param name="height">高</param>/// <returns>截屏后的位图对象,需要调用Dispose手动释放资源。</returns>public static System.Drawing.Bitmap Snapshot(int x, int y, int width, int height){System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmap)){graphics.CopyFromScreen(x, y, 0, 0, new System.Drawing.Size(width, height), System.Drawing.CopyPixelOperation.SourceCopy);}return bitmap;}//将Bitmap 转换成WriteableBitmap public static WriteableBitmap BitmapToWriteableBitmap(System.Drawing.Bitmap src){var wb = CreateCompatibleWriteableBitmap(src);System.Drawing.Imaging.PixelFormat format = src.PixelFormat;if (wb == null){wb = new WriteableBitmap(src.Width, src.Height, 0, 0, System.Windows.Media.PixelFormats.Bgra32, null);format = System.Drawing.Imaging.PixelFormat.Format32bppArgb;}BitmapCopyToWriteableBitmap(src, wb, new System.Drawing.Rectangle(0, 0, src.Width, src.Height), 0, 0, format);return wb;}//创建尺寸和格式与Bitmap兼容的WriteableBitmappublic static WriteableBitmap CreateCompatibleWriteableBitmap(System.Drawing.Bitmap src){System.Windows.Media.PixelFormat format;switch (src.PixelFormat){case System.Drawing.Imaging.PixelFormat.Format16bppRgb555:format = System.Windows.Media.PixelFormats.Bgr555;break;case System.Drawing.Imaging.PixelFormat.Format16bppRgb565:format = System.Windows.Media.PixelFormats.Bgr565;break;case System.Drawing.Imaging.PixelFormat.Format24bppRgb:format = System.Windows.Media.PixelFormats.Bgr24;break;case System.Drawing.Imaging.PixelFormat.Format32bppRgb:format = System.Windows.Media.PixelFormats.Bgr32;break;case System.Drawing.Imaging.PixelFormat.Format32bppPArgb:format = System.Windows.Media.PixelFormats.Pbgra32;break;case System.Drawing.Imaging.PixelFormat.Format32bppArgb:format = System.Windows.Media.PixelFormats.Bgra32;break;default:return null;}return new WriteableBitmap(src.Width, src.Height, 0, 0, format, null);}//将Bitmap数据写入WriteableBitmap中public static void BitmapCopyToWriteableBitmap(System.Drawing.Bitmap src, WriteableBitmap dst, System.Drawing.Rectangle srcRect, int destinationX, int destinationY, System.Drawing.Imaging.PixelFormat srcPixelFormat){var data = src.LockBits(new System.Drawing.Rectangle(new System.Drawing.Point(0, 0), src.Size), System.Drawing.Imaging.ImageLockMode.ReadOnly, srcPixelFormat);dst.WritePixels(new Int32Rect(srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height), data.Scan0, data.Height * data.Stride, data.Stride, destinationX, destinationY);src.UnlockBits(data);}}
}

三、效果预览

显示的是窗口(放大镜)左边的画面
在这里插入图片描述


总结

以上就是今天要讲的内容,本文仅仅简单介绍了实现桌面放大镜的方法,关键在于使用Viewbox,截屏的功能因为有现成的所以比较简单,当然本文的方法是简单实现,其实还是可以优化的,尤其是截屏是可以复用Bitmap对象的。总的来说,wpf实现桌面放大镜还是比较容易的,而且效果也很不错。

相关文章:

C# wpf 实现桌面放大镜

文章目录 前言一、如何实现&#xff1f;1、制作无边框窗口2、Viewbox放大3、截屏显示&#xff08;1&#xff09;、截屏&#xff08;2&#xff09;、转BitmapSource&#xff08;3&#xff09;、显示 4、定时截屏 二、完整代码三、效果预览总结 前言 做桌面截屏功能时需要放大镜…...

Mybatis中的#{}和${}的区别

#{}和${}他们两都是替换参数的作用&#xff0c;但也还是有很大区别的。 目录 一、${} 二、#{} 三、注意点 一、${} 它是直接替换过来&#xff0c;不添加其它的什么。 比如下面的sql语句 select *from user where id${id} 如果id1&#xff0c;那么他替换过来就还是1&#xff…...

选择(使用)数据库

MySQL从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129334507?spm1001.2014.3001.5502 语法格式: use 数据库名称;大家应该知道,在对数据库进行操作的时候,要制定数据库的操作对象,也就是说操作哪一个数据库 案列:选择testing数据库 …...

GFS分布式文件系统

1、GlusterFS简介 GlusterFS&#xff08;GFS&#xff09;是一个开源的分布式文件系统 由存储服务器、客户端以及NFS/Samba 存储网关&#xff08;可选&#xff0c;根据需要选择使用&#xff09;组成。MFS 传统的分布式文件系统大多通过元服务器来存储元数据&#xff0c;元数据…...

虚函数、纯虚函数、多态

一.虚函数 在基类的函数前加上virtual关键字&#xff0c;在派生类中重写该函数&#xff0c;运行时将会根据所指对象的实际类型来调用相应的函数&#xff0c;如果对象类型是派生类&#xff0c;就调用派生类的函数&#xff0c;如果对象类型是基类&#xff0c;就调用基类的函数。 …...

QGIS学习3 - 安装与管理插件

QGIS安装与管理插件主要是使用了菜单栏安装与管理插件这个菜单。 1、通过压缩文件等添加非官方插件 通过压缩文件添加有可能会提示存在安全问题等&#xff0c;直接点是即可。 之后点击install plugins即可完成。安装后导入插件 但是load失败了应该是安装没有成功。只能通过u…...

LeetCode377. 组合总和 Ⅳ

377. 组合总和 Ⅳ 文章目录 [377. 组合总和 Ⅳ](https://leetcode.cn/problems/combination-sum-iv/)一、题目二、题解方法一&#xff1a;完全背包一维数组动态规划思路代码分析 方法二&#xff1a;动态规划二维数组 一、题目 给你一个由 不同 整数组成的数组 nums &#xff0…...

QT将数据写入文件,日志记录

项目场景&#xff1a; 在QT应用中&#xff0c;有时候需要将错误信息记录在log文件里面&#xff0c;或者需要将数据输出到文件中进行比对查看使用。 创建log文件&#xff0c;如果文件存在则不创建 QDir dir(QCoreApplication::applicationDirPath()"/recv_data");if(…...

vue2与vue3的使用区别与组件通信

1. 脚手架创建项目的区别&#xff1a; vue2: vue init webpack “项目名称”vue3: vue create “项目名称” 或者vue3一般与vite结合使用: npm create vitelatest yarn create vite2. template中结构 vue2: template下只有一个元素节点 <template><div><div…...

亚信科技与中国信通院达成全方位、跨领域战略合作

9月11日&#xff0c;亚信科技&#xff08;中国&#xff09;有限公司「简称&#xff1a;亚信科技」与中国信息通信研究院「简称&#xff1a;中国信通院」在京达成战略合作&#xff0c;双方将在关键技术研发、产业链协同等方面展开全方位、跨领域、跨行业深度合作&#xff0c;共促…...

华为Linux系统开发工程师面试

在Linux系统开发工程师的面试中&#xff0c;你可能会遇到以下一些问题&#xff1a; 在同一个网站中&#xff0c;当客户访问的时候&#xff0c;会出现有的页面访问的速度快而有的慢&#xff0c;系统和服务完全正常、网络带宽正常&#xff0c;你如何诊断这个问题&#xff1f;你以…...

Qt利用QTime实现sleep效果分时调用串口下发报文解决串口下发给下位机后产生的粘包问题

Qt利用QTime实现sleep效果分时调用串口下发报文解决串口下发给下位机后产生的粘包问题 文章目录 Qt利用QTime实现sleep效果分时调用串口下发报文解决串口下发给下位机后产生的粘包问题现象解决方法 现象 当有多包数据需要连续下发给下位机时&#xff0c;比如下载数据等&#x…...

人工智能:神经细胞模型到神经网络模型

人工智能领域中的重要流派之一是&#xff1a;从神经细胞模型&#xff08;Neural Cell Model&#xff09;到神经网络模型&#xff08;Neural Network Model&#xff09;。 一、神经细胞模型 第一个人工神经细胞模型是“MP”模型&#xff0c;它是由麦卡洛克、匹茨合作&#xff0…...

Redisson分布式锁实战

实战来源 此问题基于电商 这周遇见这么一个问题&#xff0c;简略的说一下 由MQ发布了两个消息&#xff0c;一个是订单新增&#xff0c;一个是订单状态变更 由于直接付款之后&#xff0c;这两个消息的发布时间不分先后&#xff0c;可能会造成两种情况&#xff0c;1、订单状态变更…...

JavaScript中循环遍历数组、跳出循环和继续循环

循环遍历数组 上个文章我们简单的介绍for循环&#xff0c;接下来&#xff0c;我们使用for循环去读取数据的数据&#xff0c;之前我们写过这样的一个数组&#xff0c;如下&#xff1a; const ITshareArray ["张三","二愣子","2033-1997","…...

Java——》Synchronized和Lock区别

推荐链接&#xff1a; 总结——》【Java】 总结——》【Mysql】 总结——》【Redis】 总结——》【Kafka】 总结——》【Spring】 总结——》【SpringBoot】 总结——》【MyBatis、MyBatis-Plus】 总结——》【Linux】 总结——》【MongoD…...

JDK20 + SpringBoot 3.1.0 + JdbcTemplate 使用

JDK20 SpringBoot 3.1.0 JdbcTemplate 使用 一.测试数据库 Postgres二.SpringBoot项目1.Pom 依赖2.配置文件3.启动类4.数据源配置类5.实体对象类包装类6.测试用实体对象1.基类2.扩展类 7.测试类 通过 JdbcTemplate 直接执行 SQL 语句&#xff0c;结合源码动态编译即可方便实现…...

CTFhub_SSRF靶场教程

CTFhub SSRF 题目 1. Bypass 1.1 URL Bypass 请求的URL中必须包含http://notfound.ctfhub.com&#xff0c;来尝试利用URL的一些特殊地方绕过这个限制吧 1.利用?绕过限制urlhttps://www.baidu.com?www.xxxx.me 2.利用绕过限制urlhttps://www.baidu.comwww.xxxx.me 3.利用斜…...

【华为OD机试】单词接龙【2023 B卷|100分】

【华为OD机试】-真题 !!点这里!! 【华为OD机试】真题考点分类 !!点这里 !! 题目描述: 单词接龙的规则是:可用于接龙的单词首字母必须要前一个单词的尾字母相同; 当存在多个首字母相同的单词时,取长度最长的单词,如果长度也相等, 则取字典序最小的单词;已经参与接龙…...

如何优雅的实现无侵入性参数校验之spring-boot-starter-validation

在开发过程中&#xff0c;参数校验是一个非常重要的环节。但是&#xff0c;传统的参数校验方法往往需要在代码中手动添加大量的 if-else 语句&#xff0c;这不仅繁琐&#xff0c;而且容易出错。为了解决这个问题&#xff0c;我们可以使用无侵入性参数校验的方式来简化代码并提高…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...