欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#?WPF調用QT窗口的方法

 更新時間:2023年02月09日 10:58:01   作者:路遙芝麻力  
本文主要介紹了C#?WPF調用QT窗口的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

WPF 程序內嵌 QT 窗體

1、目標:將QT控件(Qwiget)(或則基于QWiget的控件)(或則任何第三方C++控件)封裝為WPF可調用的用戶控件。簡單來說就是WPF程序調用QT窗體控件。

本人需要使用3D控件顯示一些3D點云等功能。但是又找不到好的兼容WPF的控件(大點云和效率原因)。最后選用CloudConpare作為點云顯示控件(該控件基于QT的QWiget)。
目前網絡上這方面的內容并不是太多,而且多數還都是雷同。
個人感覺 C# 跨平臺并不是太友好(或則我水平不夠),特別是3D方面。

本人對QT不是很熟悉,但是CloudCompare是基于QT寫的界面,所以沒辦法只能慢慢摸索,好在以前有MFC編程經驗,對C++還有點積累,過程中關于配置方面的問題我盡量詳細說明(對于C#編程者來說還是挺惡心的,QT的配置和CloudCompare的配置挺麻煩的)。

實現過程如下(可能需要稍微有點基礎才能看懂,我認為有意思的會寫多點 ,寫的不是太系統(tǒng)),可能有點亂,有點啰嗦,想到哪里寫到哪,見諒。

心路:
一開始查詢資料想通過中間庫 CLR鏈接C#和C++,簡單demo也測試OK,后期碰到控件句柄傳遞問題調試也比較麻煩,遂放棄(現在想來應該也是可以實現的)。
最終直接使用 C形式函數導出 的形式來創(chuàng)建DLL,也挺方便的。專業(yè)點叫P/Invoke(推薦大家一本書《精通.NET互操作:P/Invoke,C++Interop和COM Interop》)。

大概邏輯:WPF控件句柄–>傳遞給C++生成的QT庫–>動態(tài)庫根據傳遞過來的句柄創(chuàng)建一個QWiget–>根據這個QWiget生成一個GLWindow(真實的3D顯示窗體)–>C#保存這個指針方便下次訪問。
數據傳邏輯:主要是C#這邊發(fā)給C++ Dll數據,主要涉及到托管和非托管資源的問題、字節(jié)對齊等。

實現過程中可能有幾個主要問題:
1、C#和C++混合編程;
2、QT程序(QT事件循環(huán)QApplication.exec())如何封裝為Dll;
3、QT的UI線程和WPF的UI線程沖突問題(目前本人也沒完全弄懂,歡迎溝通);

工具:VS2019(Qt Visual Studio Tool 2.7.0)、QT5.14.2、CloudCompare2.6.12源碼。。。。

上代碼:

1、創(chuàng)建一個VS-QT的動態(tài)庫。

選擇Qtwidgets application,然后修改配置生成為dll。網上資料很多,不詳細描述(大概流程:修改輸出類型為dll,將沒必要的文件刪除即可(Main)(所有文件都可以刪除,然后新增一個QtWidgets class也行))。如下:

我們這里界面就不需要設置(因為我們不是直接用QT界面),只需要一個空白的Qwidget。(同志們只需要用Qwiget就可以在這里繪制了)
右鍵 編譯這個.ui文件。會生成一個ui_xxxx.h文件。添加這個文件到項目中,(可能在生成目錄的uic文件夾下,如有必要還需要將這個文件路徑加到包含目錄中。若是不添加可能會生成失?。?。
首次生成失敗很正常,各種QT環(huán)境問題。不要心急。

這里我們就獲得了一個帶QT的界面的C++庫。

2、WPF中引用它:

若是你們用的是Winform,那就比較方便了,直接拿到控件句柄(我這里使用的panel控件)傳遞給動態(tài)庫就行了。
若是你用的是WPF,會麻煩一點(因為WPF控件獲取不到“控件”句柄),這里在下試了很多,獲得的都是窗體句柄。所以只能使用WindowsFormsHost。上代碼

這里是本人在WPF創(chuàng)建了一個用戶控件的xaml文件。上代碼

public partial class Window3DControl : UserControl
    {
        public Window3DControl()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 3D顯示 窗口
        /// </summary>
        public Window3DControl_Net Control3D = new Window3DControl_Net();


        /// <summary>
        /// 創(chuàng)建真實的3D窗體,GlWindow
        /// </summary>
        /// <returns></returns>
        public bool Create3DWindow()
        {
            int res = Control3D.Creat3DWindow_Net((long)Panel3D.Handle, Panel3D.Width, Panel3D.Height);

            return res == 0;
        }

        /// <summary>
        /// 控件發(fā)生變化
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window3DControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if(Control3D.IsInitWindow)
            {
                int width = (int)(WindowForm3D.ActualWidth * 1.25);
                int Heigth = (int)(WindowForm3D.ActualHeight * 1.25);
                int res = Control3D.WindowSizeChanged_Net(width, Heigth);
            }
        }

        /// <summary>
        /// 3D窗體切換
        /// </summary>
        public void ChangeWindowModel()
        {
            if(WindowForm3D.Visibility == Visibility.Visible)
            {
                WindowForm3D.Visibility = Visibility.Collapsed;
                Button2D.Visibility = Visibility.Visible;
            }
            else
            {
                WindowForm3D.Visibility = Visibility.Visible;
                Button2D.Visibility = Visibility.Collapsed;
            }
        }

    }

上面是用戶控件的代碼部分。也很簡單只有幾個簡單功能。其中Control3D對象是我封裝的一個調用動態(tài)庫的接口類(只是封裝了一層),功能上直接調用C形式的函數接口也是可以的。上代碼

這里是封裝的3D對象的部分接口,C#這邊就很簡單了,都封裝成用戶控件了,那不是想怎么玩怎么玩。(關于C#定義函數接口就不描述了,C++那邊導出函數接口也不描述了)。上代碼

還有一點很重要(我感覺)如何顯示QT窗口正好覆蓋WPF中句柄對應的控件(可能會碰到直接顯示QT窗口在主界面的左上角)。有兩步很重要,通過如上圖,可以看到我們將控件句柄和對應的尺寸傳遞過去,并且將生成的QT窗口的實例對應的指針傳回來,為了下次能夠直接拿到這個QT窗口。可以看下我的創(chuàng)建窗口函數是如何實現的,上代碼

圖中標記部分,很重要 。(忘記從哪個大神哪里偷學來的)
另外為了C# 那邊能拿到C++這邊的對象指針。使用了二級指針概念(這個不太好解釋,要自己細細理解,這個不是偷學的,在下耗盡腦子想的)。
還有一個問題QT事件循環(huán),(若是你調用過QT的dll,可能就會發(fā)現這個問題),我這邊解決辦法就是,在程序開始(你認為的合適的地方)調用InitQTEnvironment接口,上代碼。

#include "qmfcapp.h"
int InitQtEnvironment()
{
	try
	{
		//if (QApplication::instance() == NULL)
		//{
		//	int argc = 0;
		//	g_app = new QApplication(argc, NULL);
		//	//QWidget* GroudWidget = new QWidget(NULL);
		//	//GroudWidget->setGeometry(0, 0,0, 1);//設置widget的大小
		//	//GroudWidget->showMinimized();
		//	//g_app->exec();
		//}
		if (QApplication::instance() == NULL)
		{
			return  QMfcApp::pluginInstance();
		}
		return 0;
	}
	catch(QException ex )
	{
		printf("Init Error");

		printf(ex.what());
		return -1;
	}
	
}

兩種方式都行,目的是創(chuàng)建出來QApplication這個靜態(tài)對象即可。(其中QMfcApp是偷學某個大佬)。
OK,其實到這里整個流程已經基本打通了,路走通了,其余的都好辦了。
關于數據傳遞問題,這里也說一下。C#和C++的基礎數據類型在內存中占位不盡相同,有興趣可以看下對照表(網上一大堆)。
若是使用CLR包裝C++dll,可以解決類型不一致問題(個人感覺CLR就是一次形參類型轉換而已,可能是我太淺薄了)。
若是我們這種直接調用C形式的函數接口。需要傳遞參數需要注意幾點。
1、基礎類型也需要注意內存占位是否一致。
2、結構體類型,需要考慮字節(jié)對齊和托管資源問題。思路:兩邊定義相同類型的結構體。直接傳遞結構體指針(首地址)本質上還是內存要一樣,不能亂。先上代碼(C++)

C#中數據結構

![](https://img-blog.csdnimg.cn/62431497e42241c18b2f6bb4bd98f5a3.jpg

仔細對比(字節(jié)對齊,還要考慮編譯器可能優(yōu)化)。
數組必須確定傳遞長度(內存分配才能連續(xù)),并且C#這邊申請的內存必須是非托管內存(使用Marsh申請)。關于C++傳遞數據到C#,上文也提到了二級指針,基礎類型或確定內存長度的可以直接傳遞,不確定的對象使用二級指針。關于內存釋放問題。大家可以網上找下,有幾種常用方法,此處不贅述。

按照慣例,上效果圖。

遺留問題:
玩過WPF的都知道,WPF有一個隱藏的UI線程,我們的屬性綁定控件和刷線界面都是
這個線程來更新的。QT也有一個類似的界面線程。因為我這邊主程序是WPF,QWiget只是作為一個控件來用的。
目前發(fā)現他們兩個界面線程會出現搶資源情況(我也是猜的,因為出現WPF的源已經改變了但是目標控件上沒有刷新(及時刷新)的現象)。各位大佬若有這方面的見解,請一定聯系我。抱拳?。?!

到此這篇關于C# WPF調用QT窗口的方法的文章就介紹到這了,更多相關C# WPF調用QT窗口內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C#中Dictionary<TKey,TValue>排序方式的實現

    C#中Dictionary<TKey,TValue>排序方式的實現

    這篇文章主要介紹了C#中Dictionary<TKey,TValue>排序方式的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-02-02
  • 詳解C#中Helper類的使用

    詳解C#中Helper類的使用

    項目中用戶頻繁訪問數據庫會導致程序的卡頓,甚至堵塞。使用緩存可以有效的降低用戶訪問數據庫的頻次,有效的減少并發(fā)的壓力。而helper類對緩存有了封裝,本文展示了封裝的示例代碼,需要的可以參考一下
    2022-04-04
  • C#中的多線程小試牛刀

    C#中的多線程小試牛刀

    這篇文章主要給大家介紹了關于C#中多線程的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用C#具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-05-05
  • C#中Byte[]和String之間轉換的方法

    C#中Byte[]和String之間轉換的方法

    很多朋友不清楚如何在Byte[]和String之間進行轉換?下面小編給大家?guī)砹薭yte與string轉換的方法,感興趣的朋友參考下吧
    2016-08-08
  • c# 插入數據效率測試(mongodb)

    c# 插入數據效率測試(mongodb)

    這篇文章主要介紹了c# 插入數據效率測試(mongodb),插入的速度要比Mysql和sqlserver都要快需要的朋友可以參考下
    2018-03-03
  • Unity實現截圖功能

    Unity實現截圖功能

    這篇文章主要為大家詳細介紹了Unity實現截圖功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • C#/VB.NET實現將Html轉為Word的示例詳解

    C#/VB.NET實現將Html轉為Word的示例詳解

    本文分享以C#程序代碼為例,實現將Html文件轉換Word文檔的方法(附VB.NET代碼)。在實際轉換場景中可參考本文的方法,感興趣的可以了解一下
    2022-07-07
  • 如何使用LinQ To Object把數組或DataTable中的數據進行向上匯總

    如何使用LinQ To Object把數組或DataTable中的數據進行向上匯總

    這篇文章主要介紹了如何使用LinQ To Object把數組或DataTable中的數據進行向上匯總,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • C#中的const和readonly關鍵字詳解

    C#中的const和readonly關鍵字詳解

    本文詳細講解了C#中的const和readonly關鍵字,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-08-08
  • 使用C#連接SQL?Server的詳細圖文教程

    使用C#連接SQL?Server的詳細圖文教程

    初學者學習上位機開發(fā)遇到數據庫連接不上,是很常見的情況,可能會以各種形式呈現出來,下面這篇文章主要給大家介紹了關于使用C#連接SQL?Server的詳細圖文教程,需要的朋友可以參考下
    2023-02-02

最新評論