2025, Oct 03 17:33
PyQt5 में लेआउट alignment बनाम setAlignment: लेबल को बीच में लाने की सही तकनीक
PyQt5 में QLabel नीचे क्यों अटका रहता है और उसे विंडो के बीच में सही तरह से कैसे रखें। VBoxLayout, addStretch, AlignHCenter के साथ उपयोगी कोड व टिप्स।
PyQt5 लेआउट में किसी विजेट को केंद्र में रखना उलझाऊ हो सकता है, खासकर तब जब आप लेआउट-स्तर के alignment और विजेट-स्तर के alignment कॉल्स को मिला देते हैं। एक आम स्थिति यह होती है: QVBoxLayout में लेबल को AlignBottom के साथ जोड़ा गया, फिर बाकी विजेट छिपा दिए, और लेबल जिद करके नीचे ही टिका रहता है। मकसद है कि बटन क्लिक होने के बाद लेबल पेज के बीच में आ जाए।
समस्या का सेटअप
नीचे guessing game का एक न्यूनतम संस्करण है, जिसमें बटन दबाने के बाद भी लेबल नीचे ही रहता है, जबकि हम उसे दोबारा align करने की कोशिश करते हैं:
import sys
import time
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class AppWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        QFontDatabase.addApplicationFont("fonts\Evangelie.ttf")
        QFontDatabase.addApplicationFont("fonts\Bebas_Neue_Cyrillic.ttf")
        QFontDatabase.addApplicationFont("fonts\MontserratAlternates-Medium.ttf")
        QFontDatabase.addApplicationFont("fonts\MontserratAlternates-Bold.ttf")
        QFontDatabase.addApplicationFont("fonts\MontserratAlternates-SemiBold.ttf")
        self.msg_label = QLabel("Скільки чулувіків має крапка?", self)
        self.input_field = QLineEdit(self)
        self.submit_btn = QPushButton("Відповісти.", self)
        self.build_ui()
    def build_ui(self):
        host = QWidget()
        self.setCentralWidget(host)
        self.setWindowTitle("Guess.")
        self.resize(800, 700)
        self.setStyleSheet("background-color: #697565;")
        self.msg_label.setFont(QFont("Montserrat Alternates SemiBold", 24))
        self.msg_label.adjustSize()
        self.msg_label.setStyleSheet(
            "margin: 0, 20, 0, 0;"
            "color: #ECDFCC;"
            "font-style: bold;"
        )
        self.input_field.setFixedSize(200, 80)
        self.input_field.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.input_field.setFont(QFont("Montserrat Alternates SemiBold", 20))
        self.input_field.setStyleSheet(
            "background-color: #181C14;"
            "color: #697565;"
            "border-radius: 15px;"
            "margin: 0,20,0,0;"
        )
        self.submit_btn.setStyleSheet(
            "border-radius:15px;"
            "background-color: #ECDFCC;"
            "color: #181C14;"
        )
        self.submit_btn.setFixedSize(150, 50)
        self.submit_btn.setFont(QFont("Montserrat Alternates Medium", 10))
        self.submit_btn.clicked.connect(self.handle_click)
        layout_main = QVBoxLayout()
        layout_main.addWidget(self.msg_label, alignment=Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignJustify)
        layout_main.addWidget(self.input_field, alignment=Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignJustify)
        layout_main.addWidget(self.submit_btn, alignment=Qt.AlignmentFlag.AlignJustify | Qt.AlignmentFlag.AlignTop)
        host.setLayout(layout_main)
    def handle_click(self):
        self._user_value = self.input_field.text()
        print(self._user_value)
        if self._user_value == '0':
            self.msg_label.setText("You won!")
            self.input_field.hide()
            self.submit_btn.hide()
            self.msg_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
    def center_window(self):
        frame_geo = self.frameGeometry()
        screen_center = QDesktopWidget().availableGeometry().center()
        frame_geo.moveCenter(screen_center)
        self.move(frame_geo.topLeft())
def main():
    app = QApplication(sys.argv)
    ui = AppWindow()
    ui.show()
    sys.exit(app.exec_())
if __name__ == "__main__":
    main()लेबल बीच में क्यों नहीं आ रहा
