Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Resizible Frameless Window visual artefacts
Forum Updated to NodeBB v4.3 + New Features

Resizible Frameless Window visual artefacts

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 3 Posters 942 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • FinchiF Offline
    FinchiF Offline
    Finchi
    wrote on last edited by
    #1

    Hi there! I was create QWidget class with atribute
    setAttribute(Qt::WA_TranslucentBackground);
    and flag setWindowFlags(Qt::FramelessWindowHint);
    to make a partly transparent and repeated the functionality of a window with a frame, including resizing the window with the mouse. But there were problems with resizing, when I resize, for example, from the left or top side, I am forced to move the widget and the animation of this movement manifests itself as an undesirable visual effect on the opposite side of the widget, constant shakes are obtained. The repainting after resizing smooths out the shaking a little, but I want to get rid of it completely.
    The code of resizing from the left side:

    void QtFormColorTest::mouseMoveEvent(QMouseEvent* event)
    {
    // mGlobalPos - last write of globalPos()
    const QPoint delta = event->globalPos() - mGlobalPos;
    resize(width() - delta.x(), height());
    move(pos() + QPoint(delta.x(), 0));
    mGlobalPos = event->globalPos();
    }
    

    With setGeomerty() the effect is the same.
    Can you advise me a method to solve this problem without using QML?
    How is this implemented for a standard QWidget?
    Thanks.

    M 1 Reply Last reply
    0
    • FinchiF Finchi

      @Axel-Spoerl Thanks for the answer, other windows do not jittering at all, even the similar code is implemented on QML, I just wanted to make sure that I am doing everything correctly in terms of programming on Qt.
      Thank you.

      FinchiF Offline
      FinchiF Offline
      Finchi
      wrote on last edited by
      #7

      @Finchi

      After some time, I returned to this problem and the best thing I could think of was to make a special transparent widget on top of the main one to resize the main one without visual artifacts.
      For those who are interested, here is the link to github
      Perhaps this code will be useful to those who have a similar problem.

      1 Reply Last reply
      0
      • Axel SpoerlA Offline
        Axel SpoerlA Offline
        Axel Spoerl
        Moderators
        wrote on last edited by
        #2

        Hi @Finchi ,

        could you please share the entire code with us, so I can try to reproduce it?
        Which Qt Version are you using?

        Cheers
        Axel

        Software Engineer
        The Qt Company, Oslo

        FinchiF 1 Reply Last reply
        1
        • FinchiF Finchi

          Hi there! I was create QWidget class with atribute
          setAttribute(Qt::WA_TranslucentBackground);
          and flag setWindowFlags(Qt::FramelessWindowHint);
          to make a partly transparent and repeated the functionality of a window with a frame, including resizing the window with the mouse. But there were problems with resizing, when I resize, for example, from the left or top side, I am forced to move the widget and the animation of this movement manifests itself as an undesirable visual effect on the opposite side of the widget, constant shakes are obtained. The repainting after resizing smooths out the shaking a little, but I want to get rid of it completely.
          The code of resizing from the left side:

          void QtFormColorTest::mouseMoveEvent(QMouseEvent* event)
          {
          // mGlobalPos - last write of globalPos()
          const QPoint delta = event->globalPos() - mGlobalPos;
          resize(width() - delta.x(), height());
          move(pos() + QPoint(delta.x(), 0));
          mGlobalPos = event->globalPos();
          }
          

          With setGeomerty() the effect is the same.
          Can you advise me a method to solve this problem without using QML?
          How is this implemented for a standard QWidget?
          Thanks.

          M Offline
          M Offline
          mpergand
          wrote on last edited by mpergand
          #3

          @Finchi
          Well known issue:
          https://bugreports.qt.io/browse/QTBUG-33302

          Not clear if the culprit is Qt or the OS.
          On Qt 5.12 and MacOS 10.14, no flickering,
          but I see this bug in previous Qt / OS versions.

          1 Reply Last reply
          1
          • Axel SpoerlA Axel Spoerl

            Hi @Finchi ,

            could you please share the entire code with us, so I can try to reproduce it?
            Which Qt Version are you using?

            Cheers
            Axel

            FinchiF Offline
            FinchiF Offline
            Finchi
            wrote on last edited by
            #4

            @Axel-Spoerl

            qt_form_color_test.h

            #pragma once
            
            #include <QtWidgets/QMainWindow>
            #include <QMouseEvent>
            #include <QPushButton>
            
            class QtFormColorTest : public QWidget
            {
            	Q_OBJECT
            
            public:
            	explicit QtFormColorTest(QWidget* parent = nullptr);
            	virtual ~QtFormColorTest();
            
            	void setHorisontalResizeMargin(int margin) { mHMargin = margin; }
            	void setVerticalResizeMargin(int margin) { mVMargin = margin; }
            	void setFullResizeMargin(int margin) { mFMargin = margin; }
            
            	int getHorisontalResizeMargin() { return mHMargin; }
            	int getVerticalResizeMargin() { return mVMargin; }
            	int getFullResizeMargin() { return mFMargin; }
            
            protected:
            	void paintEvent(QPaintEvent* event) override;
            	void mousePressEvent(QMouseEvent* event) override;
            	void mouseMoveEvent(QMouseEvent* event) override;
            	void mouseReleaseEvent(QMouseEvent* event) override;
            	void resizeEvent(QResizeEvent* event) override;
            
            private:
            	const QPoint mInvalidPoint{ QPoint(-1, -1) };
            	QPoint mGlobalPos{ QPoint(0, 0) };
            	QPoint mLocalPos{ QPoint(0, 0) };
            	bool mIsMaximized{ false };
            	bool mMouseLeftButtonPressed{ false };
            	QPushButton* mBtnClose{ nullptr };
            	QPushButton* mBtnMaximize{ nullptr };
            	QPushButton* mBtnMinimize{ nullptr };
            	enum class MoveType
            	{
            		NO_TYPE,
            		NO_WIDGET,
            		WIDGET_MOVING,
            		WIDGET_LEFT_HORISONTAL_RESIZE,
            		WIDGET_RIGHT_HORISONTAL_RESIZE,
            		WIDGET_TOP_VERTICAL_RESIZE,
            		WIDGET_BOTTOM_VERTICAL_RESIZE,
            		WIDGET_FULL_RESIZE_RIGHT_TOP,
            		WIDGET_FULL_RESIZE_LEFT_BOTTOM,
            		WIDGET_FULL_RESIZE_LEFT_TOP,
            		WIDGET_FULL_RESIZE_RIGHT_BOTTOM
            	};
            	MoveType mMoveType{ MoveType::WIDGET_MOVING };
            
            	int mHMargin{ 5 };
            	int mVMargin{ 5 };
            	int mFMargin{ 15 };
            };
            
            
            

            qt_form_color_test.cpp

            #include "qt_form_color_test.h"
            #include <QLayout>
            #include <QPainter>
            #include <QPaintEvent>
            #include <QTextEdit>
            #include <QDebug>
            #include <QPainterPath>
            #include <QEvent>
            #include <math.h>
            #include <QApplication>
            
            QtFormColorTest::QtFormColorTest(QWidget* parent)
            	: QWidget(parent)
            {
            	this->setAttribute(Qt::WA_TranslucentBackground);
            	this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
            	this->setStyleSheet(
            		R"(
            			border-radius: 10px;
            			padding: 5px;
            		)");
            	setMouseTracking(true);
            	setCursor(Qt::OpenHandCursor);
            	resize(640, 480);
            	this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
            
            	mBtnClose = new QPushButton("✕", this);
            	mBtnMaximize = new QPushButton("🗖", this);
            	mBtnMinimize = new QPushButton("🗕", this);
            	mBtnClose->setCursor(Qt::CursorShape::ArrowCursor);
            	mBtnMaximize->setCursor(Qt::CursorShape::ArrowCursor);
            	mBtnMinimize->setCursor(Qt::CursorShape::ArrowCursor);
            	mBtnClose->setMaximumSize(mBtnClose->height(), mBtnClose->height());
            	mBtnMaximize->setMaximumSize(mBtnMaximize->height(), mBtnMaximize->height());
            	mBtnMinimize->setMaximumSize(mBtnMinimize->height(), mBtnMinimize->height());
            	mBtnClose->setStyleSheet(
            		R"(
            			QPushButton:!hover
            			{
            				background-color: rgba(90, 90, 90, 1);
            				color: white;
            				border-width: 1px;
            				border-radius: 10px;
            				border-color: rgba(90, 90, 90, 1);
            				font: bold;
            				font-family: Times New Roman;
            				font-size: 14;
            				padding: 5px;
            			}
            			QPushButton:hover
            			{
            				background-color: red;
            				color: white;
            				border-width: 1px;
            				border-radius: 10px;
            				border-color: rgba(90, 90, 90, 1);
            				font: bold;
            				font-family: Times New Roman;
            				font-size: 14;
            				padding: 5px;
            			}
            		)");
            
            	mBtnMaximize->setStyleSheet(
            		R"(
            			QPushButton:!hover
            			{
            				background-color: rgba(90, 90, 90, 1);
            				color: white;
            				border-width: 1px;
            				border-radius: 10px;
            				border-color: rgba(90, 90, 90, 1);
            				font: bold;
            				font-family: Times New Roman;
            				font-size: 14;
            				padding: 5px;
            			}
            			QPushButton:hover
            			{
            				background-color: rgba(60, 60, 60, 1);
            				color: white;
            				border-width: 1px;
            				border-radius: 10px;
            				border-color: rgba(90, 90, 90, 1);
            				font: bold;
            				font-family: Times New Roman;
            				font-size: 14;
            				padding: 5px;
            			}
            		)");
            	mBtnMinimize->setStyleSheet(mBtnMaximize->styleSheet());
            
            	QTextEdit* text_edit = new QTextEdit(this);
            	text_edit->setFont(QFont("Times New Roman", 14));
            	text_edit->setStyleSheet(
            		R"(
            			background-color: rgba(60, 60, 60, 1);
            			color: white;
            		)");
            	QVBoxLayout* main_vbox = new QVBoxLayout(this);
            	QHBoxLayout* hbox_system_btns = new QHBoxLayout;
            	hbox_system_btns->addStretch(1);
            	hbox_system_btns->addWidget(mBtnMinimize);
            	hbox_system_btns->addWidget(mBtnMaximize);
            	hbox_system_btns->addWidget(mBtnClose);
            	main_vbox->addLayout(hbox_system_btns);
            	main_vbox->addStretch(1);
            	main_vbox->addWidget(text_edit);
            
            	setLayout(main_vbox);
            
            	auto maximize = [=]() -> void
            	{
            		if (!mIsMaximized)
            		{
            			this->showMaximized();
            			mIsMaximized = true;
            		}
            		else
            		{
            			this->showNormal();
            			mIsMaximized = false;
            		}
            	};
            
            	connect(mBtnClose, &QPushButton::clicked, qApp, QApplication::quit);
            	connect(mBtnMaximize, &QPushButton::clicked, this, maximize);
            	connect(mBtnMinimize, &QPushButton::clicked, this, &QMainWindow::showMinimized);
            
            	auto closePressed = [=]() -> void
            	{
            		mBtnClose->setStyleSheet(
            			R"(
            			background-color: red;
            			color: white;
            			border-width: 1px;
            			border-radius: 10px;
            			border-color: rgba(60, 60, 60, 1);
            			font: bold;
            			font-family: Times New Roman;
            			font-size: 14;
            			padding: 5px;
            			)");
            	};
            }
            
            QtFormColorTest::~QtFormColorTest()
            {}
            
            void QtFormColorTest::paintEvent(QPaintEvent* event)
            {
            	QPainter painter(this);
            	painter.setRenderHint(QPainter::Antialiasing);
            	QPainterPath rounded_rect;
            	rounded_rect.addRoundedRect(this->rect(), 10, 10);
            	painter.fillPath(rounded_rect, QColor(0, 0, 0, 60));
            	painter.end();
            }
            
            void QtFormColorTest::mousePressEvent(QMouseEvent* event)
            {
            	if (event->button() == Qt::LeftButton &&
            		event->modifiers() == Qt::NoModifier)
            	{
            		mMouseLeftButtonPressed = true;
            		mGlobalPos = event->globalPos();
            		if (mMoveType == MoveType::WIDGET_MOVING)
            			setCursor(Qt::CursorShape::ClosedHandCursor);
            		return;
            	}
            	QWidget::mousePressEvent(event);
            }
            
            void QtFormColorTest::mouseMoveEvent(QMouseEvent* event)
            {
            	if (!mMouseLeftButtonPressed || mMoveType == MoveType::NO_TYPE)
            	{
            		// Loock for the arrow types to move or resize widget
            		mLocalPos = QPoint(this->cursor().pos().x() - this->x(), this->cursor().pos().y() - this->y());
            		if ((mMoveType != MoveType::NO_WIDGET || mMoveType == MoveType::NO_TYPE) && (mLocalPos.x() < 0 || mLocalPos.x() > width() || mLocalPos.y() < 0 || mLocalPos.y() > height()))
            		{
            			setCursor(Qt::CursorShape::ArrowCursor);
            			mMoveType = MoveType::NO_WIDGET;
            			//qDebug() << "no widget";
            		}
            		else if ((mMoveType != MoveType::WIDGET_FULL_RESIZE_LEFT_TOP || mMoveType == MoveType::NO_TYPE) && (mLocalPos.x() <= mFMargin && mLocalPos.y() <= mFMargin) && (mLocalPos.x() > 0 && mLocalPos.y() > 0))
            		{
            			setCursor(Qt::CursorShape::SizeFDiagCursor);
            			mMoveType = MoveType::WIDGET_FULL_RESIZE_LEFT_TOP;
            			//qDebug() << "full resize left top";
            		}
            		else if ((mMoveType != MoveType::WIDGET_FULL_RESIZE_RIGHT_BOTTOM || mMoveType == MoveType::NO_TYPE) && (mLocalPos.x() >= width() - mFMargin && mLocalPos.y() >= height() - mFMargin) && (mLocalPos.x() < width() && mLocalPos.y() < height()))
            		{
            			setCursor(Qt::CursorShape::SizeFDiagCursor);
            			mMoveType = MoveType::WIDGET_FULL_RESIZE_RIGHT_BOTTOM;
            			//qDebug() << "full resize right bottom";
            		}
            		else if ((mMoveType != MoveType::WIDGET_FULL_RESIZE_LEFT_BOTTOM || mMoveType == MoveType::NO_TYPE) && (mLocalPos.x() <= mFMargin && mLocalPos.y() >= height() - mFMargin) && (mLocalPos.x() > 0 && mLocalPos.y() < height()))
            		{
            			setCursor(Qt::CursorShape::SizeBDiagCursor);
            			mMoveType = MoveType::WIDGET_FULL_RESIZE_LEFT_BOTTOM;
            			//qDebug() << "full resize left bottom";
            		}
            		else if ((mMoveType != MoveType::WIDGET_FULL_RESIZE_RIGHT_TOP || mMoveType == MoveType::NO_TYPE) && (mLocalPos.x() >= width() - mFMargin && mLocalPos.y() <= mFMargin) && (mLocalPos.x() < width() && mLocalPos.y() > 0))
            		{
            			setCursor(Qt::CursorShape::SizeBDiagCursor);
            			mMoveType = MoveType::WIDGET_FULL_RESIZE_RIGHT_TOP;
            			//qDebug() << "full resize right top";
            		}
            		else if ((mMoveType != MoveType::WIDGET_LEFT_HORISONTAL_RESIZE || mMoveType == MoveType::NO_TYPE) && mLocalPos.x() <= mHMargin && mLocalPos.x() > 0)
            		{
            			setCursor(Qt::CursorShape::SizeHorCursor);
            			mMoveType = MoveType::WIDGET_LEFT_HORISONTAL_RESIZE;
            			//qDebug() << "horisontal left";
            		}
            		else if ((mMoveType != MoveType::WIDGET_RIGHT_HORISONTAL_RESIZE || mMoveType == MoveType::NO_TYPE) && mLocalPos.x() >= width() - mHMargin && mLocalPos.x() < width())
            		{
            			setCursor(Qt::CursorShape::SizeHorCursor);
            			mMoveType = MoveType::WIDGET_RIGHT_HORISONTAL_RESIZE;
            			//qDebug() << "horisontal right";
            		}
            		else if ((mMoveType != MoveType::WIDGET_TOP_VERTICAL_RESIZE || mMoveType == MoveType::NO_TYPE) && mLocalPos.y() <= mVMargin && mLocalPos.y() > 0)
            		{
            			setCursor(Qt::CursorShape::SizeVerCursor);
            			mMoveType = MoveType::WIDGET_TOP_VERTICAL_RESIZE;
            			//qDebug() << "vertical top";
            		}
            		else if ((mMoveType != MoveType::WIDGET_BOTTOM_VERTICAL_RESIZE || mMoveType == MoveType::NO_TYPE) && mLocalPos.y() >= height() - mVMargin && mLocalPos.y() < height())
            		{
            			setCursor(Qt::CursorShape::SizeVerCursor);
            			mMoveType = MoveType::WIDGET_BOTTOM_VERTICAL_RESIZE;
            			//qDebug() << "vertical bottom";
            		}
            		else if ((mMoveType != MoveType::WIDGET_MOVING || mMoveType == MoveType::NO_TYPE) && mLocalPos.x() > std::max(mHMargin, mFMargin) && mLocalPos.x() < width() - std::max(mHMargin, mFMargin)
            			&& mLocalPos.y() > std::max(mVMargin, mFMargin) && mLocalPos.y() < height() - std::max(mVMargin, mFMargin))
            		{
            			setCursor(Qt::OpenHandCursor);
            			mMoveType = MoveType::WIDGET_MOVING;
            			//qDebug() << "moving";
            		}
            	}
            	else
            	{
            		if (mGlobalPos == mInvalidPoint)
            			return QWidget::mouseMoveEvent(event);
            		const QPoint delta = event->globalPos() - mGlobalPos;
            		switch (mMoveType)
            		{
            		case MoveType::NO_TYPE:
            			return;
            		case MoveType::NO_WIDGET:
            			return;
            		case MoveType::WIDGET_MOVING:
            			move(pos() + delta);
            			mGlobalPos = event->globalPos();
            			break;
            		case MoveType::WIDGET_LEFT_HORISONTAL_RESIZE:
            			resize(width() - delta.x(), height());
            			move(pos() + QPoint(delta.x(), 0));
            			mGlobalPos = event->globalPos();
            			break;
            		case MoveType::WIDGET_RIGHT_HORISONTAL_RESIZE:
            			resize(width() + delta.x(), height());
            			mGlobalPos = event->globalPos();
            			break;
            		case MoveType::WIDGET_TOP_VERTICAL_RESIZE:
            			resize(width(), height() - delta.y());
            			move(pos() + QPoint(0, delta.y()));
            			mGlobalPos = event->globalPos();
            			break;
            		case MoveType::WIDGET_BOTTOM_VERTICAL_RESIZE:
            			resize(width(), height()+delta.y());
            			mGlobalPos = event->globalPos();
            			break;
            		case MoveType::WIDGET_FULL_RESIZE_RIGHT_TOP:
            			resize(width()+delta.x(), height() - delta.y());
            			move(pos() + QPoint(0, delta.y()));
            			mGlobalPos = event->globalPos();
            			break;
            		case MoveType::WIDGET_FULL_RESIZE_LEFT_BOTTOM:
            			resize(width() - delta.x(), height() + delta.y());
            			move(pos() + QPoint(delta.x(), 0));
            			mGlobalPos = event->globalPos();
            			break;
            		case MoveType::WIDGET_FULL_RESIZE_LEFT_TOP:
            			resize(width() - delta.x(), height() - delta.y());
            			move(pos() + QPoint(delta.x(), delta.y()));
            			mGlobalPos = event->globalPos();
            			break;
            		case MoveType::WIDGET_FULL_RESIZE_RIGHT_BOTTOM:
            			resize(width() + delta.x(), height() + delta.y());
            			mGlobalPos = event->globalPos();
            			break;
            		default:
            			return;
            		}
            	}
            }
            
            void QtFormColorTest::mouseReleaseEvent(QMouseEvent* event)
            {
            	
            	mGlobalPos = mInvalidPoint;
            	if(mMouseLeftButtonPressed && mMoveType==MoveType::WIDGET_MOVING)
            		setCursor(Qt::OpenHandCursor);
            	mMouseLeftButtonPressed = false;
            	QWidget::mouseReleaseEvent(event);
            }
            
            void QtFormColorTest::resizeEvent(QResizeEvent* event)
            {
            	repaint();
            }
            
            

            OS: MS Windows 10 x64, IDE: MSVS 2022, Qt6.4.1 with qmake compiller
            Thank you.

            1 Reply Last reply
            0
            • Axel SpoerlA Offline
              Axel SpoerlA Offline
              Axel Spoerl
              Moderators
              wrote on last edited by
              #5

              I can observe gentle jittering on Windows 11 and Linux/X11 with Qt 6.4
              What smoothens it out almost entirely for me is to completely drop the resizeEventoverride.
              The benchmark is how other windows on the desktop jitter when being resized.
              That behavior depends on multiple factors, including CPU/GPU power and usage, screen size and memory.
              Difficult to pin that to a problem in the Qt code base.
              Sorry for replying late and without a solution...

              Software Engineer
              The Qt Company, Oslo

              FinchiF 1 Reply Last reply
              1
              • Axel SpoerlA Axel Spoerl

                I can observe gentle jittering on Windows 11 and Linux/X11 with Qt 6.4
                What smoothens it out almost entirely for me is to completely drop the resizeEventoverride.
                The benchmark is how other windows on the desktop jitter when being resized.
                That behavior depends on multiple factors, including CPU/GPU power and usage, screen size and memory.
                Difficult to pin that to a problem in the Qt code base.
                Sorry for replying late and without a solution...

                FinchiF Offline
                FinchiF Offline
                Finchi
                wrote on last edited by
                #6

                @Axel-Spoerl Thanks for the answer, other windows do not jittering at all, even the similar code is implemented on QML, I just wanted to make sure that I am doing everything correctly in terms of programming on Qt.
                Thank you.

                FinchiF 1 Reply Last reply
                0
                • FinchiF Finchi

                  @Axel-Spoerl Thanks for the answer, other windows do not jittering at all, even the similar code is implemented on QML, I just wanted to make sure that I am doing everything correctly in terms of programming on Qt.
                  Thank you.

                  FinchiF Offline
                  FinchiF Offline
                  Finchi
                  wrote on last edited by
                  #7

                  @Finchi

                  After some time, I returned to this problem and the best thing I could think of was to make a special transparent widget on top of the main one to resize the main one without visual artifacts.
                  For those who are interested, here is the link to github
                  Perhaps this code will be useful to those who have a similar problem.

                  1 Reply Last reply
                  0
                  • FinchiF Finchi has marked this topic as solved on

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved