Qt Application in native Windows window
-
While it's possible to embed QWidget in external window it's a waste of time since it already has a native frame, so you'd be doing the same thing Qt does anyway.
To get a grip on the Windows windowing stuff(the frame in your case) you basically need access to HWND of the window and the MSG messages it receives from the system.
You can get HWND of the window by casting the result of "winId":http://qt-project.org/doc/qt-5.1/qtwidgets/qwidget.html#winId, and then implement the "nativeEvent":http://qt-project.org/doc/qt-5.1/qtwidgets/qwidget.html#nativeEvent and cast the message param to MSG.
-
Hi!
Thanks.
I already figured a small part of it in the mean time, but I'm still having some difficulties.The problem that I have is just a border around it. When a window is displayed, the border is still shown and then when it is resized, border disappears but it leaves not rendered white area around the window.
Bottom area is exact height as the title bar + bottom border and right area 2*border width.
Link to image "here":http://oi44.tinypic.com/2j8ayo.jpg.
Black area: entire screen cropped out a little bit
Blue and green window custom border
White with a little blue and green on the left is the area: problems.
Window is already resized at this point.It's still in debug colours, so it's not yet a Picaso masterpiece ;).
I'm trying to port the code from "here":http://msdn.microsoft.com/en-us/library/windows/desktop/bb688195(v=vs.85).aspx msdn article (missing ").aspx" in the URL address).
Regards,
JakeCode:
@bool Window::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
*result = 0;
MSG *msg = static_cast<MSG *>(message);if(msg->message == WM_CREATE)
{
HWND hWnd = (HWND)this->winId();
qDebug() << "WM_ACTIVATE";RECT rcClient;
GetWindowRect(hWnd, &rcClient);SetWindowPos(hWnd,
NULL,
this->pos().x(), this->pos().y(),
this->size().width(), this->size().height(),
SWP_FRAMECHANGED);*result = 0;
}else if(msg->message == WM_ACTIVATE)
{
qDebug() << "WM_ACTIVATE";HWND hWnd = (HWND)this->winId();
MARGINS margins;margins.cxLeftWidth = 0;
margins.cxRightWidth = 0;
margins.cyBottomHeight = 0;
margins.cyTopHeight = 0;DwmExtendFrameIntoClientArea(hWnd, &margins);
*result = 0;
}else if(msg->message == WM_NCCALCSIZE)
{
qDebug() << "WM_NCCALCSIZE";NCCALCSIZE_PARAMS pncsp = reinterpret_cast<NCCALCSIZE_PARAMS>(msg->lParam);
pncsp->rgrc[0].left = pncsp->rgrc[0].left + 0;
pncsp->rgrc[0].top = pncsp->rgrc[0].top + 0;
pncsp->rgrc[0].right = pncsp->rgrc[0].right - 0;
pncsp->rgrc[0].bottom = pncsp->rgrc[0].bottom - 0;
}else
return QWidget::nativeEvent(eventType, message, result);
}@EDIT:
Includes
@#pragma comment(lib, "dwmapi.lib")
#pragma comment(lib, "UxTheme.lib")
#include <dwmapi.h>
#include <UxTheme.h>
#include <WindowsX.h>
#include "strsafe.h"
#include <afxres.h>
#include <Windows.h>@ -
Seems like some of the stuff is interfering with Qt. For example you use SetWindowPos with HWND, when there's simply resize() and move() on the QWidget. They might fight each other and it's just better to use the Qt ones.
I'm not clear on what you try to do exactly, but here's what I do to extend a frame on a widget:
@
bool extendAeroFrame( QWidget *widget, QMargins margins )
{
//magic number should be propagated to all sides
if( margins.left() == -1 || margins.right() == -1 || margins.top() == -1 || margins.bottom() == -1 )
margins = QMargins( -1, -1, -1, -1 );BOOL compositionEnabled; DwmIsCompositionEnabled( &compositionEnabled ); if( compositionEnabled ) { MARGINS mrg; mrg.cxLeftWidth = margins.left(); mrg.cxRightWidth = margins.right(); mrg.cyTopHeight = margins.top(); mrg.cyBottomHeight = margins.bottom(); HRESULT hr = DwmExtendFrameIntoClientArea( (HWND)widget->winId(), &mrg ); widget->repaint(); return SUCCEEDED( hr ); } else { widget->repaint(); return false; }
}
@An important thing is to check if "Aero" is enabled at all, and also watch for WM_DWMCOMPOSITIONCHANGED message that comes whenever used changes theme. Not watching this results in some nasty drawing artifacts after the switch.
Now the tricky part is that we have to actually paint the background to "transparent" color. Otherwise Qt will just fill it for us with it's style color disregarding the actual margins the above method sets.
To do this reimplement paintEvent and replace the margins with transparency.
Something like this (writing out of my head so expect bugs):
@void YourWidget::paintEvent(QPaintEvent * event)
{
QWidget::paintEvent( event );if(aero_is_enabled) //use DwmIsCompositionEnabled
{
QPainter p( this );
p.setCompositionMode( QPainter::CompositionMode_SourceIn );
p.fillRect( topMargin, Qt::transparent );
p.fillRect( bottomMargin, Qt::transparent );
p.fillRect( leftMargin, Qt::transparent );
p.fillRect( rightMargin, Qt::transparent );
p.setCompositionMode( QPainter::CompositionMode_SourceOver );
}
}
@That's if you want to extend the frame inside the widget.
If you don't want the frame at all and want to draw it yourself it's easier to create a borderless "frame" widget (set a Qt::FramelessWindowHint flag on it), set a layout with margins that you want your window to have and override paintEvent to draw, and mouse event like press, move and release to handle resizing, or better yet - an event filter. This is more portable and actually easier than fiddling with low level winapi stuff.
Btw. MSDN links are a pain to put on this forum(and some others), but just remove the (v=vs.85) part and they work just fine.
-
That's the thing. I don't want the frame at all.
It tried with Qt::FramelessWindowHint. Problem that I have with that option is that I can't capture windows btn + arrow keys to resize and move a window. That forced me to fallback to winapi stuff.MSDN (thanks for the link tip) example works fine, that's why I tried integrating win32 window from winapi with Qt.
EDIT:
I tried cheking button states with GetKeyboardState, GetAsyncKeyState and GetKeyState. All return 0 if Windows button is pressed."Here":https://www.dropbox.com/s/pnur0irvvhld2qr/CustomWindow.zip is a link to entire project.