वर्टिकल प्लेसमेंट उस alignment से तय होती है जो विजेट को लेआउट में जोड़ते समय दी गई थी। लेबल को AlignBottom के साथ जोड़ा गया था, इसलिए उसका वर्टिकल स्लॉट नीचे के पास बना रहता है। लेबल पर setAlignment() कॉल करने से लेआउट में उसकी स्थिति नहीं बदलती; यह केवल लेबल की सामग्री के alignment को प्रभावित करता है।
समाधान: स्टैक को सेंटर करने के लिए stretches का उपयोग करें
बटन दबाने के बाद लेबल को विंडो के बीच में लाने के लिए, विजेट स्टैक के ऊपर और नीचे लचीली जगह रखें। QVBoxLayout में addStretch() फैलने वाली खाली जगह बनाता है। विजेट्स से पहले और बाद में एक-एक stretch जोड़ने से सामग्री वर्टिकली बीच में रहती है। इसके बाद, आपको बस क्षैतिज alignment सेट करना होता है।
import sys
import time
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class AppWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        QFontDatabase.addApplicationFont("fonts\Evangelie.ttf")
        QFontDatabase.addApplicationFont("fonts\Bebas_Neue_Cyrillic.ttf")
        QFontDatabase.addApplicationFont("fonts\MontserratAlternates-Medium.ttf")
        QFontDatabase.addApplicationFont("fonts\MontserratAlternates-Bold.ttf")
        QFontDatabase.addApplicationFont("fonts\MontserratAlternates-SemiBold.ttf")
        self.msg_label = QLabel("Скільки чулувіків має крапка?", self)
        self.input_field = QLineEdit(self)
        self.submit_btn = QPushButton("Відповісти.", self)
        self.build_ui()
    def build_ui(self):
        host = QWidget()
        self.setCentralWidget(host)
        self.setWindowTitle("Guess.")
        self.resize(800, 700)
        self.setStyleSheet("background-color: #697565;")
        self.msg_label.setFont(QFont("Montserrat Alternates SemiBold", 24))
        self.msg_label.adjustSize()
        self.msg_label.setStyleSheet(
            "margin: 0, 20, 0, 0;"
            "color: #ECDFCC;"
            "font-style: bold;"
        )
        self.input_field.setFixedSize(200, 80)
        self.input_field.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.input_field.setFont(QFont("Montserrat Alternates SemiBold", 20))
        self.input_field.setStyleSheet(
            "background-color: #181C14;"
            "color: #697565;"
            "border-radius: 15px;"
            "margin: 0,20,0,0;"
        )
        self.submit_btn.setStyleSheet(
            "border-radius:15px;"
            "background-color: #ECDFCC;"
            "color: #181C14;"
        )
        self.submit_btn.setFixedSize(150, 50)
        self.submit_btn.setFont(QFont("Montserrat Alternates Medium", 10))
        self.submit_btn.clicked.connect(self.handle_click)
        layout_main = QVBoxLayout()
        layout_main.addStretch()
        layout_main.addWidget(self.msg_label, alignment=Qt.AlignmentFlag.AlignHCenter)
        layout_main.addWidget(self.input_field, alignment=Qt.AlignmentFlag.AlignHCenter)
        layout_main.addWidget(self.submit_btn, alignment=Qt.AlignmentFlag.AlignHCenter)
        layout_main.addStretch()
        host.setLayout(layout_main)
    def handle_click(self):
        self._user_value = self.input_field.text()
        print(self._user_value)
        if self._user_value == '0':
            self.msg_label.setText("You won!")
            self.input_field.hide()
            self.submit_btn.hide()
            self.msg_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
    def center_window(self):
        frame_geo = self.frameGeometry()
        screen_center = QDesktopWidget().availableGeometry().center()
        frame_geo.moveCenter(screen_center)
        self.move(frame_geo.topLeft())
def main():
    app = QApplication(sys.argv)
    ui = AppWindow()
    ui.show()
    sys.exit(app.exec_())
if __name__ == "__main__":
    main()यह जानना क्यों महत्वपूर्ण है
हल्के-से लेआउट फ्लैग भी UI के अप्रत्याशित व्यवहार का कारण बन सकते हैं। addStretch() के साथ ऊर्ध्वाधर संतुलन बनाए रखकर और प्रति-विजेट साधारण क्षैतिज alignment उपयोग करके, आप बाद में लेआउट सिस्टम से लड़ने से बचते हैं—खासकर जब कंट्रोल्स को डायनेमिक रूप से दिखाना या छिपाना हो। साथ ही, Python स्ट्रिंग्स के लिए एक व्यावहारिक पाथ टिप याद रखें: एक सिंगल बैकस्लैश एक escape कैरेक्टर होता है। यदि आप पाथ में बैकस्लैश चुनते हैं, तो डबल बैकस्लैश या raw strings का उपयोग करें; वरना, फॉरवर्ड स्लैश Qt द्वारा व्यापक रूप से स्वीकार किए जाते हैं और क्रॉस-प्लैटफ़ॉर्म फ्रेंडली हैं।
निष्कर्ष
जब आप चाहते हैं कि UI बदलने के बाद कोई विजेट बीच में आ जाए, तो केवल विजेट-स्तर के alignment से उसे मजबूर न करें। लेआउट को काम करने दें: वर्टिकल सेंटरिंग के लिए अपनी सामग्री को stretches से घेरें और प्रति-विजेट AlignHCenter जैसे सरल alignment रखें। यह पैटर्न तब भी इंटरफेस को पूर्वानुमेय बनाए रखता है जब तत्व छिपाए, दिखाए या बदले जाते हैं।