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

C#?WPF調(diào)用QT窗口的方法

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

WPF 程序內(nèi)嵌 QT 窗體

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

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

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

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

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

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

實現(xiàn)過程中可能有幾個主要問題:
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。網(wǎng)上資料很多,不詳細(xì)描述(大概流程:修改輸出類型為dll,將沒必要的文件刪除即可(Main)(所有文件都可以刪除,然后新增一個QtWidgets class也行))。如下:

我們這里界面就不需要設(shè)置(因為我們不是直接用QT界面),只需要一個空白的Qwidget。(同志們只需要用Qwiget就可以在這里繪制了)
右鍵 編譯這個.ui文件。會生成一個ui_xxxx.h文件。添加這個文件到項目中,(可能在生成目錄的uic文件夾下,如有必要還需要將這個文件路徑加到包含目錄中。若是不添加可能會生成失?。?br />首次生成失敗很正常,各種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對象是我封裝的一個調(diào)用動態(tài)庫的接口類(只是封裝了一層),功能上直接調(diào)用C形式的函數(shù)接口也是可以的。上代碼

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

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

圖中標(biāo)記部分,很重要 。(忘記從哪個大神哪里偷學(xué)來的)
另外為了C# 那邊能拿到C++這邊的對象指針。使用了二級指針概念(這個不太好解釋,要自己細(xì)細(xì)理解,這個不是偷學(xué)的,在下耗盡腦子想的)。
還有一個問題QT事件循環(huán),(若是你調(diào)用過QT的dll,可能就會發(fā)現(xiàn)這個問題),我這邊解決辦法就是,在程序開始(你認(rèn)為的合適的地方)調(diào)用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);//設(shè)置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是偷學(xué)某個大佬)。
OK,其實到這里整個流程已經(jīng)基本打通了,路走通了,其余的都好辦了。
關(guān)于數(shù)據(jù)傳遞問題,這里也說一下。C#和C++的基礎(chǔ)數(shù)據(jù)類型在內(nèi)存中占位不盡相同,有興趣可以看下對照表(網(wǎng)上一大堆)。
若是使用CLR包裝C++dll,可以解決類型不一致問題(個人感覺CLR就是一次形參類型轉(zhuǎn)換而已,可能是我太淺薄了)。
若是我們這種直接調(diào)用C形式的函數(shù)接口。需要傳遞參數(shù)需要注意幾點。
1、基礎(chǔ)類型也需要注意內(nèi)存占位是否一致。
2、結(jié)構(gòu)體類型,需要考慮字節(jié)對齊和托管資源問題。思路:兩邊定義相同類型的結(jié)構(gòu)體。直接傳遞結(jié)構(gòu)體指針(首地址)本質(zhì)上還是內(nèi)存要一樣,不能亂。先上代碼(C++)

C#中數(shù)據(jù)結(jié)構(gòu)

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

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

按照慣例,上效果圖。

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

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

相關(guān)文章

  • C#中Dictionary<TKey,TValue>排序方式的實現(xiàn)

    C#中Dictionary<TKey,TValue>排序方式的實現(xiàn)

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

    詳解C#中Helper類的使用

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

    C#中的多線程小試牛刀

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

    C#中Byte[]和String之間轉(zhuǎn)換的方法

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

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

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

    Unity實現(xiàn)截圖功能

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

    C#/VB.NET實現(xiàn)將Html轉(zhuǎn)為Word的示例詳解

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

    如何使用LinQ To Object把數(shù)組或DataTable中的數(shù)據(jù)進(jìn)行向上匯總

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

    C#中的const和readonly關(guān)鍵字詳解

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

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

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

最新評論