I'm developing an application using Qt 4.5 (under Windows Vista but want it to be cross platform). I'm using C++
I'd like to create a popup window that that contains a QLineEdit widget, with the feature that when the user interacts with the QLineEdit widget, the popup window is not activated (the main application window remains active).
Creating a window (widget) with the Qt::Popup | Qt::Window flags gives me exactly what I want, except i don't want the 3D shadow border effect this provides. I want a borderless window. Note that the Qt::FramelessWindowHint flag doesn't achieve this.
Anyone got any clues?
Further clarification: Below is a snippit from a simple test application that creates a window with a button in it. When the button is pressed, a popup window is shown and the user can type into a QLineEdit box. When the user does this, the main window remains activated:
http://howlettresearch.com/popup_img_1.png
However, note the shadow border on the popup window (I have been unable to get rid of this).
By comparison, creating the window as in the commented out line allows a popup style window to be created without a shadow, but when the user clicks on the QLineEdit in the popup, the main window is no longer active. You can tell because the shadow on the main window has changed.
http://howlettresearch.com/popup_img_2.png
I'm really after a popup window which behaves as if it is part of the main window. As a side note, the popup window disappears when clicking outside it, but this is almost the behavior I want and I can work with this and grabMouse etc. to do what I want... provided I can get rid of that shadow!
PopupTest::PopupTest(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
QPushButton* pb = new QPushButton("test button");
setCentralWidget(pb);
QObject::connect(pb, SIGNAL(clicked()), this, SLOT(handleClick()));
}
void PopupTest::handleClick()
{
//QFrame* popup1 = new QFrame(this, Qt::Tool | Qt::Window | Qt::FramelessWindowHint);
QFrame* popup1 = new QFrame(this, Qt::Popup | Qt::Window );
popup1->resize(150,100);
QLineEdit *tmpE = new QLineEdit( popup1 );
connect( tmpE, SIGNAL( returnPressed() ), popup1, SLOT( hide() ) );
tmpE->setGeometry(10,10, 130, 30);
tmpE->setFocus();
popup1->show();
}
PopupTest::~PopupTest()
{
}
I worked out a solution to the question I posted earlier.
First, a popup widget can be created by deriving from QWidget
with flags Qt::Window | Qt::FramelessWindowHint
. I actually hacked qwidget_win.cpp
to ensure my window has the same style and extended style as the Popup control provided by WPF (0x96000000 and 0x08000088 respectively), as determined using Spy++, however I don't think that should matter.
Setting the window style doesn't solve the Window activation problem. The key to doing this to intercept the windows messages that inform the main window that it's non-client area should be updated (WM_NCACTIVATE
message). This can be done by providing a custom implementation of QApplication::winEventFilter(MSG* msg, long* result)
.
Unfortunately, simply eating inactivate WM_ NCACTIVATE
messages isn't enough, because it seems to prevent WM_ACTIVATE
and other messages that otherwise get generated from being sent to the popup window. To solve this, I have a proof of concept working where I generate the required windows messages in winEventFilter
after having caught an appropriate WM_NCACTIVATE
message.
From here, there are some details to work through to make sure it's robust (intercept WM_ACTIVATEAPP
comes to mind), and then wrap it up into something nice and reusable.
All this is windows specific of course, be interesting to see if there are issues under Linux.
All this is a bit of a pain. Hope I didn't miss something obvious...