将ue4程序嵌入qt界面显示

Posted Leslie X徐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将ue4程序嵌入qt界面显示相关的知识,希望对你有一定的参考价值。

windows窗口编程

需求:将ue4程序嵌入qt界面显示
思路:通过使用 windowsAPI 对ue4窗口进行设置跟随qt界面以及活动窗口时的位置层序设置
结果:

1.打开程序获取句柄 设置样式

函数:

  1. 获取窗口句柄:HWND FindWindow(L"class name",L"window title") 数据可通过“句柄精灵”软件获取
  2. 设置窗口样式SetWindowLong(HWND, GWL_STYLE, LONG dwNewLong)
  3. 获取窗口样式:GetWindowLong(HWND, GWL_STYLE)
  4. 窗口样式宏
void Unreal4::on_pushButton_clicked()

    QString unreal4Path"D:/lesliex/QTpro/QWidgetUnreal4/Windows/UEMetaFactory.exe";
    QStringList arguments;
    arguments << "-WINDOWED";
    _process=new QProcess;
    _process->start(unreal4Path,arguments);

    QtConcurrent::run([this]
        while(true)
            _hwnWindow=FindWindow(L"UnrealWindow",L"UEMetaFactory  ");
            SetWindowLong(_hwnWindow, GWL_STYLE, GetWindowLong(_hwnWindow, GWL_STYLE) & (~WS_OVERLAPPEDWINDOW));//使用&~去除某种样式
            if(_hwnWindow != NULL)
                qDebug()<<("get SeerSupports");
                emit sigUe4Complete();
                break;
            
        
    );

2.等待显示 移动位置

此处不使用 createWindowContainer,对ue4有鼠标键盘交互问题
函数:

  1. 移动窗口
BOOL MoveWindow(
  [in] HWND hWnd,
  [in] int  X,
  [in] int  Y,
  [in] int  nWidth,
  [in] int  nHeight,
  [in] BOOL bRepaint
);

等待到窗口出现才能获取句柄

connect(this,&Unreal4::sigUe4Complete,this,&Unreal4::slotUe4Complete);
void Unreal4::slotUe4Complete()

//createWindowContainer方式不好
    //    _window=QWindow::fromWinId((WId)_hwnWindow);
    //    _windowWidget = QWidget::createWindowContainer(_window);

    _windowWidget = ui->widget_2;
    MoveWindow(_hwnWindow,mapToGlobal(_windowWidget->pos()).x(),mapToGlobal(_windowWidget->pos()).y(),_windowWidget->width(),_windowWidget->height(),false);

3.定时器定时显示窗口到最上层

函数:

  1. 设置窗口位置
BOOL SetWindowPos(
  [in]           HWND hWnd,
  [in, optional] HWND hWndInsertAfter,
  [in]           int  X,
  [in]           int  Y,
  [in]           int  cx,
  [in]           int  cy,
  [in]           UINT uFlags
);

hWnd移动到hWndInsertAfter下层,并设置位置和大小,显示方式。

  1. 获取窗口
HWND GetWindow(
  [in] HWND hWnd,
  [in] UINT uCmd
);

要获取已知窗口上层的窗口句柄可用 GetWindow( (HWND)this->winId() ,GW_HWNDPREV )

当主要窗口和ue程序为活动窗口时,将hWndInsertAfter设置为HWND_TOPMOSTuFlags设置为SWP_NOACTIVATE 只显示不激活
当主要窗口不为活动窗口时,将hWndInsertAfter设置为 GetWindow( (HWND)this->winId() ,GW_HWNDPREV )uFlags设置为SWP_NOACTIVATE 只显示不激活

Unreal4::Unreal4(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Unreal4)

    ui->setupUi(this);

    _timer = new QTimer(this);
    _timer->start(10);
    connect(_timer,&QTimer::timeout,this,&Unreal4::timerShowUe4);



void Unreal4::timerShowUe4()

    if(_windowWidget)
        if(GetForegroundWindow()==_hwnWindow||this->isActiveWindow())
            qDebug()<<"isActive";
            SetWindowPos(_hwnWindow, HWND_TOPMOST, mapToGlobal(_windowWidget->pos()).x(),mapToGlobal(_windowWidget->pos()).y(),\\
                         _windowWidget->width(),_windowWidget->height(),SWP_NOACTIVATE);
        
        else
            qDebug()<<"NotActive";
            SetWindowPos(_hwnWindow, GetWindow((HWND)this->winId(),GW_HWNDPREV), mapToGlobal(_windowWidget->pos()).x(),mapToGlobal(_windowWidget->pos()).y(),\\
                         _windowWidget->width(),_windowWidget->height(),SWP_NOACTIVATE);
        
    

4.重写QWidget事件

函数:

  1. 设置窗口显示ShowWindow(HWND, int nCmdShow)
    设置nCmdShow:显示不激活为SW_SHOWNOACTIVATE,隐藏为SW_HIDE
void Unreal4::showEvent(QShowEvent *event)

    if(_process) ShowWindow(_hwnWindow,SW_SHOWNOACTIVATE);



void Unreal4::resizeEvent(QResizeEvent *event)

    if(_windowWidget)
        MoveWindow(_hwnWindow,mapToGlobal(_windowWidget->pos()).x(),mapToGlobal(_windowWidget->pos()).y(),_windowWidget->width(),_windowWidget->height(),false);



void Unreal4::hideEvent(QHideEvent *event)

    if(_process) ShowWindow(_hwnWindow,SW_HIDE);


5.源码

pro文件中加入:
LIBS += -luser32

头文件:

#ifndef UNREAL4_H
#define UNREAL4_H

#include "mwidget.h"
#include <QProcess>
#include "windows.h"
#include <QTimer>

