I'm trying to set up a GUI which will include multiple pages in PyQt5. The window will have a minimum size of 800x600, but is customisable beyond that. I want most, but not all, elements on the window to scale along with it. I have a solution already, but I feel that it is not very elegant.
Here is an example of the window at 800x600:
And here's another example after scaling
I've tried using QVBoxLayout, but with that system, I can't manage to keep the layout as it is here (not to say that it's impossible), rather the widgets all become centred and of the same width. At a later date, I might also be looking at adding widgets to the side that will be at the same y-value as some of the existing widgets, which is another thing that I'm not sure on how to do with the box layout.
Here's the relevant code:
class CreatePage(QWidget):
def __init__(self, parent=None):
super().__init__()
self.initUI()
def initUI(self):
self.homeBtn = QPushButton("Home", self)
self.homeBtn.move(10, 10)
self.frontLabel = QLabel("Front", self)
self.frontLabel.setFont(QFont("Decorative", 20))
self.frontEdit = QTextEdit(self)
self.frontEdit.setFont(QFont("Decorative", 11))
self.backLabel = QLabel("Back", self)
self.backLabel.setFont(QFont("Decorative", 20))
self.backEdit = QTextEdit(self)
self.backEdit.setFont(QFont("Decorative", 11))
def paintEvent(self, e):
qp = QPainter()
qp.setFont(QFont("Decorative", 20))
size = self.size()
h = size.height()
w = size.width()
frontW = qp.fontMetrics().width("Front")
self.frontLabel.move((w/2) - (frontW/2) , h/15)
#I use fontMetrics to determine the width of the text
#I then use this information to centre the text
self.frontEdit.move(50, h/15 + 40)
self.frontEdit.resize(w-100, h/3)
backW = qp.fontMetrics().width("Back")
self.backLabel.move((w/2) - (backW/2), h/2)
self.backEdit.move(50, h/2 + 40)
self.backEdit.resize(w-100, h/3)
Apologies for any general sloppiness, I am new to PyQt and to GUI programming on the whole. Anyway, the formulas I've used for resizing and moving widgets are quite arbitrary. Does anyone know a better way of achieving this effect?
Try it:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class CreatePage(QWidget):
def __init__(self, parent=None):
super().__init__()
self.initUI()
def initUI(self):
self.homeBtn = QPushButton("Home")
self.frontLabel = QLabel("Front")
self.frontLabel.setFont(QFont("Decorative", 20))
self.frontEdit = QTextEdit(placeholderText="frontEdit")
self.frontEdit.setFont(QFont("Decorative", 11))
self.backLabel = QLabel("Back")
self.backLabel.setFont(QFont("Decorative", 20))
self.backEdit = QTextEdit(placeholderText="backEdit")
self.backEdit.setFont(QFont("Decorative", 11))
grid = QGridLayout()
grid.addWidget(self.homeBtn, 0, 0, alignment=Qt.AlignTop | Qt.AlignLeft)
grid.addWidget(self.frontLabel, 1, 0, alignment=Qt.AlignCenter)
grid.addWidget(self.frontEdit, 2, 0)
grid.addWidget(self.backLabel, 3, 0, alignment=Qt.AlignCenter)
grid.addWidget(self.backEdit, 4, 0)
self.setLayout(grid)
if __name__=="__main__":
app = QApplication(sys.argv)
myapp = CreatePage()
myapp.show()
sys.exit(app.exec_())
Related
I just started using Python PyQt5 and I am trying to make a GUI. It all works, but I have a problem with the textbox. Every time the textbox gets filled and I try to add more, it stays the same size and just adds a small scrollbar IN the textbox. What I want is for the textbox to readjust depending on the size of the text so that you can always see the text. How can I do this.
Here is my current code:
#Import Module
from PyQt5.QtGui import QFont
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5 import QtGui
import sys
#Create Main Class
class AddToDeckWindow(QtWidgets.QMainWindow):
def __init__(self):
super(AddToDeckWindow, self).__init__()
#Set The UI
self.initUI()
#Set The GUI Position And Size
self.setGeometry(200, 200, 900, 710)
#Set The GUI Title
self.setWindowTitle("Add")
#Set The GUI Icon
self.setWindowIcon(QtGui.QIcon('give_way.png'))
#Set The Translator
_translate = QtCore.QCoreApplication.translate
def initUI(self):
widAddToDeckWindow = QtWidgets.QWidget(self)
#Create The Text Box
self.setCentralWidget(widAddToDeckWindow)
textBox = QtWidgets.QTextEdit(widAddToDeckWindow)
textBox.setGeometry(200, 200, 500, 200)
#Set The Font
font = QFont()
font.setPointSize(14)
textBox.setFont(font)
#Create A Windows
def window():
app = QtWidgets.QApplication(sys.argv)
win = AddToDeckWindow()
#Centers The Window On The Screen
qtRectangle = win.frameGeometry()
centerPoint = QtWidgets.QDesktopWidget().availableGeometry().center()
qtRectangle.moveCenter(centerPoint)
win.move(qtRectangle.topLeft())
win.show()
sys.exit(app.exec_())
window()
First of all, consider that you're not using a layout manager, and using fixed geometries like you did, is considered bad practice and also a very bad idea.
For instance, in your case, if I try to resize the window to a size smaller than the bottom right corner of the text edit, it will become partially (or completely) invisible.
I strongly advise you against this pattern (actually, almost everybody would), as if you want to show such big margins you only need to correctly use the layout properties instead.
That said, if you want to resize a textedit according to its contents, you must implement a function that constantly checks its document().
Then, you should choose if set the minimumHeight, or, better the sizeHint, which is used by the layout to limit its size if no more space is available. I strongly suggest you to use the latter.
class ResizingTextEdit(QtWidgets.QTextEdit):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.textChanged.connect(self.computeHint)
self._sizeHint = super().sizeHint()
def computeHint(self):
hint = super().sizeHint()
height = self.document().size().height()
height += self.frameWidth() * 2
self._sizeHint.setHeight(max(height, hint.height()))
self.updateGeometry()
self.adjustSize()
def sizeHint(self):
return self._sizeHint
class AddToDeckWindow(QtWidgets.QMainWindow):
# ...
def initUI(self):
widAddToDeckWindow = QtWidgets.QWidget(self)
#Create The Text Box
self.setCentralWidget(widAddToDeckWindow)
textBox = ResizingTextEdit(widAddToDeckWindow)
textBox.setMinimumSize(500, 200)
# this is no more necessary, as the layout will completely override it
# textBox.setGeometry(200, 200, 500, 200)
layout = QtWidgets.QGridLayout(widAddToDeckWindow)
layout.addWidget(textBox, 1, 1)
layout.setColumnStretch(0, 1)
layout.setColumnStretch(2, 1)
layout.setRowStretch(0, 1)
layout.setRowStretch(2, 1)
#Set The Font
font = QFont()
font.setPointSize(14)
textBox.setFont(font)
In case of the minimumHeight, use the following:
class ResizingTextEdit(QtWidgets.QTextEdit):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.textChanged.connect(self.computeHint)
def computeHint(self):
height = self.document().size().height()
height += self.frameWidth() * 2
if height > super().sizeHint().height():
self.setMinimumHeight(height)
else:
self.setMinimumHeight(0)
I'm trying to create a layout where is existing a row, and this row should contain an absolute positioned button which should be placed outside of this row.
Here is the simple schema
I did it by just pushing a child button into the parent button (I'm not sure that it's a correct solution) and moved it to some absolute coordinates.
It works but, unfortunately, the child button is clipping by the parent. So it's like overflow: hidden in CSS. But in case of QT I couldn't found how to disable this behavior.
Here is the demo of my current QUI
Is there exists any way to solve it? Or should I just use some widget combination with the empty spacer etc.?
btn = QPushButton("button")
test = QPushButton("X")
test.setParent(btn)
test.move(200, 5)
self.layout.addWidget(btn)
Full code of the UI class (minimal reproducible example)
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.layout = QVBoxLayout()
btn = QPushButton("button")
test = QPushButton("X")
test.setParent(btn)
test.move(200, 5)
self.layout.addWidget(btn)
self.setLayout(self.layout)
self.layout.setContentsMargins(0,0,0,74)
self.layout.setSpacing(0)
# self.layout.addStretch(-1)
self.setMinimumSize(640,400)
self.setWindowFlags(Qt.FramelessWindowHint)
Sorry, but the advice of #Heike is absolutely correct and you should not look for wrong solutions.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.setMinimumSize(640,400)
self.setWindowFlags(Qt.FramelessWindowHint)
btn = QPushButton("button")
test = QPushButton("X")
test.setParent(btn)
# test.move(200, 5)
# self.layout = QVBoxLayout()
self.layout = QGridLayout()
self.layout.addWidget(btn, 0, 0, 1, 10)
self.layout.addWidget(test, 0, 11, 1, 1)
self.layout.setContentsMargins(0,0,0,74)
self.layout.setSpacing(0)
self.setLayout(self.layout)
if __name__ == '__main__':
import sys
application = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(application.exec_())
New Python programmer here. I'm trying to make a simple-ish GUI and cannot get one of the PyQt elements to display. Perhaps someone here can point me in the right direction and give some general code comments. Don't worry. I know my code is probably awful. We've all got to start somewhere.
I have a GUI which consists of two widgets in an HBoxLayout. One widget is a simple PushButton, the other is a custom ControlWidget. I can get these to display just fine (alignment issues notwithstanding). On the ControlWidget, I have a GridLayout with some Labels, ComboBoxes, and a subclassed QTextBrowser (Debugger). This is what I can't get to appear.
Admittedly, I'm not absolutely sure how to do this. Is the inheritance wrong? Do I need to pass something else into the lower classes? etc. I want the various elements broken up into separate files and for future events to be accessible in other parts of the code, but obviously I'm missing something.
MainGUI.py
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from ControlWidget import ControlWidget
# from MenuBar import MenuBar
from Debugger import Debugger
# Main
class TopWindow(QMainWindow):
def __init__(self):
super(TopWindow, self).__init__()
self.setWindowTitle('Test GUI')
self.setGeometry(0, 0, 800, 600)
self.setMaximumSize(1024, 768)
self.initUI()
def initUI(self):
# MenuBar.initMenuBar(self)
centralWidget = QWidget(self)
self.setCentralWidget(centralWidget)
hLayout = QHBoxLayout(centralWidget)
pushButton = QPushButton("Button A")
hLayout.addWidget(pushButton)
hLayout.addWidget(ControlWidget())
self.show()
# Program Entry Point
if __name__ == '__main__':
applicationInstance = QApplication(sys.argv)
ex = TopWindow()
sys.exit(applicationInstance.exec_())
ControlWidget.py
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from Debugger import Debugger
class ControlWidget(QWidget):
def __init__(self, parent=None):
super(ControlWidget, self).__init__(parent)
self.left = 100
self.top = 100
self.width = 320
self.height = 100
self.numClicks = 0
self.setMaximumWidth(240)
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.initUI()
def initUI(self):
self.setGeometry(self.left, self.top, self.width, self.height)
self.createGridLayout()
def createGridLayout(self):
# Create Grid Layout
layout = QGridLayout()
self.setLayout(layout)
layout.setColumnStretch(0, 2)
layout.setColumnStretch(1, 3)
layout.setColumnStretch(2, 1)
# Instantiate Labels
labelA = QLabel()
labelB = QLabel()
labelC = QLabel()
labelD = QLabel()
labelE = QLabel()
labelF = QLabel()
self.labelFa = QLabel()
labelA.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
labelB.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
labelC.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
labelD.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
labelE.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
labelF.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
self.labelFa.setAlignment(Qt.AlignCenter | Qt.AlignVCenter)
labelA.setText('ABCD: ')
labelB.setText('BCDE: ')
labelC.setText('CDEF: ')
labelD.setText('DEFG: ')
labelE.setText('EFGH: ')
labelF.setText('FGHI: ')
# Instantiate Combo Boxes
comboBoxA = QComboBox()
comboBoxB = QComboBox()
comboBoxC = QComboBox()
comboBoxD = QComboBox()
comboBoxE = QComboBox()
comboBoxA.addItems(["A", "B", "C", "D"])
comboBoxB.addItems(["B", "C", "D", "E"])
comboBoxC.addItems(["C", "D", "E", "F"])
comboBoxD.addItems(["D", "E", "F", "G"])
comboBoxE.addItems(["E", "F", "G", "H"])
# Instantiate Push Buttons
pushButtonF = QPushButton()
pushButtonF.setText('Set Value')
# Spacer
spacer = QSpacerItem(10, 30, QSizePolicy.Fixed, QSizePolicy.Fixed)
# Message Box
labelDebug = QLabel()
labelDebug.setText("Debug")
labelDebug.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
debug = Debugger(self) # DOES NOT WORK
# Add to Grid Layout (item, row, column, rowspan, colspan)
layout.addWidget(labelA, 0, 0)
layout.addWidget(labelB, 1, 0)
layout.addWidget(labelC, 2, 0)
layout.addWidget(labelD, 3, 0)
layout.addWidget(labelE, 4, 0)
layout.addWidget(labelF, 5, 0)
layout.addWidget(comboBoxA, 0, 1, 1, 2)
layout.addWidget(comboBoxB, 1, 1, 1, 2)
layout.addWidget(comboBoxC, 2, 1, 1, 2)
layout.addWidget(comboBoxD, 3, 1, 1, 2)
layout.addWidget(comboBoxE, 4, 1, 1, 2)
layout.addWidget(pushButtonF, 5, 1, 1, 1)
layout.addWidget(self.labelFa, 5, 2, 1, 1)
layout.addItem(spacer, 6, 0, 1, 3)
layout.addWidget(labelDebug, 7, 0)
layout.addWidget(debug, 8, 0)
# Hook Up ComboBox Signals to Handlers
comboBoxA.currentIndexChanged.connect(self.comboBoxAHandler)
# Hook Up PushButton Signals to Handlers
pushButtonF.clicked.connect(self.pushButtonFHandler)
#self.horizontalGroupBox.setLayout(layout)
def comboBoxAHandler(self, i):
print('Combo Box A Selection Changed to {0}'.format(i))
#Debugger.write(self, 'Combo Box A Selection Changed')
def pushButtonFHandler(self):
print('Push Button F Clicked')
self.numClicks = self.numClicks + 1
self.labelFa.setText(str(self.numClicks))
Debugger.py
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class Debugger(QWidget):
def __init__(self, parent=None):
super(Debugger, self).__init__(parent)
self.setMaximumWidth(240)
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
self.createTextBrowser()
def createTextBrowser(self):
self.textBrowser = QTextBrowser()
self.textBrowser.setReadOnly(True)
def write(self, text):
self.textBrowser.append("• " + text)
What's the simple thing that I'm missing or doing incorrectly?
You have 2 errors:
You are not using the inheritance in Debugger, but a composition.
If you are going to want to use a variable in other methods of the same class you must make that variable member of the class.
Considering the above, the solution is:
Debugger.py
import sys
from PyQt5.QtWidgets import QTextBrowser, QSizePolicy
class Debugger(QTextBrowser):
def __init__(self, parent=None):
super(Debugger, self).__init__(parent)
self.setMaximumWidth(240)
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
self.setReadOnly(True)
def write(self, text):
self.append("• " + text)
ControlWidget.py
# ...
class ControlWidget(QWidget):
# ...
def initUI(self):
# ...
# Message Box
labelDebug = QLabel()
labelDebug.setText("Debug")
labelDebug.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
self.debug = Debugger() # <---
# ...
layout.addWidget(labelDebug, 7, 0)
layout.addWidget(self.debug, 8, 0) # <---
# Hook Up ComboBox Signals to Handlers
# ...
def comboBoxAHandler(self, i):
print('Combo Box A Selection Changed to {0}'.format(i))
self.debug.write('Combo Box A Selection Changed') # <---
# ...
I recommend reading the following publications so that you understand the difference between inheritance(is-a) and composition(has-a):
Difference between Inheritance and Composition
Python: Inheritance versus Composition
My guess is that it has to do with the fact that your textbrowser object doesn't have a parent, and you never explicitly told it to .show().
Usually, when a widget has a parent, a call to the parent widget's show method will show the children as well. Since your textbrowser object has no parent, the alternative is to show that object explicitly, but you haven't done that either.
In your TopWindow class' initUI method, you call self.show(). This is the actual invokation that shows all of the parent's children (the parent being self, the window). This single call correctly shows your other widgets because you explicitly assigned the main window as their parent, but it does not show your textbrowser because you did not give it a parent. (note, because your debugger class is using composition as opposed to inheritance, you did give the debugger a parent (which is a QWidget), but the actual QTextBrowser object does not have a parent)
I'm trying to incorporate a QSplitter. The code works perfectly from a functionality standpoint, but the QSplitter itself doesn't appear correctly under the default PyQt style... possibly because it is itself embedded within a vertical splitter. This is confusing for the user.
If you uncomment out the line (and thus change the default PyQt style), the QSplitter visualizes correctly only when hovered over... however, I also don't want this other style.
Can anyone provide any guidance on this matter?
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout(self)
L_layout = QGridLayout()
R_layout = QGridLayout()
L_widgets = QWidget()
L_widgets.setLayout(L_layout)
R_widgets = QWidget()
R_widgets.setLayout(R_layout)
topleft = QFrame()
topleft.setFrameShape(QFrame.StyledPanel)
btn1 = QPushButton('btn1')
bottom = QFrame()
bottom.setFrameShape(QFrame.StyledPanel)
textedit = QTextEdit()
L_layout.addWidget(topleft, 0, 0, 1, 1)
L_layout.addWidget(btn1, 1, 0, 1, 1)
R_layout.addWidget(textedit)
splitter1 = QSplitter(Qt.Horizontal,frameShape=QFrame.StyledPanel,frameShadow=QFrame.Plain)
splitter1.addWidget(L_widgets)
splitter1.addWidget(R_widgets)
splitter1.setStretchFactor(1,1)
splitter2 = QSplitter(Qt.Vertical)
splitter2.addWidget(splitter1)
splitter2.addWidget(bottom)
hbox.addWidget(splitter2)
self.setLayout(hbox)
#QApplication.setStyle(QStyleFactory.create('Cleanlooks'))
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('QSplitter demo')
self.show()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
EDIT: This is apparently a known macOS bug. When viewed on Linux, the bar of splitter1 has the same look as splitter2. I'll leave this topic open in case anyone else knows of a suitable workaround for mac.
Because the QPushButton has default minimum size, when you want to move splitter to left,
the button has reached its minimum size. So you can not move left anymore, otherwise the left will will collapse.
So if you want the left showing as you want, you can set the minimum size off button widget.
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout(self)
L_layout = QGridLayout()
R_layout = QGridLayout()
L_widgets = QWidget()
L_widgets.setLayout(L_layout)
R_widgets = QWidget()
R_widgets.setLayout(R_layout)
topleft = QFrame()
topleft.setFrameShape(QFrame.StyledPanel)
btn1 = QPushButton('btn1')
btn1.setMinimumWidth(1) # For example : set the minimum width to 1, then you can move left until the btn1 width is 1
bottom = QFrame()
bottom.setFrameShape(QFrame.StyledPanel)
textedit = QTextEdit()
L_layout.addWidget(topleft, 0, 0, 1, 1)
L_layout.addWidget(btn1, 1, 0, 1, 1)
R_layout.addWidget(textedit)
splitter1 = QSplitter(Qt.Horizontal,frameShape=QFrame.StyledPanel,frameShadow=QFrame.Plain)
splitter1.addWidget(L_widgets)
splitter1.addWidget(R_widgets)
splitter1.setStretchFactor(1,1)
splitter2 = QSplitter(Qt.Vertical)
splitter2.addWidget(splitter1)
splitter2.addWidget(bottom)
hbox.addWidget(splitter2)
self.setLayout(hbox)
#QApplication.setStyle(QStyleFactory.create('Cleanlooks'))
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('QSplitter demo')
self.show()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I want to display welcome label in middle of frame, how can I do that? It seems like layout problem as I googled but I haven't got final solution.
Here is the code:
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class Window(QMainWindow):
def __init__(self):
super(Window, self).__init__()
palette = QPalette()
palette.setBrush(QPalette.Background, QBrush(QPixmap("Login page.jpg")))
self.setPalette(palette)
self.setWindowTitle("Login Frame")
self.setWindowIcon(QIcon('logo.png'))
self.setGeometry(50, 50, 500, 300)
self.setFixedSize(500, 300)
self.addWidgets()
def addWidgets(self):
self.lblWelcome = QLabel("Welcome to Railway e-Ticketing System", self)
self.lblWelcome.move(100,30)
wcFont = QFont("Open Sans", 25)
self.lblWelcome.setFont(wcFont)
self.lblUid = QLabel("User ID:", self)
self.lblUid.move(100,80)
font = QFont("Open Sans", 10)
self.lneUid = QLineEdit(self)
self.lneUid.setFont(font)
self.lneUid.setFixedHeight(25)
self.lneUid.setFixedWidth(200)
self.lneUid.move(225, 80)
self.lblPass = QLabel("Password:", self)
self.lblPass.move(100, 130)
self.lnePass = QLineEdit(self)
self.lnePass.setEchoMode(QLineEdit.Password)
self.lnePass.setFixedHeight(25)
self.lnePass.setFixedWidth(200)
self.lnePass.move(225, 130)
self.lblInvalid = QLabel("",self)
self.lblInvalid.move(100, 180)
self.btnLogin = QPushButton("Login",self)
#btnLogin.resize(btnLogin.sizeHint())
self.btnLogin.move(175, 230)
self.btnLogin.clicked.connect(self.authenticate)
#self.authenticate()
self.btnReg = QPushButton("Register", self)
self.btnReg.move(300, 230)
#btnReg.clicked.connect(register)
self.show()
def authenticate(self):
uid = self.lneUid.text()
upass = self.lnePass.text()
if(len(uid.strip()) == 0 or len(upass.strip()) == 0):
palette = QPalette()
palette.setColor(QPalette.Foreground, Qt.darkRed)
self.lblInvalid.setPalette(palette)
self.lblInvalid.setText("*Invalid credentials .")
else:
self.lblInvalid.setText("")
def main():
app = QApplication(sys.argv)
LoginWin = Window()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
And here is the output:
You are using a QMainWindow which already has a layout with a central widget, a toolbar, a menu bar etc. The right way to use it is to define a central Widget, and put all your label and buttons in it. You didn't, so your label is not displayed properly.
But for your login frame, you clearly don't need all of this. You just need a QWidget:
import sys
from PyQt4 import QtCore,QtGui
class LoginFrame(QtGui.QWidget):
def __init__(self):
super(LoginFrame, self).__init__()
...
if __name__=='__main__':
app = QtGui.QApplication(sys.argv)
win = LoginFrame()
win.show()
sys.exit(app.exec_())
Your code should work with a QWidget, but I would still advise reading about box layout. Right now, you're using absolute positioning, which means you have to manually place your widget at a precise position, and you can't resize your window.
A box layout would be more flexible, and practical. For example you can use QFormLayout for the userID and password.
More about layouts on the ZetCode tutorial