当前位置: 首页 > wzjs >正文

深圳建网站兴田德润专业网络推广外包联系方式

深圳建网站兴田德润专业,网络推广外包联系方式,高平网站建设,谈谈网站建设创新问题Qt中10倍提升动态截屏及渲染60帧/秒 理解模态窗口和非模态窗口 在C中,窗口的**模态(Modal)和非模态(Modeless)**显示是两种不同的对话框或窗口行为模式,主要区别体现在用户交互和程序流程控制上。以下是它…

Qt中10倍提升动态截屏及渲染60帧/秒

  1. 理解模态窗口和非模态窗口
    在C++中,窗口的**模态(Modal)和非模态(Modeless)**显示是两种不同的对话框或窗口行为模式,主要区别体现在用户交互和程序流程控制上。以下是它们的核心区别:
    1. 模态窗口(Modal)
      阻塞父窗口:
      模态窗口会阻止用户与父窗口(或其他程序窗口)交互,直到该模态窗口关闭。例如,文件保存对话框通常是模态的。

同步执行:
代码会暂停在打开模态窗口的位置,等待窗口关闭后才继续执行后续逻辑。

常见用途:
必须用户响应的关键操作(如确认对话框、文件选择框等)。

实现方式:

  1. Win32 API:DialogBox() 或 MessageBox()。
  2. MFC:CDialog::DoModal()。
  3. Qt:QDialog::exec()。
// Win32 模态对话框示例
DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), hParentWnd, DialogProc);// MFC 模态对话框
CMyDialog dlg;
dlg.DoModal(); // 阻塞在此,直到对话框关闭
  1. 非模态窗口(Modeless)
    非阻塞父窗口:
    非模态窗口允许用户同时与父窗口和其他窗口交互,例如工具栏或查找替换对话框。

异步执行:
窗口打开后代码继续执行,不等待窗口关闭。

常见用途:
需要持续交互的辅助窗口(如工具面板、实时预览窗口等)。

实现方式:

  1. Win32 API:CreateDialog() + 消息循环处理。

  2. MFC:CDialog::Create() + ShowWindow()。

  3. Qt:QDialog::show()。

// Win32 非模态对话框示例
HWND hDlg = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), hParentWnd, DialogProc);
ShowWindow(hDlg, SW_SHOW);// MFC 非模态对话框
CMyDialog* pDlg = new CMyDialog();
pDlg->Create(IDD_DIALOG1, this);
pDlg->ShowWindow(SW_SHOW);

在这里插入图片描述

  1. 动态截屏为什么不能直接使用grabWindow

WId targetWid = reinterpret_cast(hwnd);
QPixmap windowPixmap = screen->grabWindow(targetWid); 通个该方法获取程序界面 但是单击程序子对象 会弹出非模态窗口显示的界面 无法被截取到.

  1. 合成截屏方案【低效】
    解决方案:捕获所有子窗口并合成图像
  2. 获取目标窗口及其所有子窗口
    使用Windows API遍历目标窗口的所有子窗口(包括非模态弹窗):
#include <windows.h>
#include <vector>// 回调函数枚举所有子窗口
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam) {std::vector<HWND>* handles = reinterpret_cast<std::vector<HWND>*>(lParam);if (IsWindowVisible(hwnd)) { // 仅处理可见窗口handles->push_back(hwnd);}return TRUE;
}std::vector<HWND> getAllChildWindows(HWND parent) {std::vector<HWND> children;EnumChildWindows(parent, EnumChildProc, reinterpret_cast<LPARAM>(&children));return children;
}
  1. 截取每个窗口的内容
    对主窗口和每个子窗口分别截图,并记录其屏幕位置:
#include <QScreen>
#include <QGuiApplication>
#include <QWindow>QPixmap captureWindowWithChildren(WId targetWid) {QScreen* screen = QGuiApplication::primaryScreen();HWND hwnd = reinterpret_cast<HWND>(targetWid);// 获取主窗口截图QPixmap mainPixmap = screen->grabWindow(targetWid);// 获取所有子窗口std::vector<HWND> childHandles = getAllChildWindows(hwnd);// 遍历子窗口并截图for (HWND childHwnd : childHandles) {WId childWid = reinterpret_cast<WId>(childHwnd);QWindow* childWindow = QWindow::fromWinId(childWid);if (childWindow) {// 获取子窗口在屏幕中的位置RECT rect;GetWindowRect(childHwnd, &rect);QPoint childPos(rect.left, rect.top);// 截取子窗口内容QPixmap childPixmap = screen->grabWindow(childWid);// 将子窗口内容绘制到主截图中QPainter painter(&mainPixmap);painter.drawPixmap(childPos - mainPixmap.rect().topLeft(), childPixmap);}}return mainPixmap;
}
  1. 处理窗口层级和覆盖
    若子窗口有重叠,需按Z序(从底到顶)绘制,确保正确覆盖:
