-
概述
本文主要解決以下幾個問題:- 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