iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C#WPF调用QT窗口的方法
  • 957
分享到

C#WPF调用QT窗口的方法

C#WPF调用QT窗口C#WPF调用QT 2023-02-09 12:02:52 957人浏览 八月长安
摘要

WPF 程序内嵌 Qt 窗体 1、目标:将QT控件(Qwiget)(或则基于QWiget的控件)(或则任何第三方c++控件)封装为WPF可调用的用户控件。简单来说就是WPF程序调用Q

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的配置挺麻烦的)。

实现过程如下(可能需要稍微有点基础才能看懂,我认为有意思的会写多点 ,写的不是太系统),可能有点乱,有点啰嗦,想到哪里写到哪,见谅。

心路:
一开始查询资料想通过中间库 CLR链接C#和C++,简单demo也测试OK,后期碰到控件句柄传递问题调试也比较麻烦,遂放弃(现在想来应该也是可以实现的)。
最终直接使用 C形式函数导出 的形式来创建DLL,也挺方便的。专业点叫P/Invoke(推荐大家一本书《精通.net互操作:P/Invoke,C++Interop和COM Interop》)。

大概逻辑:WPF控件句柄–>传递给C++生成的QT库–>动态库根据传递过来的句柄创建一个QWiget–>根据这个QWiget生成一个GLWindow(真实的3D显示窗体)–>C#保存这个指针方便下次访问。
数据传逻辑:主要是C#这边发给C++ Dll数据,主要涉及到托管和非托管资源的问题、字节对齐等。

实现过程中可能有几个主要问题:
1、C#和C++混合编程;
2、QT程序(QT事件循环QApplication.exec())如何封装为Dll;
3、QT的UI线程和WPF的UI线程冲突问题(目前本人也没完全弄懂,欢迎沟通);

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

上代码:

1、创建一个VS-QT的动态库。

选择Qtwidgets application,然后修改配置生成为dll。网上资料很多,不详细描述(大概流程:修改输出类型为dll,将没必要的文件删除即可(Main)(所有文件都可以删除,然后新增一个QtWidgets class也行))。如下:

我们这里界面就不需要设置(因为我们不是直接用QT界面),只需要一个空白的Qwidget。(同志们只需要用Qwiget就可以在这里绘制了)
右键 编译这个.ui文件。会生成一个ui_xxxx.h文件。添加这个文件到项目中,(可能在生成目录的uic文件夹下,如有必要还需要将这个文件路径加到包含目录中。若是不添加可能会生成失败)。
首次生成失败很正常,各种QT环境问题。不要心急。

这里我们就获得了一个带QT的界面的C++库。

2、WPF中引用它:

若是你们用的是winform,那就比较方便了,直接拿到控件句柄(我这里使用的panel控件)传递给动态库就行了。
若是你用的是WPF,会麻烦一点(因为WPF控件获取不到“控件”句柄),这里在下试了很多,获得的都是窗体句柄。所以只能使用windowsFORMsHost。上代码

这里是本人在WPF创建了一个用户控件的xaml文件。上代码

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

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


        /// <summary>
        /// 创建真实的3D窗体,GlWindow
        /// </summary>
        /// <returns></returns>
        public bool Create3DWindow()
        {
            int res = Control3D.Creat3DWindow_Net((long)Panel3D.Handle, Panel3D.Width, Panel3D.Height);

            return res == 0;
        }

        /// <summary>
        /// 控件发生变化
        /// </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对象是我封装的一个调用动态库的接口类(只是封装了一层),功能上直接调用C形式的函数接口也是可以的。上代码

这里是封装的3D对象的部分接口,C#这边就很简单了,都封装成用户控件了,那不是想怎么玩怎么玩。(关于C#定义函数接口就不描述了,C++那边导出函数接口也不描述了)。上代码

还有一点很重要(我感觉)如何显示QT窗口正好覆盖WPF中句柄对应的控件(可能会碰到直接显示QT窗口在主界面的左上角)。有两步很重要,通过如上图,可以看到我们将控件句柄和对应的尺寸传递过去,并且将生成的QT窗口的实例对应的指针传回来,为了下次能够直接拿到这个QT窗口。可以看下我的创建窗口函数是如何实现的,上代码

