Flickering when resizing window from left side QT

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 to SWP_NOCOPYBITS
       wp = reinterpret_cast<tagWINDOWPOS*>(msg->lParam);
       wp->flags |= SWP_NOCOPYBITS;
  • Returning WVR_VALIDRECTS in WM_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.imgur.com/zdDAP1D.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.



Comments

Popular posts from this blog

Spring Elasticsearch Operations

Network Error and Timeout on Authorize.net JS

Object oriented programming concepts (OOPs)