PDA

View Full Version : Events not fired when used Windows::SetParent on QApplication



Gigges
25th July 2012, 15:45
Hi,

I am using Qt for the last two years without any real problems but now I am stuck...

It is about the communication about two Qt programs under Windows.
One program, let's call him Client, is developed for Linux and can also run under Windows for test purposes (thank you Qt for the multi platform :)).
The other program, called Server, has to run only under Windows. This is a 'Host' program which has several functionality (more like small programs), each placed in a separate tabs using a QTabWidget.

The situation:
Now I want to place the Client inside a new QTab in the Server. With other words: I want to run the executable (using QProcess) and show it on top of a tab of the QTabWidget. Windows already supplies some nice methods for removing the decoration (border,title bar etc..) and change the parent of a window so repainting,resizing,window activation is all taken care by Windows.
When I start my Client using a QProcess I wait for it to be launched, so that there is a window I can talk to. Then I remove the decoration and set the tab of the QTabWidget of the Server as parent.
All done with this code:



HWND window = findEmbeddedWindow(); // Get/Find the HWND of the 'Client'
if (!window) return;

HWND parent = winId(); // HWND of tab of the 'Server'

SetParent(window,parent); // WINDOWS CALL

long style = GetWindowLong(window,GWL_STYLE); // WINDOWS CALL

style &= ~WS_CHILD;
style |= WS_POPUP; // owned window of this one...

style &= ~WS_CAPTION;
style &= ~WS_BORDER;
style &= ~WS_THICKFRAME;

SetWindowLong(window,GWL_STYLE,style); // WINDOWS CALL

QPoint pos = this->mapToGlobal(QPoint(0,0));
QSize size = this->size();

SetWindowPos(window,HWND_TOP,0,0,size.width(),size .height(),SWP_FRAMECHANGED); // WINDOWS CALL


This all works perfectly, my Client is nicely placed on top of my tab and all the repainting etc. is working perfect.
When I load notepad.exe through the QProcess it's being located on top of my tab and i can open files, edit save, exit etc... everything works fine.

Problem:
However... there is a problem, otherwise I would not post anything... :p
When I load my Client, or any other QApplication instead of notepad.exe the execatuable is being loaded and nicely placed on the tab.
But my pushbuttons of Client do not respond (slot is never called). When I hoover over a button with my mouse the button get's selected. Which should be. But a press on the mouse has no respond.
Even when I make a small QApplication, containing a QPushButton and a QLineEdit. When the button is pressed, the lineedit says "clicked". This does also not work.

I have set some debugging and I can see that the events for mousePressEvent and mouseReleaseEvent for my QMainWindow are called. However not in the QPushButtons or any other QWidget of the QMainWindow. Installing an eventFilter on the QWidget shows that it receives the QEvent::MouseButtonPress but just doesn't do anything with it.
When i put a QLineEdit in the QMainWindow i can just type stuff in it, that's making it even more stranger for me... Because this means that I can select the LineEdit with my mouse but not click on a PushButton.

I hope someone knows anything about this because I have been testing, debugging and searching the web for some time now...

Ps. Already thanks for reading my first post!

Gigges
26th July 2012, 10:59
I have done some debugging and I found out that all the events where triggered.
However the position of the mouse was wrong.

The global position is correct but the relative position (to calculate if the mouse is on a widget) could not be calculated. This failed because the position is being calculated by QWidget::mapToGlobal. This one sends the global position minus the decoration instead of the real relative because the QWidget::internalWinId() returns 0 (which is in the if statement).

I think the winid's got screwed up when i reset the parent of the program using the windows call SetParent(HWND,HWND) from my other program, however... just a guess because the enterEvent and leaveEvent are triggered at the right moments and they are also based on the relative mouse positions...

--- New stuff ---
- When i set the 'client' program as child of the 'server' via the Windows api, the position of the window will be 0,0. So Windows itself takes the relative point to the parent.
- The enterEvent and leaveEvent work fine because they use the QMainWindow winid, which is set correctly. However all other events use the QWidgets winid which is empty. And I think because they didn't get reset or something like that when using the Windows call SetParent(HWND,HWND) on the QMainWindow.

I will stay debugging, testing and reading documentation, but as usual any help/advice would be nice.

Vikki
4th October 2012, 14:46
Hi,

I'm currently trying to perform the exact same operation and I'm facing the same problems.
It seems that as you said, most of the Qt widgets do not have by default a native id. To tackle this issue, you have the possibility to force a widget (or every widgets of your application) to use a native id. See the documentation of QWidget about "Native Widgets vs Alien Widgets" for more details.

