QT打开外部程序并嵌入Qt子窗口的缺点

文章讨论了在QT环境中如何通过WindowsAPI来嵌入外部程序到界面,但指出这种方法在其他平台如Mac上不可行,并可能导致闪烁、界面残留和响应问题。作者建议要么以分离方式启动程序,要么在源码层面整合。代码示例展示了QProcess的使用和窗口处理过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先可以参考如下文章:

QT打开外部程序并嵌入Qt界面_qt界面嵌入外部应用程序_初学小白Lu的博客-CSDN博客

 Qt嵌入外部程序界面初探_qt嵌入其他程序窗口_liming4675的博客-CSDN博客

 QT 如何把外部程序嵌入到QT界面_qt嵌入其他程序窗口_hellokandy的博客-CSDN博客

 Qt界面程序中嵌入其他可执行exe程序_qt 把exe嵌入窗口_new_2018的博客-CSDN博客

 Qt 嵌入第三方程序_qt 内嵌第三方程序_缘如风的博客-CSDN博客

QT中使用嵌入窗口_qt 嵌入窗口_blwinner的博客-CSDN博客

 qt中父进程窗口嵌入子进程产生的窗口_tusong86的博客-CSDN博客

缺点就是:

  1. 依赖windows的原生api,因此别的平台,可能就无法实现了,例如mac上好像就不行了
  2. 需要先通过QProcess等方式打开该软件,然后进行嵌入,会导致被嵌软件闪烁一下,然后嵌进去,影响使用感。这个问题是无法解决的,就算QProcess启动后,立刻进行嵌入,也会闪现一下软件的
  3. 再拉伸外面软件时,被嵌软件出现锯齿状残留等现象,明显是有问题的
  4. 可能鼠标,或者键盘啥的,响应有奇奇怪怪的问题

总之,这样做,是不好用的,所以要么就是以分离软件的形式启动,让它独立运行,或者直接嵌入源码一起编译了(在两个软件都是自己开发的情况了,因为需要源码)。

mainwindow.h 文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}


class QProcess;


class WidgetScheulerAnalysis : public QMainWindow
{
    Q_OBJECT
    
public:
    explicit WidgetScheulerAnalysis(QWidget *parent = 0);
    ~WidgetScheulerAnalysis();
    
private slots:
    void on_pushButton_clicked();
    
    void on_processStarted();
private:
    Ui::MainWindow *ui;
    
    QProcess* m_process;
    QWindow* m_window;
    QWidget* m_widget;
};

#endif // MAINWINDOW_H

mainwindow.cpp 文件

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <Windows.h>

#include <QProcess>
#include <QWindow>
#include <QDebug>
#include <QDir>
#include <QMessageBox>






//自定义结构体
struct handle_data {
	unsigned long process_id;
	HWND best_handle;
};

BOOL IsMainWindow(HWND handle);
BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam);
HWND FindMainWindow(unsigned long process_id);//通过进程id号获取主窗口句柄


BOOL IsMainWindow(HWND handle)
{
	return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle);
}

BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam)
{
	handle_data& data = *(handle_data*)lParam;
	unsigned long process_id = 0;
	GetWindowThreadProcessId(handle, &process_id);
	if (data.process_id != process_id || !IsMainWindow(handle)) {
		return TRUE;
	}
	data.best_handle = handle;
	return FALSE;
}


//通过进程id号获取主窗口句柄
HWND FindMainWindow(unsigned long process_id)
{
	handle_data data;
	data.process_id = process_id;
	data.best_handle = 0;
	EnumWindows(EnumWindowsCallback, (LPARAM)&data);
	return data.best_handle;
}










WidgetScheulerAnalysis::WidgetScheulerAnalysis(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    

}

WidgetScheulerAnalysis::~WidgetScheulerAnalysis()
{
    delete ui;
}

