I'm aware that have some similar questions about this topic, but I couldn't find one relative to a window being created using Qt.
I tried all suggestions in this answer: How to smooth ugly jitter/flicker/jumping when resizing windows, especially dragging left/top border (Win 7-10; bg, bitblt and DWM)?
- Modifying
WM_WINDOWPOSCHANGING
flag toSWP_NOCOPYBITS
wp = reinterpret_cast<tagWINDOWPOS*>(msg->lParam);
wp->flags |= SWP_NOCOPYBITS;
- Returning
WVR_VALIDRECTS
inWM_NCCALCSIZE
if (msg->wParam == 1)
return WVR_VALIDRECTS;
- Applying
CS_HREDRAW | CS_VREDRAW
styles to the window
SetWindowLongPtr(HWND(winId()), GWL_STYLE, CS_HREDRAW | CS_VREDRAW | WS_POPUPWINDOW | WS_CAPTION | WS_SIZEBOX | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CLIPCHILDREN);
- Apply the
exstyle
WS_EX_COMPOSITED
WM_ERASEBKGND
to return 1;
But the flicker persists. What else I could try?
The goal is to create a window without a caption, that can be resized/minimized.
The code below is working the problem is when the window is being resized from left/top it causes flickering.
//.h
#include <QtWidgets/QMainWindow>
#include <Windows.h>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void Frameless()
{
// set flags that will override what Qt does, especially with the Qt::FramelessWindowHint which essentially disables WS_SIZEBOX/WS_THICKFRAME
SetWindowLongPtr(HWND(winId()), GWL_STYLE, WS_POPUPWINDOW | WS_CAPTION | WS_SIZEBOX | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CLIPCHILDREN);
}
private:
Ui::MainWindowClass ui;
protected:
virtual bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result) override;
};
//.cpp
#include "MainWindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
Frameless();
return;
}
MainWindow::~MainWindow()
{}
bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, qintptr* result)
{
MSG* msg = static_cast<MSG*>(message);
switch (msg->message)
{
case WM_WINDOWPOSCHANGING:
{
tagWINDOWPOS* wp;
wp = reinterpret_cast<tagWINDOWPOS*>(msg->lParam);
wp->flags |= SWP_NOCOPYBITS;
}
break;
case WM_NCCALCSIZE:
{
if (msg->wParam == 1)
return WVR_VALIDRECTS;
// Just return 0 and mark event as handled. This will draw the widget contents
// into the full size of the frame, instead of leaving room for it.
*result = 0;
return true;
}
break;
case WM_NCHITTEST:
{
if (isMaximized())
{
return false;
}
*result = 0;
const LONG borderWidth = 8;
RECT winrect;
GetWindowRect(reinterpret_cast<HWND>(winId()), &winrect);
// must be short to correctly work with multiple monitors (negative coordinates)
short x = msg->lParam & 0x0000FFFF;
short y = (msg->lParam & 0xFFFF0000) >> 16;
bool resizeWidth = minimumWidth() != maximumWidth();
bool resizeHeight = minimumHeight() != maximumHeight();
if (resizeWidth)
{
//left border
if (x >= winrect.left && x < winrect.left + borderWidth)
{
*result = HTLEFT;
}
//right border
if (x < winrect.right && x >= winrect.right - borderWidth)
{
*result = HTRIGHT;
}
}
if (resizeHeight)
{
//bottom border
if (y < winrect.bottom && y >= winrect.bottom - borderWidth)
{
*result = HTBOTTOM;
}
//top border
if (y >= winrect.top && y < winrect.top + borderWidth)
{
*result = HTTOP;
}
}
if (resizeWidth && resizeHeight)
{
//bottom left corner
if (x >= winrect.left && x < winrect.left + borderWidth &&
y < winrect.bottom && y >= winrect.bottom - borderWidth)
{
*result = HTBOTTOMLEFT;
}
//bottom right corner
if (x < winrect.right && x >= winrect.right - borderWidth &&
y < winrect.bottom && y >= winrect.bottom - borderWidth)
{
*result = HTBOTTOMRIGHT;
}
//top left corner
if (x >= winrect.left && x < winrect.left + borderWidth &&
y >= winrect.top && y < winrect.top + borderWidth)
{
*result = HTTOPLEFT;
}
//top right corner
if (x < winrect.right && x >= winrect.right - borderWidth &&
y >= winrect.top && y < winrect.top + borderWidth)
{
*result = HTTOPRIGHT;
}
}
if (*result != 0)
return true;
QWidget *action = QApplication::widgetAt(QCursor::pos());
if (action == this){
*result = HTCAPTION;
return true;
}
return false;
}
break;
default:
return QWidget::nativeEvent(eventType, message, result);
}
return QWidget::nativeEvent(eventType, message, result);
}
EDIT
I was testing the GUI compiling the project as debug
when I changed to release
the flicker reduced a lot but still persists, and now it flickers from the right instead of the left.
Testing with QT 6.3.1 static
debug
:
https://www.youtube.com/watch?v=a5fmXKsKDaY&feature=youtu.be
Testing with QT 6.3.1 static
release
:
https://www.youtube.com/watch?v=OwpxmCsLLRQ
Computer settings, os version: https://i.stack.imgur.com/3DXmd.png
I tested on two different machines using win10, and the flicker happens on both.
The same issue happens with the frameless.h
from jdfa
answer, the difference is that my method the GUI resizing is way more 'smoothly'/fast.