当前位置:   article > 正文

将qt的子程序窗口嵌入qt的主进程主窗口中(第二种方式)

将qt的子程序窗口嵌入qt的主进程主窗口中(第二种方式)

上一篇文章,存在失去焦点问题,分析可能原因是直接将子进程的窗口句柄封装到QWindow对象中之后,窗口的键盘事件可能就qt自己处理,但是目前没有搞清楚怎么处理的.

下面这种方式也类似第一种方式,不同点在于处理窗口句柄的方式.

通过自定义一个QWindow的一个子类,在子类中通过window平台api将子进程窗口的句柄与子类对象形成父子关系.然后在将子类封装为QWidget供qt主进程的其他控件使用.这种方式的优点是不存在失去焦点问题.但是要处理win7下的其他问题.

笔者在win7下出现的问题:

1.当子进程非全屏模式时,当通过QProcess启动这个子进程窗口时,出现卡住的问题,并且不会显示该窗口. 只有将子进程的设置为 showFullScreen()后,就能正常启动了.分析可能原因时,window平台api设置窗口为无边框及工具窗口对于qt窗口无效,只能通过子进程内部设置好.

2.当主进程窗口是showFullScreen()状态时,子进程存在QDailog窗口,或者一些其他控件的操作时,会出现window桌面任务栏弹出的现象.win10下正常. 笔者通过判断当前操作系统版本,然后通过将任务栏的自动隐藏功能开启后,可通软件层面技术性解决该问题.将任务栏自动隐藏功能开启后,及时存在弹出现象,也因为隐藏后,不会显示. 当软件退出时,再取消该功能.