void WidgetScheulerAnalysis::on_pushButton_clicked()
{
#if 0
//    QProcess *pro = new QProcess(this);
//    pro->start("TaskSchedSimulatPlatform/TaskSchedSimulatPlatform.exe");
    
//    QString Name = "TaskSchedSimulatPlatform";
    
    //启动
    QDir::setCurrent("C:\\windows\\system32");
    QProcess *pro = new QProcess(this);
    pro->start("notepad.exe");
//    pro->waitForStarted();
    
//    Sleep(10);
    
    QString Name = "无标题 - 记事本";
//    WId hwnd = (WId)FindWindow(L"MainWindow",(LPCTSTR)Name.unicode());
    
    WId hwnd ;
    while(1)
    {
       hwnd = (WId)FindWindow(L"Notepad",(LPCTSTR)Name.unicode());
        if(hwnd != 0)
            break;
    }
    
    qDebug()<<hwnd;
    
    //嵌入
    if (hwnd > 0)
    {
        QWindow *m_window;
        m_window = QWindow::fromWinId(WId(hwnd));
        QWidget *m_widget;
        m_widget = QWidget::createWindowContainer(m_window,this);
        ui->verticalLayout->addWidget(m_widget);
    }
    
#endif
    
    
    /*
    *启动外部程序
    */
    //QString cmd = "D:/Program Files/InnovMetric/PolyWorks MS 2021/bin/polyworks.exe";
    //QString cmd = "D:/Program Files (x86)/Adobe/Reader 11.0/Reader/AcroRd32.exe";
    //QString cmd = "D:/Program Files/MVS/MVS/Applications/Win64/MVS.exe";
    
    QString exePath = "TaskSchedSimulatPlatform/TaskSchedSimulatPlatform.exe";
    
    m_process = new QProcess(this);
    connect(m_process, &QProcess::started, this, &WidgetScheulerAnalysis::on_processStarted);
    m_process->setParent(this);	
	QStringList arg;
	arg << "";
    m_process->start(exePath, arg);//外部程序启动后,将随主程序的退出而退出 
    //m_process->start(exePath);//外部程序启动后,将随主程序的退出而退出  

    
}


//嵌入外部程序
void WidgetScheulerAnalysis::on_processStarted()
{   
	qint64 id = m_process->processId();//如果程序没有运行,将会返回0
//    while (1) {
//        if(m_process->state() == QProcess::Running  && id !=0)
//            break;
//    }
//	if (id == 0)
//	{
//		QMessageBox::information(NULL, "提示", "程序没有启动");
//		return;
//	}

//	Sleep(100);
	qDebug() << "Status: " << m_process->state();
//	HWND mainwindowHwnd = FindMainWindow(id);
    
    HWND mainwindowHwnd;
    while (1) {
        mainwindowHwnd = FindMainWindow(id);
        if(mainwindowHwnd)
            break;
    }
    
//	qDebug() << "mainwindowHwnd: " << mainwindowHwnd;
//	if (!mainwindowHwnd)
//		return;
    
//    while (1) {
//        if(mainwindowHwnd != 0)
//            break;
//    }

    QWindow *m_window;
    m_window = QWindow::fromWinId(WId(mainwindowHwnd));
    m_window->setFlags(m_window->flags() | Qt::CustomizeWindowHint | Qt::WindowTitleHint); //这边可以设置一下属性
    
    QWidget *m_widget;
    m_widget = QWidget::createWindowContainer(m_window,this);
    ui->verticalLayout->addWidget(m_widget);

}