You can quickly test this solution by calling:
QCoreApplication.setAttribute(Qt::AA_NativeWindows ,true);
at the beginning of your main function

bbdaffy
21st November 2013, 02:56
Hi,

I am a newbie to Qt, so please bear with me if I am asking silly questions. I am trying to perform SetParent on a child window which is a QApplication, but has no clue how to start. Therefore I am very interested in the code :

HWND window = findEmbeddedWindow();

Is it possible to paste some snipplet of the function findEmbeddedWindow() here? It will definitely be helpful to me. Thank you very much.

Best Regards...

one
8th June 2014, 13:19
I have a similar problem but exactly opposite -
I too have a 'server' and a 'client' and I need to bring the client into the 'server's QWidget.

my code is:

winHandle = ::FindWindowA(NULL, "My Client");
if(winHandle != NULL)
{
::ShowWindow(winHandle, SW_HIDE);


// Remove the window border
LONG lStyle = GetWindowLong(winHandle, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
::SetWindowLong(winHandle, GWL_STYLE, lStyle);

::SetParent(winHandle, (HWND)(ui->widget->effectiveWinId()));
::SetWindowPos(winHandle, HWND_TOP, ui->widget->pos().x(), ui->widget->pos().y(), 0, 0 , SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_NOSIZE | SWP_ASYNCWINDOWPOS);
::UpdateWindow(winHandle);
::ShowWindow(winHandle, SW_SHOW);
}
the problem I'm facing is that sometimes (not always!) the servers' buttons become not responding.
I noticed that when such a case happens, the buttons don't respond as long as they are located in the middle of the screen. but, the weirdest thing is that if i move the whole window so the buttons are located close to the edge of the screen - they work! if i move it back to the center - they stop working again.
any idea?? someone?

anda_skoa
8th June 2014, 14:02
Have you tried using Qt's "foreign window" capability?

QWindow::fromWinId() to create a QWindow for the winHandle and then embedding it into the widget scene using QWidget::createWindowContainer()

Cheers,
_

one
9th June 2014, 09:05
can you explain exactly how to do so?
I tried, but couldn't get the window to actually be embedded in the server's widget.
the code I've tried was:

QWindow* win= QWindow::fromWinId((WId)winHandle);
QWidget *wid = QWidget::createWindowContainer(win,ui->widget);

the result I got was: the client's window shoed up small on the top left of the screen, not integrated at all.
thanks!

anda_skoa
9th June 2014, 09:28
Did you add wid to the layout of its parent?

Cheers,
_

one
9th June 2014, 09:30
no, how do you do so?

anda_skoa
9th June 2014, 11:39
Like for any other widget.

If ui->widget does not have a layout yet, create a simple one and add the child widget



QVBoxLayout *layout = new QVBoxLayout(ui->widget);
layout->addWidget(wid);


Cheers,
_

one
10th June 2014, 07:57
thanks for that but it didn't work.
I've realized that
QWindow::fromWinId((WId)winHandle) returns NULL and in the console it found:
fromWinId(): platform plugin does not support foreign windows.
how can i solve this?

anda_skoa
10th June 2014, 09:01
Interesting. The Windows platform plugin should have the ForeignWindow capability.

Which version of Qt are you using?

Cheers,
_

one
10th June 2014, 09:29
qt 5.1.1 , MSVC 2012 x64 compiler

Added after 25 minutes:

tried with QT 5.2 and it worked.
The client's window is now embedded in the Server's widget but you can see only a very skinny vertical line of the client's screen.
how can i fix it and make the whole client's window visible?

anda_skoa
10th June 2014, 11:19
Can you post the embedding code you have working right now?

Cheers,
_

one
10th June 2014, 17:46
WId winid = (WId) winHandle;

QWindow * window = QWindow::fromWinId(winid);
QWidget * widget = QWidget::createWindowContainer(window);
widget->setParent( ui->widget);
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(widget);
ui->widget->setLayout(layout);

Thanks a lot for your help!

anda_skoa
11th June 2014, 07:13
Make sure that ui->widget did not have a layout already and that it is part of its parent's layout.

Otherwise this unfortunately looks OK to me.

Cheers,
_

one
11th June 2014, 07:16
I added a set of minimum size to the window - and that helped. Thanks!
BUT, now the keyboard is not working in the internal window - for example if i embed Notepad - i cannot type anything there!:( but i can use the mouse.
strange!!