在 Qt 中,虽然 Qt 本身没有直接提供枚举桌面窗口的 API,但可以通过调用 Windows API 来实现枚举桌面上所有窗口的句柄,包括子窗口以及子窗口与父窗口的关系。我们可以使用 Windows 的 EnumWindows
和 EnumChildWindows
函数来枚举所有顶层窗口及其子窗口。
以下是一个完整的 Qt 程序示例,它演示了如何枚举所有顶层窗口和它们的子窗口,并显示它们之间的父子关系。
示例代码
#include <QCoreApplication>
#include <Windows.h>
#include <QDebug>
#include <QMap>
#include <QString>
// 用于存储父窗口及其子窗口关系
QMap<HWND, QList<HWND>> windowHierarchy;
// 枚举子窗口的回调函数
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam) {
HWND parent = (HWND)lParam;
windowHierarchy[parent].append(hwnd);
return TRUE;
}
// 枚举顶层窗口的回调函数
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
// 获取窗口标题
int length = GetWindowTextLength(hwnd);
if (length > 0) {
TCHAR *buffer = new TCHAR[length + 1];
GetWindowText(hwnd, buffer, length + 1);
QString windowTitle = QString::fromWCharArray(buffer);
delete[] buffer;
qDebug() << "Top-level Window Handle:" << hwnd << "Title:" << windowTitle;
// 枚举子窗口
EnumChildWindows(hwnd, EnumChildProc, (LPARAM)hwnd);
}
return TRUE;
}
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
// 枚举所有顶层窗口
EnumWindows(EnumWindowsProc, 0);
// 输出子窗口的父子关系
for (auto it = windowHierarchy.begin(); it != windowHierarchy.end(); ++it) {
HWND parent = it.key();
const QList<HWND>& children = it.value();
qDebug() << "Parent Window Handle:" << parent << "has" << children.size() << "children.";
for (HWND child : children) {
qDebug() << " Child Window Handle:" << child;
}
}
return a.exec();
}
代码说明
-
Windows API 函数:
EnumWindows
: 枚举所有顶层窗口。EnumChildWindows
: 枚举指定窗口的子窗口。GetWindowText
: 获取窗口的标题文本。
-
数据结构:
- 使用
QMap<HWND, QList<HWND>>
来存储窗口的父子关系,键是父窗口句柄,值是子窗口句柄的列表。
- 使用
-
回调函数:
EnumWindowsProc
: 枚举顶层窗口的回调函数,它会获取窗口的标题并调用EnumChildWindows
来枚举该窗口的所有子窗口。EnumChildProc
: 枚举子窗口的回调函数,它将子窗口添加到对应父窗口的列表中。
-
主函数:
EnumWindows(EnumWindowsProc, 0);
枚举所有顶层窗口,并为每个顶层窗口调用回调函数EnumWindowsProc
。- 最后,遍历
windowHierarchy
,输出每个顶层窗口及其子窗口的关系。
运行结果
程序将在控制台输出所有顶层窗口及其子窗口的句柄和标题,例如:
Top-level Window Handle: 0x000203D2 Title: "MyApp - Notepad"
Parent Window Handle: 0x000203D2 has 3 children.
Child Window Handle: 0x000203DA
Child Window Handle: 0x000203E2
Child Window Handle: 0x000203EA
...
注意事项
- Windows 特定:这个代码依赖 Windows API,因此只能在 Windows 系统上运行。
- 窗口标题为空:某些窗口可能没有标题,因此
GetWindowTextLength
返回 0,在这种情况下,窗口会被跳过。 - 子窗口与父窗口的关系:程序枚举所有子窗口并将它们关联到父窗口,方便在以后的操作中了解它们的关系。
这个示例提供了一个基础框架,你可以在此基础上扩展功能,例如进一步获取窗口的其他属性,或执行更复杂的窗口管理操作。