Home > front end >  PyQt6 set position of input field and button
PyQt6 set position of input field and button

Time:07-01

I'm trying to create in PyQt6 an input field (location: bottom right of the window) and next to It on the right an "Enter" button (I'm using pg.GraphicView()). I can't use the PySide library because of some interaction problems with the rest of my code. How can I achieve that?

I'm using the following code for generating a button but I can't figure out how to place It at the bottom right of the current window:

view = pg.GraphicsView()
l = pg.GraphicsLayout()
view.setCentralItem(l)
view.show()

proxy = QGraphicsProxyWidget()
button = QPushButton("ENTER")
proxy.setWidget(button)

view.addItem(proxy)

Regarding the input field I tried to implement different things without using PySide but they didn't worked.

CodePudding user response:

The pg.GraphicsView class is actually a subclass of QGraphicsView, which is a standard QWidget that inherits from QAbstractScrollArea.

This means that we can potentially add any child widget to it without interfering with the contents of the scene and also ignoring possible transformations (scaling, rotation, etc.).

The solution, in fact, is quite simple: set the view as parent of the widget (either by using the view as argument in the constructor, or by calling setParent()). Then, what's left is to ensure that the widget geometry is always consistent with the view, so we need to wait for resize events and set the new geometry based on the new size. To achieve this, the simplest solution is to create a subclass.

For explanation purposes, I've implemented a system that allows to set widgets for any "corner" of the view, and defaults to the bottom right corner.

Note: since this question could also be valid for Qt5, in the following code I'm using the "old" enum style (Qt.Align...), for newer versions of Qt (and mandatory for PyQt6), you need to change to Qt.Alignment.Align....

class CustomGraphicsView(pg.GraphicsView):
    toolWidgets = None
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.toolWidgets = {}

    def setToolWidget(self, widget, position=Qt.AlignBottom|Qt.AlignRight):
        position = Qt.AlignmentFlag(position)
        current = self.toolWidgets.get(position)
        if current:
            current.deleteLater()
        self.toolWidgets[position] = widget

        widget.resize(widget.sizeHint())

        # ensure that the widget is reparented
        widget.setParent(self)

        # setParent() automatically hides widgets, we need to
        # explicitly call show()
        widget.show()

        self._updateToolWidgets()

    def _updateToolWidgets(self):
        if not self.toolWidgets:
            return
        viewGeo = self.rect()
        for pos, widget in self.toolWidgets.items():
            rect = widget.rect()
            if pos & Qt.AlignLeft:
                rect.moveLeft(0)
            elif pos & Qt.AlignRight:
                rect.moveRight(viewGeo.right())
            elif pos & Qt.AlignHCenter:
                rect.moveLeft(viewGeo.center().x() - rect.width() / 2)
            if pos & Qt.AlignTop:
                rect.moveTop(0)
            elif pos & Qt.AlignBottom:
                rect.moveBottom(viewGeo.bottom())
            elif pos & Qt.AlignVCenter:
                rect.moveTop(viewGeo.center().y() - rect.height() / 2)
            widget.setGeometry(rect)

    def resizeEvent(self, event):
        super().resizeEvent(event)
        self._updateToolWidgets()


# ...

view = CustomGraphicsView()
l = pg.GraphicsLayout()
view.setCentralItem(l)
view.show()

container = QFrame(autoFillBackground=True, objectName='container')
container.setStyleSheet('''
    QFrame#container {
        background: palette(window);
        border: 1px outset palette(mid); 
        border-radius: 2px;
    }
''')
lineEdit = QLineEdit()
button = QPushButton("ENTER")
frameLayout = QHBoxLayout(container)
frameLayout.setContentsMargins(0, 0, 0, 0)
frameLayout.addWidget(lineEdit)
frameLayout.addWidget(button)
view.setToolWidget(container)

bottomLeftButton = QPushButton('Something')
view.setToolWidget(bottomLeftButton, Qt.AlignLeft|Qt.AlignBottom)
  • Related