// 修改回调函数获取Z序列表
std::vector<HWND> getAllChildWindowsOrdered(HWND parent) {std::vector<HWND> children;HWND hwnd = GetWindow(parent, GW_CHILD);while (hwnd) {if (IsWindowVisible(hwnd)) {children.push_back(hwnd);}hwnd = GetWindow(hwnd, GW_HWNDNEXT); // 按Z序获取}return children;
}
  1. 使用高级API处理复杂内容
    对使用DirectComposition或透明效果的窗口,使用PrintWindow API:
QPixmap captureWithPrintWindow(HWND hwnd) {RECT rect;GetWindowRect(hwnd, &rect);int width = rect.right - rect.left;int height = rect.bottom - rect.top;QImage image(width, height, QImage::Format_ARGB32);HDC hdc = GetWindowDC(hwnd);HDC memdc = CreateCompatibleDC(hdc);HBITMAP hbitmap = CreateCompatibleBitmap(hdc, width, height);SelectObject(memdc, hbitmap);// 使用 PW_RENDERFULLCONTENT 捕获所有内容(Windows 8+)PrintWindow(hwnd, memdc, PW_RENDERFULLCONTENT);BITMAPINFOHEADER bi = { sizeof(BITMAPINFOHEADER), width, height, 1, 32, BI_RGB };GetDIBits(memdc, hbitmap, 0, height, image.bits(), (BITMAPINFO*)&bi, DIB_RGB_COLORS);DeleteObject(hbitmap);DeleteDC(memdc);ReleaseDC(hwnd, hdc);return QPixmap::fromImage(image);
}

完整调用示例

// 主函数调用
HWND targetHwnd = ...; // 目标窗口句柄
WId targetWid = reinterpret_cast<WId>(targetHwnd);
QPixmap result = captureWindowWithChildren(targetWid);
result.save("capture.png");

关键注意事项
窗口可见性检查:通过IsWindowVisible过滤隐藏窗口。

坐标转换:确保子窗口位置相对于主窗口正确偏移。

性能优化:若窗口频繁更新,考虑缓存或增量截图。

DPI适配:处理高DPI缩放,使用GetDpiForWindow和Qt::AA_EnableHighDpiScaling。

通过上述方法,可确保非模态子窗口的内容被正确捕获并合成到主截图中。

  1. 通个直接访问显卡内存高效完成操作**[高效方案设计思路]**
    3.1. 使用DXGI Desktop Duplication API
    直接捕获整个屏幕的帧,避免逐个窗口截图,利用GPU加速。

3.2基于窗口位置裁剪区域
通过目标窗口及其子窗口的屏幕坐标,从全屏帧中提取所需内容。

3.3多线程缓存与合成
主线程捕获全屏帧,子线程处理坐标计算和图像裁剪,减少单帧延迟。

步骤1:初始化DXGI捕获(仅需一次)

#include <dxgi1_2.h>
#include <d3d11.h>ID3D11Device* d3dDevice = nullptr;
ID3D11DeviceContext* d3dContext = nullptr;
IDXGIOutputDuplication* duplication = nullptr;bool initDxgiCapture() {// 创建D3D设备D3D_FEATURE_LEVEL featureLevel;HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0,nullptr, 0, D3D11_SDK_VERSION, &d3dDevice, &featureLevel, &d3dContext);if (FAILED(hr)) return false;// 获取DXGI输出IDXGIOutput* output;IDXGIAdapter* adapter;DXGI_OUTPUT_DESC outputDesc;if (SUCCEEDED(d3dDevice->QueryInterface(__uuidof(IDXGIAdapter), (void**)&adapter))) {if (SUCCEEDED(adapter->EnumOutputs(0, &output))) {output->GetDesc(&outputDesc);IDXGIOutput1* output1;output->QueryInterface(__uuidof(IDXGIOutput1), (void**)&output1);output1->DuplicateOutput(d3dDevice, &duplication);output1->Release();}adapter->Release();}return duplication != nullptr;
}

步骤2:异步捕获全屏帧(每帧调用)

#include <QtConcurrent/QtConcurrent>QPixmap dxgiFrame; // 全局帧缓存
QMutex frameMutex;void captureFrameAsync() {QtConcurrent::run([&]() {DXGI_OUTDUPL_FRAME_INFO frameInfo;IDXGIResource* resource = nullptr;HRESULT hr = duplication->AcquireNextFrame(0, &frameInfo, &resource);if (hr == DXGI_ERROR_WAIT_TIMEOUT) return;if (SUCCEEDED(hr)) {ID3D11Texture2D* texture;resource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&texture);D3D11_TEXTURE2D_DESC desc;texture->GetDesc(&desc);desc.Usage = D3D11_USAGE_STAGING;desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;ID3D11Texture2D* stagingTexture;d3dDevice->CreateTexture2D(&desc, nullptr, &stagingTexture);d3dContext->CopyResource(stagingTexture, texture);D3D11_MAPPED_SUBRESOURCE mapped;d3dContext->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &mapped);QImage image(desc.Width, desc.Height, QImage::Format_RGBA8888);for (int y = 0; y < desc.Height; ++y) {memcpy(image.scanLine(y), (BYTE*)mapped.pData + y * mapped.RowPitch, desc.Width * 4);}d3dContext->Unmap(stagingTexture, 0);stagingTexture->Release();resource->Release();duplication->ReleaseFrame();QMutexLocker locker(&frameMutex);dxgiFrame = QPixmap::fromImage(image);}});
}