代码1: 自定义一个QWindow子类

  1. #include <windows.h>
  2. #include <QWindow>
  3. //创建子进程用的QWindow子类
  4. class ChildWindowWrapper : public QWindow {
  5. public:
  6. /// <summary>
  7. /// 构造一个Qwindow子类对象
  8. /// </summary>
  9. /// <param name="hwnd">子进程创建句柄</param>
  10. /// <param name="parent">Qwindow对象的父对象</param>
  11. ChildWindowWrapper(HWND hwnd, QWindow* parent = nullptr)
  12. : QWindow(parent), m_hwnd(hwnd) {
  13. embedChildWindow();
  14. }
  15. ~ChildWindowWrapper()
  16. {
  17. if (m_hwnd) {
  18. SetParent(m_hwnd, NULL);
  19. }
  20. }
  21. void embedChildWindow() {
  22. // 修改子窗口样式,去掉标题栏和边框 win7下,qt窗口好像无效了,所以通过子进程内部将窗口设置为全屏
  23. LONG style = GetWindowLong(m_hwnd, GWL_STYLE);
  24. style &= ~(WS_CAPTION | WS_THICKFRAME);
  25. style|= WS_EX_TOOLWINDOW;
  26. SetWindowLong(m_hwnd, GWL_STYLE, style);
  27. //关键点,通过window api 将当前QWindow对象设置为子进程窗口的父对象窗口
  28. SetParent(m_hwnd, (HWND)winId());
  29. //这个也很重要,将子进程窗口设置为无边框及标题栏的窗口 ,在win7下才不会弹出底下的状态栏.,win10没有这个也正常
  30. //SWP_FRAMECHANGED刷新一次上述更改的状态.SWP_NOZORDER保存窗口为层级不变
  31. SetWindowPos(m_hwnd, nullptr, 0, 0, width(), height(), SWP_NOACTIVATE | SWP_FRAMECHANGED);
  32. // 显示子进程窗口
  33. //ShowWindow(m_hwnd, SW_SHOW);
  34. //SetForegroundWindow(m_hwnd);
  35. //SetFocus(m_hwnd);
  36. }
  37. protected:
  38. bool event(QEvent* event) override {
  39. if (event->type() == QEvent::Resize) {
  40. if (m_hwnd) {
  41. //SetWindowPos(m_hwnd, nullptr, 0, 0, width(), height(), SWP_NOZORDER | SWP_NOACTIVATE);
  42. SetWindowPos(m_hwnd, nullptr, 0, 0, width(), height(), SWP_NOACTIVATE);
  43. }
  44. }
  45. return QWindow::event(event);
  46. }
  47. private:
  48. //子进程窗口的句柄
  49. HWND m_hwnd;
  50. };
  1. //头文件中定义子类对象指针
  2. ChildWindowWrapper* m_ChildVMWin{ nullptr };

 具体代码实现

  1. //window 底层操作,隐藏window桌面的任务栏功能,在win7下
  2. /// <summary>
  3. /// 获取window版本
  4. /// </summary>
  5. /// <returns>0为win7,1为win10,其他为-1</returns>
  6. int CncOpWindows::GetWindowsVerson()
  7. {
  8. int iType{ 0 };
  9. QString osName = QSysInfo::productType();
  10. //qDebug() << "Operating System:" << osName;
  11. if (osName == "windows")
  12. {
  13. if (QSysInfo::windowsVersion() == QSysInfo::WV_WINDOWS7)
  14. {
  15. //qDebug() << "Windows 7";
  16. iType = 0;
  17. }
  18. else if (QSysInfo::windowsVersion() == QSysInfo::WV_WINDOWS10)
  19. {
  20. //qDebug() << "Windows 10";
  21. iType = 1;
  22. }
  23. else
  24. {
  25. //其他windows系统
  26. iType = 2;
  27. }
  28. }
  29. else {
  30. //qDebug() << "Other OS";
  31. iType = -1;
  32. }
  33. return iType;
  34. }
  35. void CncOpWindows::FindWindowsTaskBarHandle()
  36. {
  37. //windows任务栏句柄
  38. hwndWindowsTaskBar = FindWindow("Shell_TrayWnd", NULL);
  39. }
  40. void CncOpWindows::HideWindowsTaskBar()
  41. {
  42. if(hwndWindowsTaskBar)
  43. SetAutoHideWindowsTaskbar(true);
  44. }
  45. void CncOpWindows::ShowWindowsTaskBar()
  46. {
  47. if (hwndWindowsTaskBar)
  48. SetAutoHideWindowsTaskbar(false);
  49. }
  50. void CncOpWindows::SetAutoHideWindowsTaskbar(bool enable)
  51. {
  52. //开启/关闭任务栏自动隐藏功能
  53. APPBARDATA appBarData = { 0 };
  54. appBarData.cbSize = sizeof(APPBARDATA);
  55. appBarData.hWnd = hwndWindowsTaskBar;
  56. if (enable) {
  57. appBarData.lParam = ABS_AUTOHIDE ;
  58. }
  59. else {
  60. appBarData.lParam = 0;
  61. }
  62. SHAppBarMessage(ABM_SETSTATE, &appBarData);
  63. }
  64. void CncOpWindows::CreateShareMem()
  65. {
  66. //创建共享内存,与子进程通信用, 通过变量控制子进程的退出与显示
  67. m_pShareMemObj = new qcShareMemory(nullptr);
  68. m_pThreadShareMem = new QThread(this);
  69. m_pThreadShareMem->setObjectName(tr("ShareMenThread"));
  70. m_pShareMemObj->moveToThread(m_pThreadShareMem);
  71. connect(m_pThreadShareMem, &QThread::started, m_pShareMemObj, &qcShareMemory::slotInit);
  72. connect(m_pThreadShareMem, &QThread::finished, m_pShareMemObj, &qcShareMemory::slotFinish);
  73. connect(this, &CncOpWindows::signalReadWriteShareMem, m_pShareMemObj, &qcShareMemory::slotReadWriteShareMem);
  74. connect(m_pShareMemObj, &qcShareMemory::signalShowLastWnd, this, &CncOpWindows::slotShowLastWnd);
  75. m_pThreadShareMem->start();
  76. m_pShareMemObj->m_bStart = true;
  77. emit signalReadWriteShareMem();
  78. }
  79. bool CncOpWindows::LoadVisionMeasureApp()
  80. {
  81. QString cmd= QCoreApplication::applicationDirPath();
  82. int iCamAppType = 0;
  83. switch (iCamAppType)
  84. {
  85. case 0:
  86. cmd += "/ImageGrab.exe";//子程序执行文件地址
  87. break;
  88. case 5:
  89. cmd += "/MeasureVM.exe";//子程序执行文件地址
  90. break;
  91. }
  92. QStringList argList;
  93. argList << QString::number(ui->stackedWidget_sub->winId());//把父窗口的id给子进程传递过去
  94. m_pProcessVM = new QProcess(this);//使用进程运行子进程窗口
  95. connect(m_pProcessVM, &QProcess::readyReadStandardError, this, &CncOpWindows::slotCreateWaitingVM);//等待子进程窗口把自身的winId传递过来
  96. connect(m_pProcessVM, qOverload<int, QProcess::ExitStatus>(&QProcess::finished),
  97. this, qOverload<int , QProcess::ExitStatus>(&CncOpWindows::slotFinishedProcessVM));
  98. //connect(m_pProcessVM, &QProcess::readyRead, this, &CncOpWindows::slotReadProcessVM);
  99. m_pProcessVM->start(cmd, argList);
  100. return m_pProcessVM->waitForStarted(2000);
  101. }
  102. void CncOpWindows::slotCreateWaitingVM()
  103. {
  104. quint64 winId = m_pProcessVM->readAllStandardError().toLongLong();
  105. m_ChildVMWin = new ChildWindowWrapper((HWND)winId, ui->stackedWidget_sub->windowHandle());
  106. //m_ChildVMWin = QWindow::fromWinId(winId);
  107. if (m_ChildVMWin)
  108. {
  109. //m_ChildVMWin->setParent(ui->stackedWidget_sub->windowHandle());
  110. m_WidgetVMProcess = QWidget::createWindowContainer(m_ChildVMWin);//获取一个子进程窗口的widget
  111. // 调整窗口大小以适应控件大小
  112. ui->stackedWidget_sub->addWidget(m_WidgetVMProcess);
  113. //这里是可以使用布局器管理子进程窗口的,不管理的话就在坐标0,0处
  114. }
  115. }
  116. void CncOpWindows::slotFinishedProcessVM(int exitCode, QProcess::ExitStatus exitStatus)
  117. {
  118. qInfo() << "ImageGrab.exe quit"<<"[exitCode="<< exitCode << "ExitStatus=" << exitStatus << "]";
  119. //if (exitStatus== QProcess::NormalExit)
  120. //{
  121. // //正常退出
  122. //}
  123. //else
  124. //{
  125. // //非正常退出
  126. //}
  127. }
  128. void CncOpWindows::CloseVisionMeasureApp()
  129. {
  130. //关闭当前视觉测量进程
  131. if (m_pProcessVM)
  132. {
  133. //
  134. //关键点,必须将嵌入的QWindow设置为没有父对象,在调用退出指令就正常了
  135. /* if (m_ChildVMWin)
  136. {
  137. m_ChildVMWin->setParent(nullptr);
  138. }*/
  139. //正常退出程序terminate 发送一个close消息到顶层窗口.
  140. //m_pProcessVM->terminate();
  141. //结束app信号 共享内存与子进程通信
  142. if (PointGlobalParams()->m_pDataApp)
  143. {
  144. PointGlobalParams()->m_pDataApp->bC2V[1] = true;
  145. }
  146. //等待结束不能省,
  147. bool bFinish=m_pProcessVM->waitForFinished(5000);
  148. if (!bFinish)
  149. {
  150. //非正常退出
  151. qInfo() << "ImageGrab.exe crash quit";
  152. }
  153. }
  154. }

子进程实现

  1. //mian函数中的实现,只需要传递子进程窗口的winid,也即window下的窗口句柄
  2. if (argc >1)
  3. {
  4. //关键代码,触发错误之后,主进程能够响应
  5. fprintf(stderr, "%lld", (quint64)w.winId());//写入标准错误输出,stderr能立即输出,stdout则不行
  6. w.hide();
  7. }
  8. else
  9. {
  10. w.show();
  11. }
  1. //定义一个定时器,时刻监控共享内存的状态,来执行下面这两个函数
  2. //显示当前app
  3. void ImageGrab::slotShowApp()
  4. {
  5. //将当前窗口处于激活状态
  6. m_pGlobalPa->m_pDataApp->bV2C[0] = true;
  7. if (this->isHidden())
  8. {
  9. this->show();
  10. this->activateWindow();
  11. }
  12. }
  13. void ImageGrab::slotCloseApp()
  14. {
  15. //将当前app关闭
  16. this->close();
  17. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/730588
推荐阅读
相关标签
  

闽ICP备14008679号