如何在 C# 中有效地在桌面上绘图?

Posted

技术标签:

【中文标题】如何在 C# 中有效地在桌面上绘图?【英文标题】:How to effectively draw on desktop in C#? 【发布时间】:2011-02-23 17:58:21 【问题描述】:

我想用 C# 直接在桌面上绘图。经过一番搜索,我最终使用了桌面 HDC 中的图形对象(空)。然后,我使用这个 Graphics 对象正常绘制。

问题是当屏幕的任何部分被重绘时我的形状会丢失。我尝试了一个 While 循环,但它实际上最终以尽可能快的速度绘制应用程序,这不是桌面的更新速率。

通常,我需要将我的绘图代码放在“OnPaint”事件中,但桌面不存在这样的事情。

我该怎么做?

示例代码:https://***.com/questions/1536141/how-to-draw-directly-on-the-windows-desktop-c

【问题讨论】:

什么版本的 Windows? 【参考方案1】:

我针对类似需求发布了两个解决方案here

基本上你有两个选择。

1- 获取桌面的图形对象并开始对其进行绘图。问题是您是否需要开始清除之前绘制的内容等。

Point pt = Cursor.Position; // Get the mouse cursor in screen coordinates 

using (Graphics g = Graphics.FromHwnd(IntPtr.Zero)) 
         
  g.DrawEllipse(Pens.Black, pt.X - 10, pt.Y - 10, 20, 20); 

2- 我在上面的链接中提供的第二个选项是创建一个透明的最顶层窗口并在该窗口中进行所有绘图。这基本上为您可以绘制的桌面提供了一个透明的覆盖层。正如我在原始答案中提到的那样,一个可能的缺点是,在您的应用程序启动后创建的其他最顶层窗口会遮盖您的最顶层窗口。如果这是一个问题,这可以解决。

对于选项 2,使表单透明就像使用透明键一样简单,这允许鼠标点击等进入底层桌面。

BackColor = Color.LightGreen; 
TransparencyKey = Color.LightGreen; 

【讨论】:

大概这适用于全屏应用程序(游戏等)? 应该将 GetDesktopWindow() 传递给 Graphics.FromHwnd() 因为 IntPtr.Zero 是一个可能会改变的实现细节,并且肯定适用于多桌面或多桌面-会话工作站。【参考方案2】:

当您绘制到 HDC(NULL) 时,您会以非托管方式绘制到屏幕上。正如您所发现的,只要 Windows 刷新屏幕的该部分,您的更改就会被覆盖。

有几个选项,具体取决于您想要实现的目标:

    创建一个无边界的,可能 非矩形窗口。 (采用 SetWindowRgn 创建一个窗口 非矩形。)您可以将其设为桌面窗口的子窗口。 子类化桌面窗口。这并不简单,并且涉及 将DLL注入到 Explorer.exe 进程。

【讨论】:

如何使窗口成为桌面窗口的子窗口?有可用的代码示例吗?【参考方案3】:

要为桌面获取OnPaint,您需要将桌面窗口子类化并在收到WM_PAINT/WM_ERASEBKGND 消息时使用您的绘图逻辑。

正如您链接到的线程所说,您只能使用挂钩(来自 DLL 的SetWindowsHookEx)拦截发送到外部进程窗口的消息。

如前所述,透明窗口是另一种实现方式,或者(取决于更新频率)复制、绘制和设置临时壁纸(如 bginfo 所做的那样)。

【讨论】:

【参考方案4】:

这很难正确做到。

改为制作自己的无边界表单会更容易、更可靠。

【讨论】:

以上是关于如何在 C# 中有效地在桌面上绘图?的主要内容,如果未能解决你的问题,请参考以下文章

如何更好地在 c# (asp.net) 和 SQL Server 上保存和加载图片?

客户端服务器上安装的二进制程序如何方便地在授权服务器上进行授权(有有效期)?

如何最有效地在 SQL Server 中插入/更新几百万行?

我应该如何有效地在 Android 手机上的服务器之间发送 JSON 数据?

如何获取(逻辑)桌面上的项目总数(C#)

哪种 C# 数据结构允许最有效地在一对字符串中搜索子字符串?