步骤3:实时裁剪目标窗口区域

// 缓存窗口位置(每100ms更新一次,避免频繁调用)
QTimer* updateTimer = new QTimer;
std::vector<QRect> windowRegions; // 主窗口和子窗口的区域updateTimer->start(100); // 100ms更新一次窗口位置
QObject::connect(updateTimer, &QTimer::timeout, [targetHwnd]() {HWND hwnd = reinterpret_cast<HWND>(targetHwnd);windowRegions.clear();// 主窗口区域RECT rect;GetWindowRect(hwnd, &rect);windowRegions.push_back(QRect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top));// 子窗口区域(遍历并过滤)EnumChildWindows(hwnd, [](HWND hwnd, LPARAM lParam) -> BOOL {if (IsWindowVisible(hwnd)) {RECT rect;GetWindowRect(hwnd, &rect);auto regions = reinterpret_cast<std::vector<QRect>*>(lParam);regions->push_back(QRect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top));}return TRUE;}, reinterpret_cast<LPARAM>(&windowRegions));
});// 合成最终图像(每帧调用)
QPixmap getTargetPixmap() {QMutexLocker locker(&frameMutex);if (dxgiFrame.isNull()) return QPixmap();QPixmap result(dxgiFrame.size());result.fill(Qt::transparent);QPainter painter(&result);for (const QRect& region : windowRegions) {painter.drawPixmap(region, dxgiFrame, region);}return result;
}

性能优化关键点

  1. GPU加速捕获
    DXGI直接访问显存,比grabWindow或PrintWindow快10倍以上。

  2. 异步线程模型
    分离捕获和合成线程,避免阻塞主循环。

  3. 减少窗口位置更新频率
    每100ms更新一次窗口位置,而非每帧更新。

  4. 内存复用
    复用全局QPixmap和纹理对象,避免重复分配内存。

在这里插入图片描述
注意事项
仅支持Windows 8+
DXGI Desktop Duplication需要较新的系统。

多显示器适配
需根据目标窗口所在显示器选择对应的IDXGIOutput。

管理员权限
部分系统要求进程具有管理员权限才能捕获其他窗口。

此方案通过底层API和异步处理,显著提升了截图性能,完全可满足60FPS需求。

http://www.dtcms.com/wzjs/527055.html

相关文章:

  • 网站做优化的成本竞价托管多少钱一个月
  • 怀化网站优化联系方式厦门人才网唯一官网
  • 商丘企业网站建设推荐广州网络营销推广
  • 有没有直接做网站的软件百度推广需要什么条件
  • 北京网站建设价格低网络营销师主要做什么
  • 设计企业品牌logo靠谱的seo收费
  • c 教学网站开发哪些网站是营销型网站
  • 网站模板设计开发搜索引擎推广案例
  • 国外网页素材网站网站推广的工作内容
  • 现在由哪些网站可以做外链淘宝seo具体优化方法
  • 网站开发验收模板友情链接的定义
  • 佛山优秀网站建设品牌推广案例
  • 企业网站建设规划设计任务书东莞寮步最新通知
  • 网站子域名怎么做互联网营销培训课程
  • 网站建设教程流程武汉网站优化
  • 建设厅网站官网微商软文大全
  • WordPress怎么输入代码seo整站优化吧
  • 做书app下载网站有哪些内容新乡网站优化公司
  • 网站建设968营销软文网站
  • 免费素材网站mixkit百度公司招聘岗位
  • 南宁网站建设咨q479185700上墙重庆seo公司
  • 宁波网站建设怎么样网络营销的专业知识
  • 昆明建设路租房信息昆明租房网站营销策划公司取名大全
  • 官网网站设计嘉兴新站seo外包
  • web开发和做网站的区别如何实施网站推广
  • 服务网站 建设原则谷歌外贸seo
  • 网站主题旁边的图标怎么做的网页分析工具
  • 网站建设项目策划书格式企业qq官方下载
  • 龙岗网站制作公司一般多少钱seo外包服务公司
  • 猪价格今日猪价格全国走势seo推广岗位职责