Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to resize a window from the edges after adding the property QtCore.Qt.FramelessWindowHint

Good night. I have seen some programs with new borderless designs and still you can make use of resizing. At the moment I know that to remove the borders of a pyqt program we use: QtCore.Qt.FramelessWindowHint

And that to change the size of a window use QSizeGrip. But how can we resize a window without borders?

This is the code that I use to remove the border of a window but after that I have not found information on how to do it in pyqt5. I hope you can help me with an example of how to solve this problem

from PyQt5.QtWidgets import QMainWindow,QApplication
from PyQt5 import  QtCore

class Main(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)


        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)


app = QApplication([])
m = Main()
m.show()
m.resize(800,600)
app.exec_()
like image 818
Angel Judath Alvarez Avatar asked Oct 20 '25 02:10

Angel Judath Alvarez


1 Answers

If you use a QMainWindow you can add a QStatusBar (which automatically adds a QSizeGrip) just by calling statusBar():

This function creates and returns an empty status bar if the status bar does not exist.

Otherwise, you can manually add grips, and their interaction is done automatically based on their position. In the following example I'm adding 4 grips, one for each corner, and then I move them each time the window is resized.

class Main(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)

        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        self.gripSize = 16
        self.grips = []
        for i in range(4):
            grip = QSizeGrip(self)
            grip.resize(self.gripSize, self.gripSize)
            self.grips.append(grip)

    def resizeEvent(self, event):
        QMainWindow.resizeEvent(self, event)
        rect = self.rect()
        # top left grip doesn't need to be moved...
        # top right
        self.grips[1].move(rect.right() - self.gripSize, 0)
        # bottom right
        self.grips[2].move(
            rect.right() - self.gripSize, rect.bottom() - self.gripSize)
        # bottom left
        self.grips[3].move(0, rect.bottom() - self.gripSize)

UPDATE

Based on comments, also side-resizing is required. To do so a good solution is to create a custom widget that behaves similarly to QSizeGrip, but for vertical/horizontal resizing only.

For better implementation I changed the code above, used a gripSize to construct an "inner" rectangle and, based on it, change the geometry of all widgets, for both corners and sides.

Here you can see the "outer" rectangle and the "inner" rectangle used for geometry computations:

Both rectangles highlighted

Then you can create all geometries, for QSizeGrip widgets (in light blue):

corner widgets geometries

And for custom side widgets:

side widgets geometries

from PyQt5 import QtCore, QtGui, QtWidgets

class SideGrip(QtWidgets.QWidget):
    def __init__(self, parent, edge):
        QtWidgets.QWidget.__init__(self, parent)
        if edge == QtCore.Qt.LeftEdge:
            self.setCursor(QtCore.Qt.SizeHorCursor)
            self.resizeFunc = self.resizeLeft
        elif edge == QtCore.Qt.TopEdge:
            self.setCursor(QtCore.Qt.SizeVerCursor)
            self.resizeFunc = self.resizeTop
        elif edge == QtCore.Qt.RightEdge:
            self.setCursor(QtCore.Qt.SizeHorCursor)
            self.resizeFunc = self.resizeRight
        else:
            self.setCursor(QtCore.Qt.SizeVerCursor)
            self.resizeFunc = self.resizeBottom
        self.mousePos = None

    def resizeLeft(self, delta):
        window = self.window()
        width = max(window.minimumWidth(), window.width() - delta.x())
        geo = window.geometry()
        geo.setLeft(geo.right() - width)
        window.setGeometry(geo)

    def resizeTop(self, delta):
        window = self.window()
        height = max(window.minimumHeight(), window.height() - delta.y())
        geo = window.geometry()
        geo.setTop(geo.bottom() - height)
        window.setGeometry(geo)

    def resizeRight(self, delta):
        window = self.window()
        width = max(window.minimumWidth(), window.width() + delta.x())
        window.resize(width, window.height())

    def resizeBottom(self, delta):
        window = self.window()
        height = max(window.minimumHeight(), window.height() + delta.y())
        window.resize(window.width(), height)

    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self.mousePos = event.pos()

    def mouseMoveEvent(self, event):
        if self.mousePos is not None:
            delta = event.pos() - self.mousePos
            self.resizeFunc(delta)

    def mouseReleaseEvent(self, event):
        self.mousePos = None


class Main(QtWidgets.QMainWindow):
    _gripSize = 8
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)

        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)

        self.sideGrips = [
            SideGrip(self, QtCore.Qt.LeftEdge), 
            SideGrip(self, QtCore.Qt.TopEdge), 
            SideGrip(self, QtCore.Qt.RightEdge), 
            SideGrip(self, QtCore.Qt.BottomEdge), 
        ]
        # corner grips should be "on top" of everything, otherwise the side grips
        # will take precedence on mouse events, so we are adding them *after*;
        # alternatively, widget.raise_() can be used
        self.cornerGrips = [QtWidgets.QSizeGrip(self) for i in range(4)]

    @property
    def gripSize(self):
        return self._gripSize

    def setGripSize(self, size):
        if size == self._gripSize:
            return
        self._gripSize = max(2, size)
        self.updateGrips()

    def updateGrips(self):
        self.setContentsMargins(*[self.gripSize] * 4)

        outRect = self.rect()
        # an "inner" rect used for reference to set the geometries of size grips
        inRect = outRect.adjusted(self.gripSize, self.gripSize,
            -self.gripSize, -self.gripSize)

        # top left
        self.cornerGrips[0].setGeometry(
            QtCore.QRect(outRect.topLeft(), inRect.topLeft()))
        # top right
        self.cornerGrips[1].setGeometry(
            QtCore.QRect(outRect.topRight(), inRect.topRight()).normalized())
        # bottom right
        self.cornerGrips[2].setGeometry(
            QtCore.QRect(inRect.bottomRight(), outRect.bottomRight()))
        # bottom left
        self.cornerGrips[3].setGeometry(
            QtCore.QRect(outRect.bottomLeft(), inRect.bottomLeft()).normalized())

        # left edge
        self.sideGrips[0].setGeometry(
            0, inRect.top(), self.gripSize, inRect.height())
        # top edge
        self.sideGrips[1].setGeometry(
            inRect.left(), 0, inRect.width(), self.gripSize)
        # right edge
        self.sideGrips[2].setGeometry(
            inRect.left() + inRect.width(), 
            inRect.top(), self.gripSize, inRect.height())
        # bottom edge
        self.sideGrips[3].setGeometry(
            self.gripSize, inRect.top() + inRect.height(), 
            inRect.width(), self.gripSize)

    def resizeEvent(self, event):
        QtWidgets.QMainWindow.resizeEvent(self, event)
        self.updateGrips()


app = QtWidgets.QApplication([])
m = Main()
m.show()
m.resize(240, 160)
app.exec_()
like image 154
musicamante Avatar answered Oct 22 '25 04:10

musicamante