图中标记部分,很重要 。(忘记从哪个大神哪里偷学来的)
另外为了C# 那边能拿到C++这边的对象指针。使用了二级指针概念(这个不太好解释,要自己细细理解,这个不是偷学的,在下耗尽脑子想的)。
还有一个问题QT事件循环,(若是你调用过QT的dll,可能就会发现这个问题),我这边解决办法就是,在程序开始(你认为的合适的地方)调用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;
	}
	
}

两种方式都行,目的是创建出来QApplication这个静态对象即可。(其中QMfcApp是偷学某个大佬)。
OK,其实到这里整个流程已经基本打通了,路走通了,其余的都好办了。
关于数据传递问题,这里也说一下。C#和C++的基础数据类型在内存中占位不尽相同,有兴趣可以看下对照表(网上一大堆)。
若是使用CLR包装C++dll,可以解决类型不一致问题(个人感觉CLR就是一次形参类型转换而已,可能是我太浅薄了)。
若是我们这种直接调用C形式的函数接口。需要传递参数需要注意几点。
1、基础类型也需要注意内存占位是否一致。
2、结构体类型,需要考虑字节对齐和托管资源问题。思路:两边定义相同类型的结构体。直接传递结构体指针(首地址)本质上还是内存要一样,不能乱。先上代码(C++)

C#中数据结构

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

仔细对比(字节对齐,还要考虑编译器可能优化)。
数组必须确定传递长度(内存分配才能连续),并且C#这边申请的内存必须是非托管内存(使用Marsh申请)。关于C++传递数据到C#,上文也提到了二级指针,基础类型或确定内存长度的可以直接传递,不确定的对象使用二级指针。关于内存释放问题。大家可以网上找下,有几种常用方法,此处不赘述。

按照惯例,上效果图。

遗留问题:
玩过WPF的都知道,WPF有一个隐藏的UI线程,我们的属性绑定控件和刷线界面都是
这个线程来更新的。QT也有一个类似的界面线程。因为我这边主程序是WPF,QWiget只是作为一个控件来用的。
目前发现他们两个界面线程会出现抢资源情况(我也是猜的,因为出现WPF的源已经改变了但是目标控件上没有刷新(及时刷新)的现象)。各位大佬若有这方面的见解,请一定联系我。抱拳!!!

到此这篇关于C# WPF调用QT窗口的方法的文章就介绍到这了,更多相关C# WPF调用QT窗口内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C#WPF调用QT窗口的方法