QT_BEGIN_NAMESPACE
namespace Ui  class Unreal4; 
QT_END_NAMESPACE

/// \\brief The Unreal4 class
/// \\details 将UE4界面嵌入QT界面

class Unreal4 : public QWidget

    Q_OBJECT

public:
    Unreal4(QWidget *parent = nullptr);
    ~Unreal4();

    void closeUe4();


private slots:
    void slotUe4Complete();
    void on_pushButton_clicked();
    void on_pushButton_2_clicked();
    void on_pushButton_3_clicked();
    void on_pushButton_4_clicked();

signals:
    void sigUe4Complete();
private:
    Ui::Unreal4 *ui;
    QProcess *_processQ_NULLPTR;
    HWND _hwnWindowQ_NULLPTR;
    QWidget *_windowWidgetQ_NULLPTR;
    QWindow * _windowQ_NULLPTR;
    QTimer* _timerQ_NULLPTR;

    // QWidget interface
protected:
    void timerShowUe4();
    void showEvent(QShowEvent *event) override;
    void resizeEvent(QResizeEvent *event) override;
    void hideEvent(QHideEvent *event) override;
;
#endif // UNREAL4_H

源文件:

#include "Unreal4.h"
#include "ui_Unreal4.h"

#include <QWindow>
#include <QDebug>
#include <QPalette>

#include <QtConcurrent>
#include <QMouseEvent>
#include <QPainter>

Unreal4::Unreal4(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Unreal4)

    ui->setupUi(this);

    connect(this,&Unreal4::sigUe4Complete,this,&Unreal4::slotUe4Complete);
    _timer = new QTimer(this);
    _timer->start(10);
    connect(_timer,&QTimer::timeout,this,&Unreal4::timerShowUe4);




Unreal4::~Unreal4()

    closeUe4();
    delete ui;


void Unreal4::closeUe4()

    if(!_process) return;
    if(_process->state()==QProcess::Running)
       _process->kill();
       QString exe = "UEMetaFactory-Win64-Shipping.exe";
       _process->execute("taskkill",QStringList()<<"-im"<<exe<<"-f");
       _process->waitForFinished(5000);
       delete _process; _process = Q_NULLPTR;
       ui->verticalLayout->removeWidget(_windowWidget); delete _windowWidget;
    


void Unreal4::slotUe4Complete()

    _windowWidget = ui->widget_2;
    MoveWindow(_hwnWindow,mapToGlobal(_windowWidget->pos()).x(),mapToGlobal(_windowWidget->pos()).y(),_windowWidget->width(),_windowWidget->height(),false);


void Unreal4::on_pushButton_clicked()

    QString unreal4Path"D:/lesliex/QTpro/QWidgetUnreal4/Windows/UEMetaFactory.exe";
    QStringList arguments;
    arguments << "-WINDOWED";
    _process=new QProcess;
    _process->start(unreal4Path,arguments);

    QtConcurrent::run([this]
        while(true)
            _hwnWindow=FindWindow(L"UnrealWindow",L"UEMetaFactory  ");
            SetWindowLong(_hwnWindow, GWL_STYLE, GetWindowLong(_hwnWindow, GWL_STYLE) & (~WS_OVERLAPPEDWINDOW));
            if(_hwnWindow != NULL)
                qDebug()<<("get SeerSupports");
                emit sigUe4Complete();
                break;
            
        
    );


//==================================show ue4===============================
void Unreal4::timerShowUe4()

    if(_windowWidget)
        if(GetForegroundWindow()==_hwnWindow||this->isActiveWindow())
            qDebug()<<"isActive";
            SetWindowPos(_hwnWindow, HWND_TOPMOST, mapToGlobal(_windowWidget->pos()).x(),mapToGlobal(_windowWidget->pos()).y(),\\
                         _windowWidget->width(),_windowWidget->height(),SWP_NOACTIVATE);
        
        else
            qDebug()<<"NotActive";
            SetWindowPos(_hwnWindow, GetWindow((HWND)this->winId(),GW_HWNDPREV), mapToGlobal(_windowWidget->pos()).x(),mapToGlobal(_windowWidget->pos()).y(),\\
                         _windowWidget->width(),_windowWidget->height(),SWP_NOACTIVATE);
        
    


void Unreal4::showEvent(QShowEvent *event)

    if(_process) ShowWindow(_hwnWindow,SW_SHOWNOACTIVATE);



void Unreal4::resizeEvent(QResizeEvent *event)

    if(_windowWidget)
        MoveWindow(_hwnWindow,mapToGlobal(_windowWidget->pos()).x(),mapToGlobal(_windowWidget->pos()).y(),_windowWidget->width(),_windowWidget->height(),false);



void Unreal4::hideEvent(QHideEvent *event)

    if(_process) ShowWindow(_hwnWindow,SW_HIDE);


//=====================button==========================
void Unreal4::on_pushButton_3_clicked()

    _timer->start(10);
    if(_process) ShowWindow(_hwnWindow,SW_SHOWNOACTIVATE);


void Unreal4::on_pushButton_2_clicked()

    this->close();


void Unreal4::on_pushButton_4_clicked()

    _timer->stop();
    if(_process) ShowWindow(_hwnWindow,SW_HIDE);



以上是关于将ue4程序嵌入qt界面显示的主要内容,如果未能解决你的问题,请参考以下文章

linux下framebuffer显示图形的基本思想是啥

对《将Unreal4打包后的工程嵌入到Qt或者桌面中》一文的补充

Qt界面中嵌入其他exe程序的界面,使用Qt5

外部进程嵌入到Qt进程界面(使用QWindow::fromWinId)

Qt ui界面调用问题

几个ui显示在一个窗口里