本博客所有文章分類的總目錄:【總目錄】本博客博文總目錄-實時更新
Matlab和C#混合編程文章目錄 :【目錄】Matlab和C#混合編程文章目錄
1.前言
做Matlab.NET混合編程好幾年了,雖然Matlab很多函數忘記得差不多了,但基本的東西還是能熟練使用。特別是在C#調用Matlab函數這方面,積累了比較多的經驗,和使用經驗密切相關。根據很多朋友經常遇到的WinForm窗體混編調用Matlab的Figure的問題,花了一些功夫,把這個封裝為C#控件,使得大家可以很容易調用Matlab的Figure了。
2.Matlab.NET混合編程概述
這方面就不仔細闡述了,主要是利用Matlab的Deploytool工具將m函數編譯為.NET程序集,然后在C#中調用的過程。然后程序可以在安裝MCR的機器上運行,這個過程如果懂Matalb和C#的人,其實看看幫助很容易理解,也有例子。在這里不仔細講解。2012年,我錄制過國內第一套Matlab.NET混合編程視頻教程,與ILoveMatab論壇的管理員Math商量之后,已經免費開放,大家去論壇下載即可。
混合編程最重要的是利用matlab的科學計算功能和強大的工具箱函數。但目前很多學生做這個,都只是為了簡單的繪圖,.NET繪圖其實也很強大。很多人混編,就想把Matlab繪圖產生的Figure在WinForm窗體中顯示,但是Matlab並沒有提供直接的解決方法。只能找另外的方法,我目前想到的有2種:
1.先把Figure保存為圖片,然后WinForm窗體去讀取圖片;
2.利用Windows API 技術,動態的獲取窗體句柄,然后嵌入到WinForm中。
第一種方法很容易想到,也很容易解決,就不仔細講了。
第二中方法懂開發的人一般能想得到,但是學生一般不是很容易想到,即使想到,做出來也很難。
下面我就把第二種方法的實現過程講解一下。
3.MatlabFigure控件的封裝過程
控件的設計思想:
1.能夠在WinForm桌面程序調用Matlab混編產生的Figure,主要是根據Figure的標題文字
2.Figure嵌入在控件C中,C的大小應該和Figure的大小一致,程序只需要關心控件的大小狀態就可以
3.初始化的時候,Figure的大小根據控件C的大小進行調整
4.Figure的大小將隨着控件的大小改變而改變
其實根據上面闡述的原理,精通Windows API的人很快就可以解決,主要就這么幾個函數,我貼一下代碼:
1 DllImport("user32.dll")] 2 public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 3 4 [DllImport("user32.dll")] 5 public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); 6 7 [DllImport("user32.dll")] 8 public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); 9 10 [StructLayout(LayoutKind.Sequential)] 11 public struct RECT 12 { 13 public int left; 14 public int top; 15 public int right; 16 public int bottom; 17 } 18 19 [DllImport("user32.dll")] 20 public static extern int GetClientRect(IntPtr hwnd, ref RECT rc); 21 22 [DllImport("user32.dll", EntryPoint = "SendMessage")] 23 private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); 24 25 /// <summary>最大化窗口,最小化窗口,正常大小窗口 26 /// nCmdShow:0隱藏,3最大化,6最小化,5正常顯示 27 /// </summary> 28 [DllImport("user32.dll", EntryPoint = "ShowWindow")] 29 public static extern int ShowWindow(IntPtr hwnd, int nCmdShow); 30 31 [DllImport("user32.dll")] 32 public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect); 33 34 35 public class _SW 36 { 37 public const int SW_HIDE = 0; 38 public const int SW_SHOWNORMAL = 1; 39 public const int SW_SHOWMINIMIZED = 2; 40 public const int SW_SHOWMAXIMIZED = 3; 41 public const int SW_MAXIMIZE = 3; 42 public const int SW_SHOWNOACTIVATE = 4; 43 public const int SW_SHOW = 5; 44 public const int SW_MINIMIZE = 6; 45 public const int SW_SHOWMINNOACTIVE = 7; 46 public const int SW_SHOWNA = 8; 47 public const int SW_RESTORE = 9; 48 }
在Figure窗體顯示后,通過FindWindow("SunAwtFrame", figureTitleName);來動態獲取窗體的句柄,注意Figure的類型都是”SunAwtFrame”,這個要專業點的軟件查出來。獲取窗體之后,然后通過 SetParent和MoveWindow來設置子窗體,並改變窗體的大小。控件的詳細代碼就不貼了,主要是上面的封裝過程吧,把邏輯搞懂了,很容易。由於源代碼是給商業項目使用,暫時不開放。貼一段窗體尋找的代碼,為了防止Figure還未顯示,程序已經在尋找,特意加了一個延時:
1 #region 尋找窗體 2 int num = 0 ; 3 while (num <5 ) 4 { 5 num++; 6 //若找不到窗體,循環5次,每次100ms 7 if (wf == IntPtr.Zero) 8 { 9 wf = FindWindow("SunAwtFrame", figureTitleName); 10 Thread.Sleep(timeSpan); 11 } 12 else 13 { //找到隱藏起來 14 ShowWindow(wf, _SW.SW_HIDE);break; 15 } 16 } 17 if (wf == IntPtr.Zero) 18 { 19 MessageBox.Show("無法獲取Figure窗體,請確認信息是否正確"); 20 return; 21 } 22 #endregion
看看效果圖:
特意新建了一個混編QQ交流群:154957583,有經驗的朋友可以一起探討。