本文链接: https://www.lsjlt.com/news/195354.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C#WPF调用QT窗口的方法
    WPF 程序内嵌 QT 窗体 1、目标:将QT控件(Qwiget)(或则基于QWiget的控件)(或则任何第三方C++控件)封装为WPF可调用的用户控件。简单来说就是WPF程序调用Q...
    99+
    2023-02-09
    C# WPF调用QT窗口 C# WPF调用QT
  • wpf子窗口调用主窗口的方法是什么
    在WPF中,子窗口可以通过以下几种方式调用主窗口的方法:1. 通过子窗口的Owner属性获取到主窗口的实例,然后直接调用主窗口的方法...
    99+
    2023-08-16
    wpf
  • QT编写窗口插件实现调用窗口的自适应
    前言 最近项目中遇到插件架构,将几个功能模块分别写成了dll供主程序调用。本文主要在QT下实现这样一个功能: 编写一个dll,里面包含一个QDialog对话框作为主窗口。该dll提供...
    99+
    2024-04-02
  • vue跨窗口通信之新窗口调用父窗口方法实例
    众所周知,在vue中bus等工具只能跨组件通信,如何实现跨窗口通信呢? 场景如下,我们在A窗口中新开了B窗口,想在B窗口中调用A窗口的方法? 这里还总结了一点window事件的方法:...
    99+
    2023-01-17
    vue跨窗口通信 vue多窗口 vue调用父窗口方法
  • javascript中怎么调用父窗口的方法
    javascript中怎么调用父窗口的方法,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。javascript调用父窗口的方法:...
    99+
    2024-04-02
  • C#如何调用MFC窗口DLL
    目录C#调用MFC 窗口 DLLMFC DLLMFC DLL属性C# 调用 C++ MFC DLLC++ MFC DLL 的封装C# 中调用,CharSet须设置为多字节的 Ansi...
    99+
    2024-04-02
  • Qt之调用C#的动态库的解决方法
    环境:VS2019+Qt5.12 1. CLR库安装         首先,如果你VS2019没有安装...
    99+
    2024-04-02
  • wpf调用python的方法是什么
    在WPF中调用Python方法,可以通过以下几种方式:1. 使用Python标准库的`subprocess`模块,通过调用Pytho...
    99+
    2023-10-12
    wpf python
  • PyQT5之使用QT Designer创建基本窗口方式
    目录环境配置使用QT Designer布局窗体UI文件的编译编译后的.PY源码运行结果总结环境配置 pip install pyqt5 (安装pyQT5库):pyuic5包含在内pi...
    99+
    2023-02-24
    PyQT5 QT Designer QT Designer创建基本窗口 PyQT5 QT Designer窗口
  • C#实现悬浮窗口的方法详解
    目录一 悬浮窗口二 创建悬浮窗口1 实现细节2 细节三 圆形背景一 悬浮窗口 特点: ① 窗口一般较小,有时为不规则背景; ② 置顶显示; ③ 窗口支持拖动; ④ 一般用于程序状态显...
    99+
    2022-12-21
    C#悬浮窗口 C# 窗口
  • c# WPF中CheckBox样式的使用方法
    本篇内容主要讲解“c# WPF中CheckBox样式的使用方法 ”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“c# WPF中CheckBox样式的使用方法 ”吧!背景  很多时候我们使用WPF开...
    99+
    2023-06-07
  • C#后台调用WebApi接口的实现方法
    目录1.WebRequest方式2.HttpClient 方式1.WebRequest方式 private void button1_Click(object sender, Eve...
    99+
    2024-04-02
  • SQL窗口函数的使用方法
    目录什么是窗口函数窗口函数组成部分1.创建数据分区2.分区内的排序3.指定窗口大小窗口函数分类1.聚合窗口函数2.排名窗口函数3.取值窗口函数什么是窗口函数 SQL窗口函数为在线分析...
    99+
    2024-04-02
  • Win7的任务栏预览窗口太小调整方法
    步骤1:打开注册表编辑器   (开始,运行…,输入regedit回车;也可以按win键+R键,输入regedit回车;还可以打开Windows7优化大师,点击系统工具箱,打开注册表编辑器)   步骤2:在左...
    99+
    2023-05-25
    Win7 任务栏 窗口 调整 预览 太小
  • PyQT5中怎么使用QT Designer创建基本窗口方式
    这篇文章主要介绍“PyQT5中怎么使用QT Designer创建基本窗口方式”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“PyQT5中怎么使用QT Designer创建基本窗口方...
    99+
    2023-07-05
  • javascript窗口的关闭方法
    这篇文章主要介绍javascript窗口的关闭方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!javascript窗口关闭的方法:1、JS定时自动关闭窗口;2、点击链接没有提示的JS关闭窗口;3、窗口没有提示自动关...
    99+
    2023-06-14
  • EasyUI 的Window窗口refresh方法
    EasyUI中的Window窗口组件没有提供refresh方法。如果需要刷新Window窗口内容,可以使用以下两种方法:1. 使用l...
    99+
    2023-09-08
    EasyUI
  • java调用c语言接口的方法是什么
    Java调用C语言接口的方法主要有以下几种:1. 使用Java Native Interface(JNI):JNI是Java提供的一...
    99+
    2023-08-08
    java c语言
  • C#调用C++动态库接口函数和回调函数方法
    目录1. 前言2. 普通接口函数调用示例2.1 C++端编写接口2.2 C#端调用3. 回调函数调用示例3.1 C++端编写接口3.2 C#端调用1. 前言 需求: 当前C已经写好了...
    99+
    2024-04-02
  • C++的Qt MdiArea多窗体组件怎么使用
    本篇内容主要讲解“C++的Qt MdiArea多窗体组件怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++的Qt MdiArea多窗体组件怎么使用”吧!MDI窗体控...
    99+
    2023-06-21
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作