0

I am trying to figure out how to create a custom expanding widget that is totally resizable, but with the ability of being able to freely place labels and buttons without the constraints of layouts.

here is a rough idea of what i would like to achieve:

enter image description here

The idea is I would use a QGroupBox with some kind of title set, inside it will be a layout of some kind to ensure the contents inside can be resized when the QGroupBox is resized, with a custom button with the image of an arrow placed ontop in the corner of the QGroupBox that totally ignores the layout of the QGroupBox. which means that the QGroupBox has to be contained in an area without a layout. unfortunately what this means is the QGroupBox will no longer be "resizable" because it is not following a layout. So i want to know how to do this.

so far I have this code:

from PyQt4 import QtCore, QtGui
import sys

class Window(QtGui.QWidget):
    resized = QtCore.pyqtSignal()
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.setWindowTitle('Test UI')
        self.setMinimumSize(75, 50)
        #self.setMaximumSize(250, 500)
        self.oldWidth = 0.0
        self.oldHeight = 0.0
        self.oldButtonPosX = 0.0
        self.oldButtonPosY = 0.0
        self.resized.connect(self.someFunction)
        position = QtGui.QCursor.pos()
        self.move(position)
        self.uiWidget = QtGui.QWidget()

        self.freeWidget = QtGui.QWidget(self.uiWidget)
        self.verticalLayout = QtGui.QVBoxLayout(self.freeWidget)

        self.exportPushButton = QtGui.QPushButton(self.freeWidget)
        self.exportPushButton.setText('Export')
        self.verticalLayout.addWidget(self.exportPushButton)

        self.exportPushButton2 = QtGui.QPushButton(self.freeWidget)
        self.exportPushButton2.setText('Export')
        self.verticalLayout.addWidget(self.exportPushButton2)

        self.testButton = QtGui.QPushButton(self.uiWidget)
        self.testButton.setText('.')
        self.testButton.setGeometry(5,5,20,20)

        #self.testButton = QtGui.QPushButton(self.uiWidget)



        self.lyt = QtGui.QVBoxLayout()
        self.lyt.addWidget(self.uiWidget)

        self.setLayout(self.lyt)

        #self.oldWidth = self.width()
        #self.oldHeight = self.height()

    def resizeEvent(self, event):
        self.resized.emit()
        self.oldWidth = self.width()
        self.oldHeight = self.height()
        self.oldButtonPosX = self.testButton.x()
        self.oldButtonPosY = self.testButton.y()
        return QtGui.QWidget.resizeEvent(self, event)

    def someFunction(self):
        newWidth = self.width() - 20.0
        newHeight = self.height() - 20.0
        self.freeWidget.setGeometry(0,0,newWidth,newHeight)
        newButtonX = self.oldButtonPosX + (self.oldWidth - newWidth)
        print self.oldButtonPosX
        print 'self.oldWidth: %s' %self.oldWidth
        print 'newWidth: %s' %newWidth
        value = self.oldWidth-newWidth
        print 'difference: %s' %str(value)
        newButtonY = 20 + (self.oldHeight - newHeight)
        #self.freeWidget.setGeometry(self.geometry)
        #print 'Resizing label'
        #
        if self.oldButtonPosX != 0.0:
            self.testButton.setGeometry(newButtonX,newButtonY,20,20)

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

By incorporating this custom "resized" function I read about in another thread (and not setting a parent), the resizing of a widget itself seems possible without the need of it being in a Layout, but now I face an issue where the button that I want to overlay stays in its original position. WHat I would like it to do is follow with a widget while resizing, but also not necessarily having it contained in that widget's layout (you can see I sort have been finnicking to get this effect)

How can I achieve this?

UPDATE:

So I've managed to sort of figure out how the interactive resize/scaling works. Basically the widget's position increments 1 pixel depending on how many widgets are in a single layout. So I tried to replicate this effect (i have two widgets in this test layout, so in theory it should take a pixel change of 3 for the overlaying button to increment one pixel in position). it works somewhat, but I am noticing now that if i move the mouse too fast when dragging, the resize does not keep up, and in turn causes a misalignment. How do i go about this issue...?

from PyQt4 import QtCore, QtGui
import sys

#https://stackoverflow.com/questions/43126721/pyqt-detect-resizing-in-widget-window-resized-signal?rq=1

class Window(QtGui.QWidget):
    resized = QtCore.pyqtSignal()
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.setWindowTitle('Test UI')
        self.setMinimumSize(100, 100)
        #self.setMaximumSize(250, 500)
        self.oldWidth = 0.0
        self.oldHeight = 0.0
        self.getOriginalDimensions = False
        self.oldButtonPosX = 5.0
        self.oldButtonPosY = 5.0
        self.resized.connect(self.someFunction)
        position = QtGui.QCursor.pos()
        self.move(position)
        self.uiWidget = QtGui.QWidget()

        self.freeWidget = QtGui.QWidget(self.uiWidget)
        self.verticalLayout = QtGui.QVBoxLayout(self.freeWidget)

        self.exportPushButton = QtGui.QPushButton(self.freeWidget)
        self.exportPushButton.setText('ExportV')
        self.verticalLayout.addWidget(self.exportPushButton)

        self.exportPushButton2 = QtGui.QPushButton(self.freeWidget)
        self.exportPushButton2.setText('Export')
        self.verticalLayout.addWidget(self.exportPushButton2)

        self.testButton = QtGui.QPushButton(self.uiWidget)
        self.testButton.setText('.')
        self.testButton.setGeometry(5,5,20,20)

        #self.testButton = QtGui.QPushButton(self.uiWidget)



        self.lyt = QtGui.QVBoxLayout()
        self.lyt.addWidget(self.uiWidget)

        self.setLayout(self.lyt)

        self.buttonYDifference = 0

        #self.oldWidth = 100
        #self.oldHeight = 100

    def resizeEvent(self, event):
        self.resized.emit()
        #self.oldWidth = self.width()
        #self.oldHeight = self.height()
        self.oldButtonPosX = self.testButton.x()
        self.oldButtonPosY = self.testButton.y()
        if self.getOriginalDimensions:
            self.oldWidth = self.width()
            self.oldHeight = self.height()
        return QtGui.QWidget.resizeEvent(self, event)

    def someFunction(self):
        if not self.getOriginalDimensions:
            self.oldWidth = self.width()
            self.oldHeight = self.height()
            self.getOriginalDimensions = True
        newWidth = self.width() - 20.0
        newHeight = self.height() - 20.0
        self.freeWidget.setGeometry(0,0,newWidth,newHeight)
        #newButtonX = self.oldButtonPosX + ((self.width() - self.oldWidth))
        yDifference = self.oldHeight - self.height()
        print self.buttonYDifference
        if self.buttonYDifference <= 3 and self.buttonYDifference >= -3:
            if yDifference == 1:
                self.buttonYDifference +=1
            elif yDifference == -1:
                self.buttonYDifference -=1
        else:
            newButtonY = self.oldButtonPosY - self.buttonYDifference
            self.testButton.setGeometry(self.oldButtonPosX,newButtonY,20,20)
            self.buttonYDifference = 0

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())
user3696118
  • 343
  • 3
  • 17
  • I did not understand why you can not use QGroupBox. Could you explain please? – eyllanesc Mar 31 '18 at 20:10
  • im not sure what you mean by that question, I can use QGroupBox, I just cannot have it contained/parented in a layout so that I can overlay a push button ontop of it (for a collapse/expand button to reveal/hide the QGroupBox widget) – user3696118 Mar 31 '18 at 20:15

0 Answers0