<think>好的,我现在需要回答用户的问题:“Qt能不能和Raylib结合?”首先,我得理解这两个框架的特点和用途。 Qt是一个跨平台的C++应用程序框架,广泛用于开发GUI程序,支持多种功能,包括界面设计、网络通信、数据库交互等。而Raylib是一个专注于游戏开发的C语言库,强调简单性和高性能,主要用于图形渲染、输入处理和音频管理。 用户想知道这两个库能否结合使用。可能的场景是,用户希望利用Qt的强大GUI功能来构建应用程序的界面,同时使用Raylib处理游戏或图形渲染部分。比如,开发一个游戏编辑器,用Qt做工具栏和菜单,用Raylib显示游戏画面。 接下来,我需要分析两者结合的可行性。首先,技术层面是否兼容。Qt使用自己的渲染引擎(如QPainter或OpenGL集成),而Raylib基于OpenGL(或其它后端)。两者如果同时使用OpenGL上下文,可能会有冲突,需要正确处理窗口和上下文的管理。 其次,代码语言方面,Qt是C++,Raylib是C。虽然C++可以调用C代码,但需要注意头文件的包含和链接的正确性。例如,在C++中使用Raylib的头文件时,需要使用`extern "C"`来避免名称修饰问题。 然后,我需要考虑实际整合的步骤。例如,如何在Qt窗口嵌入Raylib的渲染窗口。可能的方法包括将Raylib的渲染目标设置为Qt的一个窗口部件,或者通过共享OpenGL上下文来实现。这需要了解Qt的OpenGL模块(如QOpenGLWidget)和Raylib的窗口初始化设置。 另外,事件处理也是一个关键点。Qt和Raylib都有自己的事件循环,如何协调两者的输入事件(如鼠标、键盘)以避免冲突或重复处理。可能需要将Qt的事件传递给Raylib,或者禁用其中一方的事件处理。 还要考虑资源管理,比如纹理、声音等资源加载是否会有冲突,以及内存管理是否一致。需要确保两者的资源路径和加载方式兼容,尤其是在跨平台时路径处理的问题。 然后,我需要查找是否有现有的案例或社区资源。比如,是否有开发者成功将Qt和Raylib结合使用,或者相关的教程、示例代码。这可以帮助验证可行性提供实际操作步骤。 可能的挑战包括窗口嵌入的兼容性问题、事件循环的协调、以及潜在的渲染冲突。例如,Qt可能期望控制主事件循环,而Raylib也有自己的循环,这可能导致程序流程上的冲突,需要合理设计架构,比如将Raylib的渲染放在单独的线程中,或者修改Raylib的主循环以适应Qt的事件机制。 最后,需要总结整合的优缺点。优点是可以结合Qt的丰富GUI功能和Raylib的高效渲染,适合需要复杂界面和图形处理的应用程序缺点是整合过程可能复杂,需要处理底层细节,且可能引入额外的性能开销或维护成本。 综上所述,Qt和Raylib在技术上是可能结合的,但需要解决窗口管理、事件处理、资源协调等技术问题。适合有一定经验的开发者,愿意投入时间进行集成和调试。</think>--- ### **Qt 与 Raylib 的结合可能性** **可以结合**,但需要解决技术细节和兼容性问题。以下是关键点分析: --- ### **1. 结合场景** - **目标**:利用 Qt 的 GUI 功能(如窗口、按钮、菜单) + Raylib 的图形渲染能力(如游戏画面、3D 模型)。 - **典型用例**: - 游戏编辑器(Qt 管理界面,Raylib 渲染预览)。 - 科学可视化工具(Qt 控制参数,Raylib 绘制动态图形)。 - 混合应用(如嵌入式设备中 Qt 处理交互,Raylib 驱动显示)。 --- ### **2. 技术可行性** #### **核心挑战** - **窗口与上下文冲突**: - Qt 默认使用自己的窗口系统和 OpenGL 上下文(如 `QOpenGLWidget`)。 - Raylib 初始化时会创建独立的 OpenGL 上下文,可能与 Qt 冲突。 - **事件循环协调**: - Qt 依赖事件循环(`QApplication::exec()`)。 - Raylib 通过 `main()` 函数内的 `while (!WindowShouldClose())` 循环运行。 - **语言兼容性**: - Qt 基于 C++,Raylib 是 C 库,需正确处理 C/C++ 混合编译。 --- ### **3. 实现方案** #### **方案 1:将 Raylib 嵌入 Qt 窗口** - **步骤**: 1. 使用 Qt 的 `QWindow` 或 `QOpenGLWidget` 创建容器。 2. 在 Qt 容器中获取原生窗口句柄(如 `WinId`)。 3. 初始化 Raylib 时,指定使用该句柄作为渲染窗口。 - **代码示例**(伪代码): ```cpp // Qt 中创建 OpenGL 容器 QOpenGLWidget *glWidget = new QOpenGLWidget(parent); glWidget->show(); // 获取窗口句柄(平台相关) #ifdef Q_OS_WIN HWND hwnd = (HWND)glWidget->winId(); #endif // 配置 Raylib 使用外部窗口 SetConfigFlags(FLAG_WINDOW_HIDDEN | FLAG_WINDOW_UNDECORATED); InitWindow(800, 600, "Raylib in Qt"); SetWindowHandle(hwnd); // 需自定义扩展或修改 Raylib 源码 // 主循环中协调渲染 while (!WindowShouldClose()) { BeginDrawing(); // Raylib 绘制逻辑 EndDrawing(); QCoreApplication::processEvents(); // 处理 Qt 事件 } ``` - **注意事项**: - Raylib 默认不支持外部窗口绑定,需修改其源码或通过 `SetWindowHandle()` 扩展(需自定义实现)。 - 需确保 OpenGL 上下文共享或兼容。 #### **方案 2:分离进程通信** - **思路**: - Qt 作为主进程,管理界面。 - Raylib 作为进程(独立窗口),通过 IPC(如套接字、共享内存)传递数据。 - **优点**:避免上下文冲突,简化开发。 - **缺点**:增加进程间通信开销,不适合实时渲染。 --- ### **4. 关键问题与解决** #### **问题 1:OpenGL 上下文冲突** - **解决**: - 强制 Qt 和 Raylib 共享同一 OpenGL 上下文(需深入定制)。 - 或使用离屏渲染(如 Raylib 渲染到纹理,Qt 显示纹理)。 #### **问题 2:事件循环阻塞** - **解决**: - 在 Qt 定时器或线程中调用 Raylib 的帧更新逻辑。 ```cpp // Qt 主线程中 QTimer *timer = new QTimer(this); connect(timer, &QTimer::timeout, [] { if (!WindowShouldClose()) { BeginDrawing(); // Raylib 渲染 EndDrawing(); } }); timer->start(16); // ~60 FPS ``` #### **问题 3:输入事件传递** - **解决**: - 将 Qt 接收的鼠标/键盘事件转发给 Raylib。 ```cpp bool MyWidget::event(QEvent *event) { if (event->type() == QEvent::MouseMove) { QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); // 转换坐标调用 Raylib 的输入函数 } return QWidget::event(event); } ``` --- ### **5. 优缺点总结** | **优点** | **缺点** | |------------------------------|---------------------------------------| | 结合 Qt 的丰富 GUI 功能 | 技术实现复杂,需深入修改/扩展代码 | | 利用 Raylib 的高性能渲染 | OpenGL 上下文管理容易冲突 | | 适合复杂交互+图形应用 | 事件循环和线程协调可能引入稳定性风险 | --- ### **6. 推荐实践** - **初级建议**:优先使用单一框架(如纯 Qt + OpenGL 或纯 Raylib)。 - **高级场景**: - 修改 Raylib 源码,支持外部窗口句柄绑定。 - 使用 `QOpenGLWidget` 共享上下文,参考 [raylib-Qt 示例](https://github.com/user/repo)。 - **替代方案**:若需 GUI + 渲染,考虑其他库(如 Unity、Godot 或 Qt 3D 模块)。 --- ### **结论** Qt 和 Raylib **可以结合**,但需解决窗口管理、事件循环和上下文冲突问题。适合需要复杂 GUI 和高性能渲染的特定场景,建议在明确需求后评估开发成本。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值