Search code examples
pythonpyqtpyqt4qstackedwidget

Position internal widget inside QStackedWidget object


I have several tabs and inside the "admin" tab I want to display two pages: one locked page (before entering credentials) and another unlocked page (after successful login). To do this, I'm using a QStackedWidget() to switch between the two pages. I have created a locked login screen but can't seem to move the object to the center of the page.

I have looked at moving widgets inside QStackedWidget and centering widgets in the center of the screen but my objects do not seem to change position. I've tried to move the entire internal widget using move() to the center of the screen using the desktop dimension and the parent widget to no avail. How would I be able to move the login fields to the center of the page? Thanks!

Current: enter image description here

Desired: enter image description here

Code:

from PyQt4 import QtGui, QtCore
# from load_CSS import load_CSS
# from widgets import UniversalPlotWidget
import sys
import time

def exit_application():
    """Exit program event handler"""

    sys.exit(1)

class VerticalTabBar(QtGui.QTabBar):
    def __init__(self, width, height, parent=None):
        super(VerticalTabBar, self).__init__(parent)
        self.width = width
        self.height = height

    def tabSizeHint(self, index):
        return QtCore.QSize(self.width, self.height)

    def paintEvent(self, event):
        painter = QtGui.QStylePainter(self)
        tab_options = QtGui.QStyleOptionTab()

        for tab in range(self.count()):
            self.initStyleOption(tab_options, tab)
            painter.drawControl(QtGui.QStyle.CE_TabBarTabShape, tab_options)
            painter.save()

            size = tab_options.rect.size()
            size.transpose()
            rectangle = QtCore.QRect(QtCore.QPoint(), size)
            rectangle.moveCenter(tab_options.rect.center())
            tab_options.rect = rectangle

            center = self.tabRect(tab).center()
            painter.translate(center)
            painter.rotate(90)
            painter.translate(-center)
            painter.drawControl(QtGui.QStyle.CE_TabBarTabLabel, tab_options);
            painter.restore()

class TabWidget(QtGui.QTabWidget):
    def __init__(self, *args, **kwargs):
        QtGui.QTabWidget.__init__(self, *args, **kwargs)
        self.setTabBar(VerticalTabBar(kwargs.pop('width'), kwargs.pop('height')))
        self.setTabPosition(QtGui.QTabWidget.West)
        self.setTabShape(QtGui.QTabWidget.Rounded)

class AdminTabWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        super(AdminTabWidget, self).__init__(parent)
        self.setWindowModality(QtCore.Qt.ApplicationModal)
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        self.admin_page_locked_init()
        self.admin_page_unlocked_init()

        self.admin_page_layout = QtGui.QGridLayout()

        self.admin_page_switch = QtGui.QStackedWidget()
        self.admin_page_switch.addWidget(self.admin_locked_tab)
        self.admin_page_switch.addWidget(self.admin_unlocked_tab)
        self.admin_page_switch.setCurrentIndex(0)
        self.admin_page_layout.addWidget(self.admin_page_switch,0,0)

    def admin_page_locked_init(self):
        self.admin_locked_tab = QtGui.QWidget()
        self.admin_locked_tab.setFixedSize(550,225)
        self.admin_locked_layout = QtGui.QGridLayout()

        self.username_label = QtGui.QLabel('Username: ')
        self.username_field = QtGui.QLineEdit()
        self.username_field.returnPressed.connect(self.verify_credentials)
        self.space_label = QtGui.QLabel(' ')
        self.space_label.setFixedHeight(25)
        self.password_label = QtGui.QLabel('Password: ')
        self.password_field = QtGui.QLineEdit()
        self.password_field.returnPressed.connect(self.verify_credentials)
        self.password_field.setEchoMode(QtGui.QLineEdit.Password)

        self.verify_button = QtGui.QPushButton('Ok')
        self.verify_button.clicked.connect(self.verify_credentials)
        self.cancel_button = QtGui.QPushButton('Cancel')
        self.cancel_button.clicked.connect(self.unauthorized)

        self.status_label = QtGui.QLabel('')
        self.status_label.setAlignment(QtCore.Qt.AlignCenter)

        self.button_layout = QtGui.QGridLayout()
        self.button_layout.addWidget(self.verify_button,0,0,1,1)
        self.button_layout.addWidget(self.cancel_button,0,1,1,1)

        self.admin_locked_layout.addWidget(self.username_label,0,0,1,1)
        self.admin_locked_layout.addWidget(self.username_field,0,1,1,1)
        self.admin_locked_layout.addWidget(self.space_label,1,0,1,3)
        self.admin_locked_layout.addWidget(self.password_label,2,0,1,1)
        self.admin_locked_layout.addWidget(self.password_field,2,1,1,1)
        self.admin_locked_layout.addWidget(self.status_label,3,0,1,3)
        self.admin_locked_layout.addLayout(self.button_layout,4,0,1,3)

        self.admin_locked_tab.setLayout(self.admin_locked_layout)

    def verify_credentials(self):
        print('button pressed')
        # Grab username/password from input fields
        self.username = str(self.username_field.text())
        self.password = str(self.password_field.text())
        self.status_label.setText('Verifying')
        self.status_label.setStyleSheet('QLabel {color: rgb(117,255,161)}')
        self.spin(.001)
        print('verified')

    def spin(self, seconds):
        """Pause for set amount of seconds, replaces time.sleep so program doesnt stall"""

        time_end = time.time() + seconds
        while time.time() < time_end:
            QtGui.QApplication.processEvents()

    def unauthorized(self):
        print('unauthorized')
        self.status_label.setText('Invalid username and/or password')
        self.status_label.setStyleSheet('QLabel {color: rgb(255,65,106)}')

    def admin_page_unlocked_init(self):
        self.admin_unlocked_tab = QtGui.QWidget()
        admin_unlocked_layout = QtGui.QGridLayout()
        admin_unlocked_button = QtGui.QPushButton('unlocked')
        admin_unlocked_layout.addWidget(admin_unlocked_button)
        self.admin_unlocked_tab.setLayout(admin_unlocked_layout)

    def get_admin_page_layout(self):
        return self.admin_page_layout

if __name__ == '__main__':

    # Create main application window
    app = QtGui.QApplication(sys.argv)
    # app.setStyleSheet(load_CSS(1))
    app.setStyle(QtGui.QStyleFactory.create("Cleanlooks"))
    font = QtGui.QFont('Ubuntu', 20)
    font.setWeight(70)
    app.setFont(font)

    screen_height = QtGui.QApplication.desktop().screenGeometry().height()
    main_window_tab = TabWidget(width=300, height=screen_height/8)
    main_window_tab.setWindowTitle("Tab Layout")
    main_window_tab.setWindowFlags(QtCore.Qt.FramelessWindowHint)
    main_window_tab.showMaximized()

    tab1 = QtGui.QWidget()
    tab2 = QtGui.QWidget()
    tab3 = QtGui.QWidget()
    tab4 = QtGui.QWidget()
    tab5 = QtGui.QWidget()
    tab6 = QtGui.QWidget()
    tab7 = QtGui.QWidget()
    admin_tab = QtGui.QWidget()

    admin_tab_widget = AdminTabWidget()
    admin_tab.setLayout(admin_tab_widget.get_admin_page_layout())

    main_window_tab.addTab(admin_tab, "Admin")
    main_window_tab.addTab(tab1, "tab1")
    main_window_tab.addTab(tab2, "tab2")
    main_window_tab.addTab(tab3, "tab3")
    main_window_tab.addTab(tab4, "tab4")
    main_window_tab.addTab(tab5, "tab5")
    main_window_tab.addTab(tab6, "tab6")
    main_window_tab.addTab(tab7, "tab7")

    main_window_tab.show()

    QtGui.QShortcut(QtGui.QKeySequence('Ctrl+Q'), main_window_tab, exit_application)

    sys.exit(app.exec_())

Solution

  • The idea is to set the QStackedWidget with the Qt::AlignCenter alignment in the layout so it changes:

    self.admin_page_layout.addWidget(self.admin_page_switch, 0, 0)
    

    to:

    self.admin_page_layout.addWidget(self.admin_page_switch, 0, 0, alignment=QtCore.Qt.AlignCenter)