I have a widget which contains three labels and three lineedits. I would like all lineedits to be aligned vertically directly after the longest label.
Here is my class:
class ScaleDisplayWidget(QWidget):
def __init__(self, parent=None):
super(ScaleDisplayWidget, self).__init__(parent)
self.setFixedSize(400, 200)
self.initUI()
self.update(0, 0, 0)
def initUI(self):
'''
Setup GUI elements of scale window
'''
mainLayout = QVBoxLayout()
hLayout = QHBoxLayout()
hLayout.setSpacing(0)
self.dx_label = QLabel('DX:')
self.dx_label.setFixedWidth(80)
self.dx_edit = QLineEdit()
self.dx_edit.setReadOnly(True)
self.dx_edit.setFocus(True)
self.dx_edit.setFixedWidth(150)
hLayout.addWidget(self.dx_label)
hLayout.addWidget(self.dx_edit)
h2Layout = QHBoxLayout()
h2Layout.setSpacing(0)
self.dy_label = QLabel('DY:')
self.dy_label.setFixedWidth(80)
self.dy_edit = QLineEdit()
self.dy_edit.setReadOnly(True)
self.dy_edit.setFocus(True)
self.dy_edit.setFixedWidth(150)
h2Layout.addWidget(self.dy_label)
h2Layout.addWidget(self.dy_edit)
h3Layout = QHBoxLayout()
h3Layout.setSpacing(0)
self.dist_label = QLabel('Distance:')
self.dist_label.setFixedWidth(80)
self.dist_edit = QLineEdit()
self.dist_edit.setReadOnly(True)
self.dist_edit.setFocus(True)
self.dist_edit.setFixedWidth(150)
h3Layout.addWidget(self.dist_label)
h3Layout.addWidget(self.dist_edit)
mainLayout.addLayout(hLayout)
mainLayout.addLayout(h2Layout)
mainLayout.addLayout(h3Layout)
self.setLayout(mainLayout)
self.show()
def update(self, dx, dy, dist):
self.dx_edit.setText(str(dx))
self.dy_edit.setText(str(dy))
self.dist_edit.setText(str(dist))
In this case I'm aiming to have all lineedits aligned directly after the distance label (maybe add 5 pixels or something small of padding). I have tried using setContentsMargins(0,0,0,0) on all the layouts but it hasn't changed anything.
Use a QFormLayout instead:
self.dx_edit = QLineEdit()
self.dx_edit.setReadOnly(True)
self.dx_edit.setFocus(True)
self.dx_edit.setFixedWidth(150)
self.dy_edit = QLineEdit()
self.dy_edit.setReadOnly(True)
self.dy_edit.setFocus(True)
self.dy_edit.setFixedWidth(150)
self.dist_edit = QLineEdit()
self.dist_edit.setReadOnly(True)
self.dist_edit.setFocus(True)
self.dist_edit.setFixedWidth(150)
layout = QFormLayout(self)
layout.addRow("DX", self.dx_edit)
layout.addRow("DY", self.dy_edit)
layout.addRow("Distance", self.dist_edit)
You might need to set the label align to left with layout.setLabelAlignment(Qt.AlignLeft)
Related
I am pretty new to pyqt5.
I have a question regarding qstacklayout. It might be the same question as the How to make different pages of a QStackedWidget of different sizes?
Let's assume that I have done this as below
class MainUI(QDialog)
def __init__(self, parent=None):
super().__init__(parent)
self.initUI()
def initUI(self):
self.scroll_area=QScrollArea()
self.main_layout=QHBoxLayout()
self.scroll_area.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget()
self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 500, 300))
self.grid_layout = QGridLayout()
self.grid_layout.addWidget(self.a_widget_ui(), 0, 0)
... # Set other widget to grid_layout in position of (1, 0), (2, 0), (3, 0)
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
#set the buttonbox at the end of gridlayout
self.grid_layout.addWidget(self.button_box, 4, 0)
self.setLayout(self.main_layout)
self.setGeometry(300, 300, 790, 800)
def self.a_widget_ui(self):
group_box = QGroupBox('A Information')
a_list = ['1', '2', '3']
self.combo_box = QComboBox()
self.combo_box.addItems(a_list)
self.combo_box.activated[str].connect(self.update_widget)
self.stacked_layout = QStackedLayout()
self.A_layout = A_Layout()
self.B_layout = B_Layout()
self.stacked_layout.addWidget(self.A_Layout)
self.stacked_layout.addWidget(self.B_Layout)
hbox = QHBoxLayout()
hbox.addWidget(self.combo_box)
vbox = QVBoxLayout()
vbox.addLayout(hbox)
vbox.addLayout(self.stacked_layout)
group_box.setLayout(vbox)
return groupbox
def update_widget(self, choice):
if choice == "A":
self.stacked_layout.setCurrentWidget(self.A_Layout)
else:
self.stacked_layout.setCurrentWidget(self.B_Layout)
Then I have these different layouts for A_Layout() and B_Layout()
class A_Layout(QWidget):
def __init__(self, parent=None)
super().__init__(parent)
grid_layout = QGridLayout()
grid_layout.addWidget(self.set_a_widget(), 0, 0)
self.setLayout(grid_layout)
def set_a_widget(self):
main_widget = QWidget()
self._a_attrib = QLineEdit()
self._b_attrib = QLineEdit()
form_layout = QFormedLayout()
form_layout.addWidget('set a attrib', self._a_attrib)
form_layout.addWidget('set b attrib', self._b_attrib)
main_widget.setLayout(form_layout)
return main_widget
class B_Layout(QWidget):
def __init__(self, parent=None)
super().__init__(parent)
grid_layout = QGridLayout()
grid_layout.addWidget(self.set_a_widget(), 0, 0)
self.setLayout(grid_layout)
def set_a_widget(self):
main_widget = QWidget()
self._a_attrib = QLineEdit()
self._b_attrib = QLineEdit()
self._c_attrib = QLineEdit()
self._d_attrib = QLineEdit()
form_layout = QFormedLayout()
form_layout.addWidget('set a attrib', self._a_attrib)
form_layout.addWidget('set b attrib', self._b_attrib)
form_layout.addWidget('set c attrib', self._c_attrib)
form_layout.addWidget('set d attrib', self._d_attrib)
main_widget.setLayout(form_layout)
return main_widget
There are some conditions that I've made when I was making this structure.
I made class A_Layout and class B_Layout in order for me to reuse those Dialog later if needed.
I used QStackedLayout / QStackedWidget in order for me to update the layout/widget via combobox.
My questions are the following.
Is it possible for me to change the layout size dynamically? For example, as you can tell that the size of layout will be different between A_Layout and B_Layout due to the number of components.
Since I am pretty new, but I have a hunch that I am doing it completely wrong about using qstackedwidget, maybe I should customize the layout such that it would work as qstackedlayout but has more size management
I would sincerely want to get advice or suggestions if it's possible. What I have tried is to put QSizePolicy before adding layout/widget in stackedlayout and put them whenever I call update_widget. Any other tip or advice would be very appreciated.
My program collecting some data from the user (patient ID, trial no., activity, etc.) using a dialog window with a QFormLayout. I want to save these data and print them onto the main window, but when I print them they come out empty. I'm new to Python so I'm wondering if there's a structural issue with my code that is causing the variables to be lost.
I have a main class for the main window that looks like this (there is more but I cut out irrelevant parts):
class App(QMainWindow):
""" Sets up the main window for the Graphical User Interface """
def __init__(self):
super().__init__()
self.title = 'Title'
self.left = 60
self.top = 100
self.width = 1400
self.height = 820
self.initUI()
def initUI(self) :
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
*lots of labels and buttons added here*
inputs = getInputs()
inputs.exec()
patID = inputs.patID
patAct = inputs.patAct
patTrial = inputs.patTrial
# print out inputs under their labels
label_pat2 = QLabel(str(patID), self)
label_pat2.move(150, 200)
label_activity2 = QLabel(str(patAct), self)
label_activity2.move(300, 200)
label_trial2= QLabel(str(patTrial), self)
label_trial2.move(500, 200)
self.show() # show main window
Then I have another class that opens a dialog window to get the inputs, which looks like this:
class getInputs(QDialog):
""" Takes in the patient ID number, trial number, and patient activity """
# NumGridRows = 3
# NumButtons = 4
def __init__(self):
super().__init__()
# super(getInputs, self).__init__()
self.createFormGroupBox()
buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
buttonBox.accepted.connect(self.accept)
buttonBox.rejected.connect(self.reject)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.formGroupBox)
mainLayout.addWidget(buttonBox)
self.setLayout(mainLayout)
self.setWindowTitle("Trial information Input Dialog")
self.resize(400,200)
def createFormGroupBox(self):
combo_box = QComboBox()
combo_box.addItem("Walking")
combo_box.addItem("Running")
combo_box.addItem("Slow Walking")
line_edit = QLineEdit()
spin_box = QSpinBox()
self.formGroupBox = QGroupBox("Form layout")
layout = QFormLayout()
layout.addRow(QLabel("Patient ID:"), line_edit)
layout.addRow(QLabel("Activity:"), combo_box)
layout.addRow(QLabel("Trial no.:"), spin_box)
self.formGroupBox.setLayout(layout)
self.patID = line_edit.text()
self.patAct = combo_box.currentText()
self.patTrial = spin_box.text()
My theories right now are that there is either an error in my structure that causes the results from the window to be deleted, or that the .text() and .currentText() functions might not be the right function to use.
The problem is that you are getting the data an instant after creating the widgets when the user still does not interact with the QDialog. On the other hand, to obtain the value of the QSpinBox you must use the value() method:
class getInputs(QDialog):
"""Takes in the patient ID number, trial number, and patient activity"""
# NumGridRows = 3
# NumButtons = 4
def __init__(self):
super().__init__()
# super(getInputs, self).__init__()
self.createFormGroupBox()
buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
buttonBox.accepted.connect(self.accept)
buttonBox.rejected.connect(self.reject)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.formGroupBox)
mainLayout.addWidget(buttonBox)
self.setLayout(mainLayout)
self.setWindowTitle("Trial information Input Dialog")
self.resize(400, 200)
def createFormGroupBox(self):
self.combo_box = QComboBox()
self.combo_box.addItem("Walking")
self.combo_box.addItem("Running")
self.combo_box.addItem("Slow Walking")
self.line_edit = QLineEdit()
self.spin_box = QSpinBox()
self.formGroupBox = QGroupBox("Form layout")
layout = QFormLayout()
layout.addRow(QLabel("Patient ID:"), self.line_edit)
layout.addRow(QLabel("Activity:"), self.combo_box)
layout.addRow(QLabel("Trial no.:"), self.spin_box)
self.formGroupBox.setLayout(layout)
def exec(self):
super().exec()
self.patID = self.line_edit.text()
self.patAct = self.combo_box.currentText()
self.patTrial = self.spin_box.value()
I want to add images to cells but it cant show properly,can you please tell me how to increase the row height and column width of the table widget.
Here given bellow is my code:
from PyQt4 import QtGui
import sys
imagePath = "pr.png"
class ImgWidget1(QtGui.QLabel):
def __init__(self, parent=None):
super(ImgWidget1, self).__init__(parent)
pic = QtGui.QPixmap(imagePath)
self.setPixmap(pic)
class ImgWidget2(QtGui.QWidget):
def __init__(self, parent=None):
super(ImgWidget2, self).__init__(parent)
self.pic = QtGui.QPixmap(imagePath)
def paintEvent(self, event):
painter = QtGui.QPainter(self)
painter.drawPixmap(0, 0, self.pic)
class Widget(QtGui.QWidget):
def __init__(self):
super(Widget, self).__init__()
tableWidget = QtGui.QTableWidget(10, 2, self)
# tableWidget.horizontalHeader().setStretchLastSection(True)
tableWidget.resizeColumnsToContents()
# tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
# tableWidget.setFixedWidth(tableWidget.columnWidth(0) + tableWidget.columnWidth(1))
tableWidget.resize(400,600)
tableWidget.setCellWidget(0, 1, ImgWidget1(self))
tableWidget.setCellWidget(1, 1, ImgWidget2(self))
if __name__ == "__main__":
app = QtGui.QApplication([])
wnd = Widget()
wnd.show()
sys.exit(app.exec_())
When using widgets inside the QTableWidget are not really the content of the table, they are placed on top of it, so resizeColumnsToContents() makes the size of the cells very small since it does not take into account the size of those widgets, resizeColumnsToContents() takes into account the content generated by the QTableWidgetItem.
On the other hand if you want to set the height and width of the cells you must use the headers, in the following example the default size is set using setDefaultSectionSize():
class Widget(QtGui.QWidget):
def __init__(self):
super(Widget, self).__init__()
tableWidget = QtGui.QTableWidget(10, 2)
vh = tableWidget.verticalHeader()
vh.setDefaultSectionSize(100)
# vh.setResizeMode(QtGui.QHeaderView.Fixed)
hh = tableWidget.horizontalHeader()
hh.setDefaultSectionSize(100)
# hh.setResizeMode(QtGui.QHeaderView.Fixed)
tableWidget.setCellWidget(0, 1, ImgWidget1())
tableWidget.setCellWidget(1, 1, ImgWidget2())
lay = QtGui.QVBoxLayout(self)
lay.addWidget(tableWidget)
If you want the size can not be varied by the user then uncomment the lines.
I am using a QVBox layout and there are two widgets and a dynamic layout 'layout2' in the layout. Widget1 is fixed on top Widget3 is fixed at the bottom and widget2 is dynamic widget. layout2 is deleted and added each time. The problem here is I am not able to position the widget3 at the bottom as layout2 layout is deleted Widget3 moves to the top. Below is the sample code.
class Screen(QWidget):
def __init__(self):
super(Screen, self).__init__()
self.main_layout = QVBoxLayout()
widget1 = QPushButton("Text1")
#self.widget2 = QWidget()
widget3 = QLabel("Text3")
self.widget2_layout = QHBoxLayout()
widget2_label = QLabel("text2")
self.widget2_layout.addWidget(widget2_label)
#self.widget2.setLayout(self.widget2_layout)
self.main_layout.addWidget(widget1,Qt.AlignTop)
self.main_layout.addLayout(self.widget2_layout)
self.main_layout.addWidget(widget3,Qt.AlignBottom)
widget1.clicked.connect(self.change_widget2)
self.setLayout(self.main_layout)
self.show()
def clearLayout(self,layout):
item = layout.takeAt(0)
while item:
w = item.widget()
if w:
w.deleteLater()
lay = item.layout()
if lay:
self.clearLayout(item.layout())
item = layout.takeAt(0)
def change_widget2(self):
self.clearLayout(self.widget2_layout)
self.widget2_layout = QHBoxLayout()
widget2_label = QLabel("text changed")
self.widget2_layout.addWidget(widget2_label)
self.main_layout.addLayout(self.widget2_layout)
app = QApplication(sys.argv)
Gui = Screen()
sys.exit(app.exec_())
I have tried addstretch, dummy additional layout and nothing worked.
If you only want to change the widget that is in the second position it is not necessary to delete create a new layout, it is only necessary to reuse it, in the following example we see how the widget is changing:
class Screen(QWidget):
def __init__(self):
super(Screen, self).__init__()
self.setLayout(QVBoxLayout())
widget1 = QPushButton("Text1", self)
widget3 = QLabel("Text3", self)
self.widget2_layout = QHBoxLayout()
self.change_widget2()
self.layout().addWidget(widget1)
self.layout().addLayout(self.widget2_layout)
self.layout().addWidget(widget3)
widget1.clicked.connect(self.change_widget2)
def clearLayout(self, layout):
item = layout.takeAt(0)
while item:
w = item.widget()
if w:
w.deleteLater()
lay = item.layout()
if lay:
self.clearLayout(item.layout())
item = layout.takeAt(0)
def change_widget2(self):
self.clearLayout(self.widget2_layout)
# change the widget.
import random
widgets = [QLabel, QLineEdit, QPushButton]
widget2 = widgets[random.randint(0, len(widgets)-1)]("widget2", self)
self.widget2_layout.addWidget(widget2)
whenever I run this script of mine, the layout of my elements are somewhat in the correct area but the spacing in the right column (where the labels/button/line edit resides) makes it very unsightly with weird spacing in between them.
Any ideas how I can kill it off? Or perhaps is the using of gridLayout not a wise choice?
class createUI(QFrame):
def __init__(self, parent =None):
QFrame.__init__(self, parent)
self.initUI()
def initUI(self):
self.objLbl = QLabel('Name of Item')
self.objTxt = QLineEdit()
self.objTxt.setMaximumWidth(100)
self.renameLbl = QLabel('Rename')
self.renameTxt = QLineEdit()
self.renameTxt.setMaximumWidth(100)
self.itemLbl = QLabel('Item Lists')
self.itemList = QListWidget()
self.okButton = QPushButton('OK')
self.okButton.setMaximumWidth(100)
gridLayout = QGridLayout()
gridLayout.addWidget(self.itemLbl,1,0)
gridLayout.addWidget(self.itemList,2,0,6,1)
gridLayout.addWidget(self.objLbl,2,1)
gridLayout.addWidget(self.objTxt,3,1)
gridLayout.addWidget(self.renameLbl,4,1)
gridLayout.addWidget(self.renameTxt,5,1)
gridLayout.addWidget(self.okButton,7,1)
self.setLayout(gridLayout)
self.setWindowTitle("Testing")
Insert a spacer with vertical strech above the OK button:
gridLayout.addWidget(self.renameTxt,5,1)
gridLayout.addItem(QSpacerItem(
0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding), 6, 1)
gridLayout.addWidget(self.okButton,7,1)