赞
踩
上一篇文章,存在失去焦点问题,分析可能原因是直接将子进程的窗口句柄封装到QWindow对象中之后,窗口的键盘事件可能就qt自己处理,但是目前没有搞清楚怎么处理的.
下面这种方式也类似第一种方式,不同点在于处理窗口句柄的方式.
通过自定义一个QWindow的一个子类,在子类中通过window平台api将子进程窗口的句柄与子类对象形成父子关系.然后在将子类封装为QWidget供qt主进程的其他控件使用.这种方式的优点是不存在失去焦点问题.但是要处理win7下的其他问题.
笔者在win7下出现的问题:
1.当子进程非全屏模式时,当通过QProcess启动这个子进程窗口时,出现卡住的问题,并且不会显示该窗口. 只有将子进程的设置为 showFullScreen()后,就能正常启动了.分析可能原因时,window平台api设置窗口为无边框及工具窗口对于qt窗口无效,只能通过子进程内部设置好.
2.当主进程窗口是showFullScreen()状态时,子进程存在QDailog窗口,或者一些其他控件的操作时,会出现window桌面任务栏弹出的现象.win10下正常. 笔者通过判断当前操作系统版本,然后通过将任务栏的自动隐藏功能开启后,可通软件层面技术性解决该问题.将任务栏自动隐藏功能开启后,及时存在弹出现象,也因为隐藏后,不会显示. 当软件退出时,再取消该功能.
代码1: 自定义一个QWindow子类
- #include <windows.h>
- #include <QWindow>
-
-
- //创建子进程用的QWindow子类
- class ChildWindowWrapper : public QWindow {
- public:
- /// <summary>
- /// 构造一个Qwindow子类对象
- /// </summary>
- /// <param name="hwnd">子进程创建句柄</param>
- /// <param name="parent">Qwindow对象的父对象</param>
- ChildWindowWrapper(HWND hwnd, QWindow* parent = nullptr)
- : QWindow(parent), m_hwnd(hwnd) {
- embedChildWindow();
- }
- ~ChildWindowWrapper()
- {
- if (m_hwnd) {
- SetParent(m_hwnd, NULL);
- }
- }
-
- void embedChildWindow() {
- // 修改子窗口样式,去掉标题栏和边框 win7下,qt窗口好像无效了,所以通过子进程内部将窗口设置为全屏
- LONG style = GetWindowLong(m_hwnd, GWL_STYLE);
- style &= ~(WS_CAPTION | WS_THICKFRAME);
- style|= WS_EX_TOOLWINDOW;
- SetWindowLong(m_hwnd, GWL_STYLE, style);
- //关键点,通过window api 将当前QWindow对象设置为子进程窗口的父对象窗口
- SetParent(m_hwnd, (HWND)winId());
- //这个也很重要,将子进程窗口设置为无边框及标题栏的窗口 ,在win7下才不会弹出底下的状态栏.,win10没有这个也正常
- //SWP_FRAMECHANGED刷新一次上述更改的状态.SWP_NOZORDER保存窗口为层级不变
- SetWindowPos(m_hwnd, nullptr, 0, 0, width(), height(), SWP_NOACTIVATE | SWP_FRAMECHANGED);
- // 显示子进程窗口
- //ShowWindow(m_hwnd, SW_SHOW);
- //SetForegroundWindow(m_hwnd);
- //SetFocus(m_hwnd);
- }
-
- protected:
- bool event(QEvent* event) override {
- if (event->type() == QEvent::Resize) {
- if (m_hwnd) {
- //SetWindowPos(m_hwnd, nullptr, 0, 0, width(), height(), SWP_NOZORDER | SWP_NOACTIVATE);
- SetWindowPos(m_hwnd, nullptr, 0, 0, width(), height(), SWP_NOACTIVATE);
- }
- }
- return QWindow::event(event);
- }
-
- private:
- //子进程窗口的句柄
- HWND m_hwnd;
- };
- //头文件中定义子类对象指针
- ChildWindowWrapper* m_ChildVMWin{ nullptr };
具体代码实现
- //window 底层操作,隐藏window桌面的任务栏功能,在win7下
-
- /// <summary>
- /// 获取window版本
- /// </summary>
- /// <returns>0为win7,1为win10,其他为-1</returns>
- int CncOpWindows::GetWindowsVerson()
- {
- int iType{ 0 };
- QString osName = QSysInfo::productType();
- //qDebug() << "Operating System:" << osName;
-
- if (osName == "windows")
- {
- if (QSysInfo::windowsVersion() == QSysInfo::WV_WINDOWS7)
- {
- //qDebug() << "Windows 7";
- iType = 0;
- }
- else if (QSysInfo::windowsVersion() == QSysInfo::WV_WINDOWS10)
- {
- //qDebug() << "Windows 10";
- iType = 1;
- }
- else
- {
- //其他windows系统
- iType = 2;
- }
- }
- else {
- //qDebug() << "Other OS";
- iType = -1;
- }
- return iType;
- }
-
-
- void CncOpWindows::FindWindowsTaskBarHandle()
- {
- //windows任务栏句柄
- hwndWindowsTaskBar = FindWindow("Shell_TrayWnd", NULL);
- }
-
-
- void CncOpWindows::HideWindowsTaskBar()
- {
- if(hwndWindowsTaskBar)
- SetAutoHideWindowsTaskbar(true);
-
- }
- void CncOpWindows::ShowWindowsTaskBar()
- {
- if (hwndWindowsTaskBar)
- SetAutoHideWindowsTaskbar(false);
- }
-
- void CncOpWindows::SetAutoHideWindowsTaskbar(bool enable)
- {
- //开启/关闭任务栏自动隐藏功能
- APPBARDATA appBarData = { 0 };
- appBarData.cbSize = sizeof(APPBARDATA);
- appBarData.hWnd = hwndWindowsTaskBar;
- if (enable) {
- appBarData.lParam = ABS_AUTOHIDE ;
- }
- else {
- appBarData.lParam = 0;
- }
- SHAppBarMessage(ABM_SETSTATE, &appBarData);
- }
-
-
- void CncOpWindows::CreateShareMem()
- {
- //创建共享内存,与子进程通信用, 通过变量控制子进程的退出与显示
- m_pShareMemObj = new qcShareMemory(nullptr);
- m_pThreadShareMem = new QThread(this);
- m_pThreadShareMem->setObjectName(tr("ShareMenThread"));
- m_pShareMemObj->moveToThread(m_pThreadShareMem);
- connect(m_pThreadShareMem, &QThread::started, m_pShareMemObj, &qcShareMemory::slotInit);
- connect(m_pThreadShareMem, &QThread::finished, m_pShareMemObj, &qcShareMemory::slotFinish);
- connect(this, &CncOpWindows::signalReadWriteShareMem, m_pShareMemObj, &qcShareMemory::slotReadWriteShareMem);
- connect(m_pShareMemObj, &qcShareMemory::signalShowLastWnd, this, &CncOpWindows::slotShowLastWnd);
-
- m_pThreadShareMem->start();
- m_pShareMemObj->m_bStart = true;
- emit signalReadWriteShareMem();
- }
-
- bool CncOpWindows::LoadVisionMeasureApp()
- {
- QString cmd= QCoreApplication::applicationDirPath();
- int iCamAppType = 0;
- switch (iCamAppType)
- {
- case 0:
- cmd += "/ImageGrab.exe";//子程序执行文件地址
- break;
- case 5:
- cmd += "/MeasureVM.exe";//子程序执行文件地址
- break;
- }
- QStringList argList;
- argList << QString::number(ui->stackedWidget_sub->winId());//把父窗口的id给子进程传递过去
-
- m_pProcessVM = new QProcess(this);//使用进程运行子进程窗口
- connect(m_pProcessVM, &QProcess::readyReadStandardError, this, &CncOpWindows::slotCreateWaitingVM);//等待子进程窗口把自身的winId传递过来
- connect(m_pProcessVM, qOverload<int, QProcess::ExitStatus>(&QProcess::finished),
- this, qOverload<int , QProcess::ExitStatus>(&CncOpWindows::slotFinishedProcessVM));
- //connect(m_pProcessVM, &QProcess::readyRead, this, &CncOpWindows::slotReadProcessVM);
-
- m_pProcessVM->start(cmd, argList);
-
- return m_pProcessVM->waitForStarted(2000);
- }
-
- void CncOpWindows::slotCreateWaitingVM()
- {
- quint64 winId = m_pProcessVM->readAllStandardError().toLongLong();
- m_ChildVMWin = new ChildWindowWrapper((HWND)winId, ui->stackedWidget_sub->windowHandle());
- //m_ChildVMWin = QWindow::fromWinId(winId);
- if (m_ChildVMWin)
- {
- //m_ChildVMWin->setParent(ui->stackedWidget_sub->windowHandle());
- m_WidgetVMProcess = QWidget::createWindowContainer(m_ChildVMWin);//获取一个子进程窗口的widget
- // 调整窗口大小以适应控件大小
- ui->stackedWidget_sub->addWidget(m_WidgetVMProcess);
-
- //这里是可以使用布局器管理子进程窗口的,不管理的话就在坐标0,0处
- }
-
- }
-
- void CncOpWindows::slotFinishedProcessVM(int exitCode, QProcess::ExitStatus exitStatus)
- {
- qInfo() << "ImageGrab.exe quit"<<"[exitCode="<< exitCode << "ExitStatus=" << exitStatus << "]";
- //if (exitStatus== QProcess::NormalExit)
- //{
- // //正常退出
- //}
- //else
- //{
- // //非正常退出
- //}
-
- }
-
- void CncOpWindows::CloseVisionMeasureApp()
- {
- //关闭当前视觉测量进程
- if (m_pProcessVM)
- {
- //
- //关键点,必须将嵌入的QWindow设置为没有父对象,在调用退出指令就正常了
- /* if (m_ChildVMWin)
- {
- m_ChildVMWin->setParent(nullptr);
- }*/
-
- //正常退出程序terminate 发送一个close消息到顶层窗口.
- //m_pProcessVM->terminate();
- //结束app信号 共享内存与子进程通信
- if (PointGlobalParams()->m_pDataApp)
- {
- PointGlobalParams()->m_pDataApp->bC2V[1] = true;
- }
- //等待结束不能省,
- bool bFinish=m_pProcessVM->waitForFinished(5000);
- if (!bFinish)
- {
- //非正常退出
- qInfo() << "ImageGrab.exe crash quit";
- }
- }
-
- }
子进程实现
- //mian函数中的实现,只需要传递子进程窗口的winid,也即window下的窗口句柄
- if (argc >1)
- {
- //关键代码,触发错误之后,主进程能够响应
- fprintf(stderr, "%lld", (quint64)w.winId());//写入标准错误输出,stderr能立即输出,stdout则不行
- w.hide();
- }
- else
- {
- w.show();
- }
- //定义一个定时器,时刻监控共享内存的状态,来执行下面这两个函数
- //显示当前app
- void ImageGrab::slotShowApp()
- {
- //将当前窗口处于激活状态
- m_pGlobalPa->m_pDataApp->bV2C[0] = true;
- if (this->isHidden())
- {
- this->show();
- this->activateWindow();
- }
- }
-
- void ImageGrab::slotCloseApp()
- {
- //将当前app关闭
- this->close();
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。