提升WinForm应用性能:C++与C#结合实现高效动画绘制的秘诀
liebian365 2024-11-04 14:30 16 浏览 0 评论
前言
在Windows Forms (WinForms) 应用程序开发过程中,动画绘制往往会占用大量的UI线程资源,导致应用程序卡顿甚至无响应。本文将介绍如何通过结合C++和C#,在WinForms应用中实现高效的动画绘制,从而提升应用性能。
为什么选择C++与C#结合?
C#是开发WinForms应用的主要语言,其强大的功能和易用性使其成为许多开发者的首选。然而,C#运行在.NET托管环境中,性能上较C++稍逊一筹。C++作为一种底层语言,可以直接生成机器码,具有更高的执行效率。因此,将复杂的动画绘制逻辑交给C++处理,可以大大减轻C# UI线程的负担,从而提升应用性能。
动画绘制的实现方案对比
C# 自己在Panel中调用动画
直接在C#中实现动画绘制非常直观和简洁,展示如何在Panel上绘制五角星:
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace AnimationDrawer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
panel1.MouseClick += new MouseEventHandler(panel1_MouseClick);
}
private void Form1_Load(object sender, EventArgs e)
{
Task.Run(() =>
{
int i = 0;
while (true)
{
int x = new Random().Next(1000);
int y = new Random().Next(1000);
panel1_MouseClick(this, new MouseEventArgs(MouseButtons.Left, 1, x, y, 1));
Thread.Sleep(100);
}
});
}
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
Task.Run(() =>
{
Stopwatch st = new Stopwatch();
st.Start();
// 在后台线程执行动画逻辑,减少UI线程负担
Invoke(new Action(() =>
{
Graphics g = panel1.CreateGraphics();
DrawStar(g, e.X, e.Y, 50);
g.Dispose();
}));
st.Stop();
Trace.WriteLine(#34;DrawStar {st.ElapsedMilliseconds} ms");
});
}
private void DrawStar(Graphics g, int x, int y, int radius)
{
const double PI = 3.14159265358979323846;
Point[] points = new Point[100000];
for (int i = 0; i < 100000; ++i)
{
double angle = i * PI / 5;
int r = (i % 2 == 0) ? radius : radius / 2;
points[i] = new Point(x + (int)(r * Math.Cos(angle - PI / 2)), y + (int)(r * Math.Sin(angle - PI / 2)));
}
g.DrawPolygon(Pens.Red, points);
}
}
}
这个示例比较简单,基本意思就是在Panel上的随机位置绘制一个五角星。程序启动后执行绘制动画。
监控执行结果:
。。。。
DrawStar 8025 ms
DrawStar 8010 ms
DrawStar 7900 ms
DrawStar 7860 ms
DrawStar 7981 ms
DrawStar 7959 ms
DrawStar 8174 ms
DrawStar 8210 ms
程序“[12332] AnimationDrawer.exe”已退出,返回值为 4294967295 (0xffffffff)。
因为绘制Point点比较多,接近10万,所以每次绘制消耗时间比较长。现在我们来看看C++编码如何实现
C++ 函数实现的动画
通过C++实现动画绘制,可以更有效地利用系统资源,减少UI线程的占用。以下是一个C++代码示例,用于绘制五角星:
编写C++部分代码:AnimationDrawer.cpp,和C#绘制一样,也是10万个Point.
// AnimationDrawer.cpp
#include "pch.h"
#include <windows.h>
#include <cmath>
void DrawStar(HDC hdc, int x, int y, int radius)
{
const double PI = 3.14159265358979323846;
POINT points[100000];
for (int i = 0; i < 100000; ++i) {
double angle = i * PI / 5;
int r = (i % 2 == 0) ? radius : radius / 2;
points[i] = { x + static_cast<int>(r * cos(angle - PI / 2)), y + static_cast<int>(r * sin(angle - PI / 2)) };
}
Polygon(hdc, points, 10);
}
extern "C" __declspec(dllexport) void __stdcall DrawStarAt(HDC hdc, int x, int y)
{
DrawStar(hdc, x, y, 50); // 绘制半径为50的五角星
}
编译上述代码生成一个DLL文件(如AnimationDrawerCpp.dll),然后在C#中调用:
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace AnimationDrawer
{
public partial class Form1 : Form
{
[DllImport("AnimationDrawerCpp.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void DrawStarAt(IntPtr hdc, int x, int y);
public Form1()
{
InitializeComponent();
panel1.MouseClick += new MouseEventHandler(panel1_MouseClick);
}
private void Form1_Load(object sender, EventArgs e)
{
Task.Run(() =>
{
int i = 0;
while (true)
{
int x = new Random().Next(1000);
int y = new Random().Next(1000);
panel1_MouseClick(this, new MouseEventArgs(MouseButtons.Left, 1, x, y, 1));
Thread.Sleep(100);
}
});
}
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
Task.Run(() =>
{
Stopwatch st = new Stopwatch();
st.Start();
Graphics g = panel1.CreateGraphics();
IntPtr hdc = g.GetHdc();
DrawStarAt(hdc, e.X, e.Y);
g.ReleaseHdc(hdc);
g.Dispose();
st.Stop();
Trace.WriteLine(#34;DrawStarAt {st.ElapsedMilliseconds} ms");
});
}
}
}
这里,我们需要重点说明的是DrawStarAt函数的参数传递中hdc这个句柄的作用:
在 C# 中调用 C++ 方法并传递 Panel 控件的句柄(handle)用于实现跨语言的控件操作或者将 Windows 控件(如 Panel)的底层句柄传递给 C++ 代码进行操作。这里的句柄是一个指向控件在操作系统中唯一标识的标识符,它可以让底层的 C++ 代码直接与控件进行交互,例如绘制、操作、或者执行其他与控件相关的操作。
简单的说:句柄的传递,是C++绘制的代码得以在C#控件上绘制出来的核心,C#授权给C++代码操作控件进行重绘等操作。执行完毕后释放句柄。防止内存泄漏。
健康执行结果:
DrawStarAt 2 ms
DrawStarAt 2 ms
DrawStarAt 2 ms
DrawStarAt 2 ms
DrawStarAt 2 ms
DrawStarAt 3 ms
DrawStarAt 2 ms
DrawStarAt 2 ms
程序“[38600] AnimationDrawer.exe”已退出,返回值为 4294967295 (0xffffffff)。
性能对比与总结
从结果中,我们可以明显看出,双方执行代码的效率差距有多大。是因为,在性能方面,直接在C#中绘制动画会更多地占用UI线程,因为所有的绘制逻辑和动画计算都在C#的UI线程上执行。而通过调用C++函数实现的动画可以将一些计算和绘制的工作转移到C++代码中,从而减少C# UI线程的负担。
C# 在Panel中调用动画:
- 优点:代码编写和调试相对简单,所有逻辑都在C#中,无需处理跨语言调用的问题。
- 缺点:动画绘制直接在UI线程上进行,可以使用异步,但是过于频繁或者绘制耗时时,会阻塞UI线程,影响用户界面的响应速度。
C++ 函数实现的动画:
- 优点:动画逻辑和绘制由C++代码完成,可以提高性能,减少C# UI线程的负担。可以将复杂的计算和绘制逻辑转移到C++中,以减少C#中耗时的操作。
- 缺点:需要编写和调试C++代码,并处理跨语言调用,开发复杂度较高。
通过结合C++和C#,我们可以在WinForms应用中实现高效的动画绘制,提升用户体验。在实际开发中,可以根据项目需求选择合适的方案,以平衡性能和开发效率。如果你的应用也存在可以优化的空间,试试通过C++与C#结合实现高效动画绘制,提升WinForm应用性能,让用户体验更流畅!
如果本文对你有帮助,我将非常荣幸。
如果你对C++辅助C#绘图有其他的看法,欢迎留言交流。
如果你喜欢我的文章,谢谢三连,点赞,关注,转发吧!!!
相关推荐
- 4万多吨豪华游轮遇险 竟是因为这个原因……
-
(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...
- “菜鸟黑客”必用兵器之“渗透测试篇二”
-
"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...
- 科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白
-
作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...
- 麦子陪你做作业(二):KEGG通路数据库的正确打开姿势
-
作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...
- 知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势
-
智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...
- 每日新闻播报(September 14)_每日新闻播报英文
-
AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...
- 香港新巴城巴开放实时到站数据 供科技界研发使用
-
中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...
- 5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper
-
本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...
- Qt动画效果展示_qt显示图片
-
今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...
- 如何从0到1设计实现一门自己的脚本语言
-
作者:dong...
- 三年级语文上册 仿写句子 需要的直接下载打印吧
-
描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...
- C++|那些一看就很简洁、优雅、经典的小代码段
-
目录0等概率随机洗牌:1大小写转换2字符串复制...
- 二年级上册语文必考句子仿写,家长打印,孩子照着练
-
二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)