Reputation: 73
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?
Upvotes: 1
Views: 345
Reputation: 243955
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):
Upvotes: 1
Reputation: 10799
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)
Upvotes: 1