简体   繁体   English

通过小部件获取顶层窗口

[英]Getting top-level window by widget

I'm hooking the QPainter::drawText() function of a Qt5 application on Windows. 我挂在Windows上的Qt5应用程序的QPainter::drawText()函数。 My goal is to identify the native handle of the top-level-window to which the text is painted. 我的目标是确定将文本绘制到的顶级窗口的本机句柄。 First, I'm getting the associated widget. 首先,我要获取关联的小部件。

QWidget *widget = static_cast<QWidget *>(painter->device());

So it should be possible to find the corresponding top-level window/widget. 因此,应该可以找到相应的顶层窗口/小部件。 But it's harder than I thought. 但这比我想的要难。 This is what I tried so far: 这是我到目前为止尝试过的:

while (widget->parentWidget())
    widget = widget->parentWidget();

HWND hwnd = (HWND) widget->winId();

No success. 没有成功 The top-parent is never the desired window. 顶级父母永远不是所需的窗口。

QApplication::topLevelWidgets()

Showed me that one single window contains several top-level-widgets (including the one I'm looking for). 告诉我一个窗口包含几个顶级小部件(包括我要寻找的小部件)。

I also tried QApplication::topLevelAt(widget->mapToGlobal(QPoint())) 我也尝试了QApplication::topLevelAt(widget->mapToGlobal(QPoint()))

In some cases this actually works, but not reliably. 在某些情况下,这确实有效,但不可靠。 Depending on text and window position I'm getting a AccessViolationException , so this is not an option. 根据文本和窗口的位置,我会得到一个AccessViolationException ,所以这不是一个选择。

By testing widget->testAttribute(Qt::WA_NativeWindow) I found out that most of the widgets are non-native Alien Widgets . 通过测试widget->testAttribute(Qt::WA_NativeWindow)我发现大多数小部件都是非本地Alien Widgets

This is how I get the (what I call) top-level window. 这就是我获得(称为)顶级窗口的方式。

WinAPI.EnumChildWindows(
    WinAPI.GetDesktopWindow(),
    new EnumWindowsProc(this.EnumWindowsCallback), 0);

Then I check the window titles to find the handles I'm interested in. 然后,我检查窗口标题以找到我感兴趣的句柄。

I'm not able to find a relation from any (low-level) widget to the (top-level) widget that holds the window title. 我找不到从任何(低级)小部件到包含窗口标题的(顶层)小部件的关系。

For the QWidget that acts as a top level window, call QWidget::window() . 对于QWidget充当顶层窗口, 调用QWidget::window()

For the nearest parent with a native handle, call QWidget::nativeParentWidget() . 对于具有本地句柄的最近的父级, 请调用QWidget::nativeParentWidget()

Calling winId() forces the widget to acquire a native window handle if it does not have one , which isn't your goal. 调用winId() 强制窗口小部件获取本机窗口句柄(如果它没有窗口句柄) ,这不是您的目标。 A top level window will always have a native id, so (HWND)window()->winId() is fine. 顶层窗口将始终具有本机ID,因此(HWND)window()->winId()很好。 Note that this is usually the same as calling QWidget::effectiveWinId() . 请注意,这通常调用QWidget::effectiveWinId()

It's done! 完成! I found a solution for my problem. 我找到了解决问题的方法。

Each windows has it's own thread. 每个窗口都有其自己的线程。

int threadId = WinApi.GetWindowThreadProcessId(wndHandle, IntPtr.Zero)

With it I use EnumThreadWindows to get a list of all window-handles created by this thread. 通过它,我使用EnumThreadWindows来获取此线程创建的所有窗口句柄的列表。

Finally I check wheather widget->effectiveWinId() is in the list. 最后,我检查了清单中的widget widget->effectiveWinId()

So I can map each widget to its corresponding window! 因此,我可以将每个小部件映射到其对应的窗口!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM