-
概述
本文主要解决以下几个问题:- Matlab函数生成Dll;
- 在C#程序中调用生成的dll;
- 程序中需要同时显示多个Figure时的处理。
-
问题背景
工作中遇到在winform中作3维点云图的需求,网上翻阅了很多资料无果,最终无奈选择使用matlab作图,将matlab的figure嵌入到程序窗体中。
由于存在同时显示多个图像的需求,网上有将图像窗口嵌入程序中的方法,但没有找到同时使用多个figure的情况,为此做了一些尝试,将尝试的过程做简单记录。
测试过程中发现使用matlab的图像窗口会导致程序内存占用上升较多,特别是使用多个图像窗口时,所以以后如果能找到替代方法,预计会将这种做法废弃。
本文中用到的方法其实不局限于winform程序。 -
Matlab函数生成Dll
- 环境:Matlab r2020a
- 函数:
% 函数作用:根据传入的一维数组,画3维点云图 function [] = draw(xyz) figure() % 将一维数组转换成3*n并转置,因为点云是由一些(x,y,z)坐标的点构成 a = reshape(xyz, 3, length(xyz) / 3).'; % 转换为点云类型 p = pointCloud(b); % 这是一个专门用来作点云图的方法 % 听说如果是4维的数据的话,第4维可以用来指定颜色,如果没有指定颜色的话,默认渲染出来的彩图颜色还挺好看的 pcshow(p);
- dll生成步骤:
命令行输入deploytool->选择Library Compiler->选择.Net Assembly->增加函数文件->修改className->选择Package->选择生成的文件夹for_redistribution_files_only中的dll文件,我使用的是没有Native后缀的文件。
-
C#程序中调用Dll
程序引用中添加Com组件,选择Matlab Appliaction Type Library;
浏览,添加MWArray.dll,我的这个dll的路径在C:/Windows/Microsoft.Net/assembly/GAC_MSIL/MWArray下面,这边注意要根据是32位程序还是64位程序作出选择,我的程序是AnyCpu;
添加上一步骤中生成的dll的引用;
程序中增加对上面两个dll的using。
使用时:以我上面的函数为例,Draw draw = new Draw(); // int[]类型需要转换为MWNumericArray draw.draw((MWNumericArray)new int[] { 0, 0, 0});
注意:此处的Draw是IDisposable的,用完之后一定要Dispose掉,new出来并使用的Draw对象越多,占用的内存越大,这个东西占用的内存还是很大的。
-
多个图同时显示并存在特定的刷新需求
这个问题其实是我本篇中所要解决的最主要的问题,上面所说的这些内容都是可以在网上找到参考事项的,关于如何在winform程序中捕获到调用matlab函数生成的figure不做过多赘述,有需求可以参考文末的参考链接。- 解决这个问题有以下几个点需要注意或会用到:
- 每次调用figure会生成一个新的figure,如果不在figure的时候做出限制,figure的标题将按照顺序递增,依次为figure 1,figure 2,figure 3...
- 如果关闭figure,将会重新开始计数;
- 使用
figure('toolbar', 'none', 'menubar', 'none', "name", name, 'numberTitle', 'off');
对"name"属性和"numberTitle"属性做出限制,可以将标题中的figure n删除,并指定标题名称,"toolbar"和"menubar"属性用来关闭菜单; - clf可以清除图上的内容;
findobj('Type', 'figure')
函数可以用来找到当前打开的所有figure,返回值是一个数组。
- 具体要求:
- 同时打开多个figure;
- 随机可能需要刷新第n个figure上的图像。
- 解决这个问题我尝试了以下思路:(本人非专业使用matlab,只是曾经使用过,可能有一些简便方法我不知道)
- 先说如果只有一个figure的情况,可以加一个flag,表明当前是否需要生成新的figure,只在需要生成新的figure的时候调用figure函数,否则调用clf函数清空已作图像;
- 在需要刷新的时候,生成一个新的figure,并调用user32中的
SendMessage
接口,将上一个窗口关闭,此前需要获取到上一个窗口的句柄,
这种做法的问题在于窗口的闪烁非常严重,因为本来就涉及到捕获窗口的问题,figure窗口刚刚出来的时候其实是独立于我的程序界面的,很容易能够看到窗口一闪而过,而且经常会出现窗口嵌入我的程序中时窗口大小不一致,窗口很混乱,有时候能正常显示,有时候显示的数量不足,某些窗口没有显示出来,这个可能和找到的窗口句柄有关系。
这种做法的主要思想就是找到窗口句柄,关闭不需要的窗口,以此为蓝本,我希望能够将当前的窗口句柄作为参数传入接口中,接口函数中直接将图作在拥有指定句柄的图形窗口中,然而,matlab中的窗口句柄与我通过user32获取到的窗口句柄有所不同,matlab中的窗口句柄更像是一个对象,而user32获取到的窗口句柄是int型的。通过不断尝试,终于找到了下面的方法: - 为figure分配id,在调用函数的时候将id作为传入参数,以id作为figure的name,使用findobj函数查找所有已经打开的figure,根据figure.Name属性判断是否有和传入的name参数一致的figure,如果有则清空对应的figure,否则则创建新的figure