Zorobay
Zorobay

Reputation: 649

Centering QLabel inside layout

I'm trying to center a QLabel showing a pixmap inside a QWidget both horizontally and vertically, but for some reason, this seems impossible. I have read many similar questions, and it seems they all comes down to specifying the alignment when adding the label to the layout. Well, I'm doing that and still it's aligning to the top left corner. Can someone please help me center my darn QLabel already? :)

main.py

import sys
from PyQt5.QtWidgets import QApplication
from mainwindow import MainWindow

app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

mainwindow.py

from PyQt5.QtGui import QGuiApplication, QWheelEvent
from PyQt5.QtWidgets import QMainWindow
from imagewidget import ImageWidget


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.resize(QGuiApplication.primaryScreen().availableSize() * 3 / 5)

        self.image_widget = ImageWidget()
        self.setCentralWidget(self.image_widget)

    def wheelEvent(self, event: QWheelEvent) -> None:
        angleDelta = event.angleDelta().y()

        if angleDelta >= 0:
            self.image_widget.zoomIn()
        else:
            self.image_widget.zoomOut()

imagewidget.py

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QPalette
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QSizePolicy, QPushButton


class ImageWidget(QWidget):
    def __init__(self):
        super().__init__()

        self.scale_factor = 1.0
        self.label = QLabel()
        self.label.setAlignment(Qt.AlignVCenter)
        self.label.setPixmap(QPixmap("image.png"))  # Loads local test image
        self.label.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        self.label.setScaledContents(True)

        self.layout = QVBoxLayout()
        self.layout.addWidget(self.label, Qt.AlignCenter)  # Why does this not align the label to the center of the layout?
        self.setLayout(self.layout)

    def zoomIn(self):
        self.scale_factor *= 1.1
        self.resizeUsingScaleFactor()

    def zoomOut(self):
        self.scale_factor /= 1.1
        self.resizeUsingScaleFactor()

    def getImageSize(self):
        return self.label.pixmap().size()

    def resizeUsingScaleFactor(self):
        self.label.resize(self.getImageSize() * self.scale_factor)

Upvotes: 1

Views: 1648

Answers (1)

musicamante
musicamante

Reputation: 48543

When you resize a widget it doesn't adjust its position, it just resize it. All widgets set their geometry based on the origin point (the top left corner), if you use resize the origin point will always remain the same.

Since you are using a layout, you should leave the positioning to the layout (which you are also preventing since you're using the Ignore size policy, which is a problem in these cases. Also note that you are using the alignment as the second argument for addWidget, but its signature is addWidget(widget, stretch=0, alignment=Qt.Alignment()), so you should use the correct keyword.

The solution is to use setFixedSize instead, which will ensure that the layout takes care of the correct alignment once it has been notified about the new fixed size (which does not happen when you use resize).

class ImageWidget(QWidget):
    def __init__(self):
        super().__init__()

        self.scale_factor = 1.0
        self.label = QLabel()
        # no need for this
        # self.label.setAlignment(Qt.AlignCenter)
        # don't do this
        # self.label.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)

        self.label.setPixmap(QPixmap("image.png"))  # Loads local test image
        self.label.setScaledContents(True)

        self.layout = QVBoxLayout()
        self.layout.addWidget(self.label, alignment=Qt.AlignCenter)
        self.setLayout(self.layout)

    # ...

    def resizeUsingScaleFactor(self):
        self.label.setFixedSize(self.getImageSize() * self.scale_factor)


Upvotes: 2

Related Questions