Inputs from QFormLayout are printing empty - python

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()

Related

How to Read QLineEdit data dynamically

I am trying to create labels and textboxes dynamically in PyQt5 however, i have no idea how i can read data entered in the textboxes when a user hits the save button. My code looks as follows:
self.setWindowTitle("Yaml --> Json")
self.setGeometry(self.left, self.top, self.width, self.height)
self.createLayout()
vbox = QVBoxLayout()
for i in range(0, len(self.listItems)):
vbox.addWidget(QLabel(list(self.listItems.keys())[i]))
vbox.addWidget(QLineEdit())
vbox.addWidget(self.groupBox)
self.setLayout(vbox)
self.show()
def createLayout(self):
self.groupBox = QGroupBox()
hboxLayout = QHBoxLayout()
button = QPushButton("Save", self)
button.setIcon(QtGui.QIcon("save.png"))
button.setIconSize(QtCore.QSize(40, 40))
button.setMinimumHeight(40)
button.clicked.connect(self.ClickSave)
hboxLayout.addWidget(button)
button1 = QPushButton("Exit", self)
button1.setIcon(QtGui.QIcon("exit.png"))
button1.setIconSize(QtCore.QSize(40, 40))
button1.setMinimumHeight(40)
button1.clicked.connect(self.ClickExit)
hboxLayout.addWidget(button1)
self.groupBox.setLayout(hboxLayout)
def ClickExit(self):
print("Exited!!")
sys.exit()
def ClickSave(self):
print("Saved!")```
You could just assign the widgets you want to access later to instance variables or store them in a list, e.g.
self.line_edit_list = []
for i in range(0, len(self.listItems)):
vbox.addWidget(QLabel(list(self.listItems.keys())[i]))
line_edit = QLineEdit()
vbox.addWidget(line_edit)
self.line_edit_list.append(line_edit)
....
def ClickSave(self):
for edit in self.line_edit_list:
print(edit.text())

binding a signal to QListWidget items

How do I make sure that clicking on a QListWidget item opens the corresponding widgets in the QFrame and that the data entered in these widgets is saved between switching list items?
class Window(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
vbox = QVBoxLayout()
tab_widget = QTabWidget()
tab_widget.setStyleSheet('background-color:gainsboro')
tab_widget.addTab(Setup(), "setup")
vbox.addWidget(tab_widget)
self.setLayout(vbox)
class Setup(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout()
splitter = QSplitter(Qt.Horizontal)
self.list = QListWidget()
self.list.setStyleSheet("background-color:white")
QListWidgetItem("vertices", self.list)
QListWidgetItem("blocks", self.list)
self.list.itemClicked.connect(self.conv_met)
splitter.addWidget(self.list)
self.frame = QFrame()
self.frame.setFrameShape(QFrame.StyledPanel)
self.frame.setLineWidth(0.6)
splitter.addWidget(self.frame)
hbox.addWidget(splitter)
self.setLayout(hbox)
self.show()
def conv_met(self, item):
if item.text() == "vertices":
convertToMeters_layout = QHBoxLayout()
convertToMeters_lbl = QLabel("convertToMeters")
convertToMeters_val = QLineEdit("0.1")
convertToMeters_layout.addWidget(convertToMeters_lbl)
convertToMeters_layout.addWidget(convertToMeters_val)
self.frame.setLayout(convertToMeters_layout)
if item.text() == "blocks":
block_grad_layout = QGridLayout()
hexx = QComboBox(self)
hexx.addItems(["hex"])
ver_labels = QLineEdit("0 1 2 3 4 5 6 7")
block_grad_layout.addWidget(hexx, 0, 0)
block_grad_layout.addWidget(ver_labels, 0, 1)
self.frame.setLayout(block_grad_layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main_win = Window()
main_win.show()
sys.exit(app.exec_())
In order to keep data for an item, you can use setData(role, value) to store the previous entered data and before changing to the new current item.
Note that you should not use setLayout() more than once; in fact, your example doesn't work as expected for this reason, and you could see the error message if you run it from a shell or command prompt:
QWidget::setLayout: Attempting to set QLayout "" on QFrame "", which already has a layout
To achieve what you want, the solution is to use QStackedWidget, which works almost like a QTabWidget, but doesn't have a tab bar to switch between "pages", as they can only be changed programmatically using setCurrentIndex() or setCurrentWidget().
class Setup(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout()
splitter = QSplitter(Qt.Horizontal)
self.list = QListWidget()
self.list.setStyleSheet("background-color:white")
self.verticesItem = QListWidgetItem("vertices", self.list)
self.blocksItem = QListWidgetItem("blocks", self.list)
self.list.itemClicked.connect(self.conv_met)
splitter.addWidget(self.list)
self.frame = QFrame()
self.frame.setFrameShape(QFrame.StyledPanel)
self.frame.setLineWidth(0.6)
frameLayout = QVBoxLayout(self.frame)
self.stackedWidget = QStackedWidget()
frameLayout.addWidget(self.stackedWidget)
self.convertToMeters_widget = QWidget()
self.stackedWidget.addWidget(self.convertToMeters_widget)
convertToMeters_layout = QHBoxLayout(self.convertToMeters_widget)
convertToMeters_lbl = QLabel("convertToMeters")
self.convertToMeters_val = QLineEdit("0.1")
convertToMeters_layout.addWidget(convertToMeters_lbl)
convertToMeters_layout.addWidget(self.convertToMeters_val)
self.block_grad_widget = QWidget()
self.stackedWidget.addWidget(self.block_grad_widget)
block_grad_layout = QGridLayout(self.block_grad_widget)
hexx = QComboBox()
hexx.addItems(["hex"])
self.ver_labels = QLineEdit("0 1 2 3 4 5 6 7")
block_grad_layout.addWidget(hexx, 0, 0)
block_grad_layout.addWidget(self.ver_labels, 0, 1)
splitter.addWidget(self.frame)
hbox.addWidget(splitter)
self.setLayout(hbox)
self.currentItem = None
def conv_met(self, item):
if self.currentItem:
if self.currentItem == self.verticesItem:
self.currentItem.setData(Qt.UserRole, self.convertToMeters_val.text())
else:
self.currentItem.setData(Qt.UserRole, self.ver_labels.text())
if item == self.currentItem:
return
self.currentItem = item
if item == self.verticesItem:
self.stackedWidget.setCurrentWidget(self.convertToMeters_widget)
self.convertToMeters_val.setText(item.data(Qt.UserRole) or '0.1')
elif item == self.blocksItem:
self.stackedWidget.setCurrentWidget(self.block_grad_widget)
self.ver_labels.setText(item.data(Qt.UserRole) or '0 1 2 3 4 5 6 7')
Note that if you want to store numeric values for the "vertices", you might prefer to use a QSpinBox (or QDoubleSpinBox for floating numbers). Similarly, if you need only hexadecimal values, it's better to set an inputMask or add a validator to ensure that the entered values are valid.

How to align QLineEdits within a QWidget?

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)

print the output statement inside the text box using PyQt5

I created a widget, The process of widget begins with an entering the SQL.table_name and switch the Run_analysis button to generate the output in the format of csv.file. the mentioned process performed well. but I stuck in printing the (print) statement in the larger textbox.
class EpiClass:
NR = 0
R = 0
CT = 0
def __init__(self, obj):
self.obj = obj
def epi_calc(self):
"""Function to process EPI formula"""
with open(FN, "w") as FL: #FN object FL
for j in self.obj:
if j[12] is not None and float(j[12]) != 0: #Exclude (Null, 0) values in Cre-j[12]
j12 = float(j[12])
type(j12)
#type(j[12]) #tested
#type(j[35]) #tested
{
Body of statement, assume it add two variable
}
print("Total no of rows affected:", EpiClass.CT)
print("No. of records not analysed:", EpiClass.NR)
print("No. of records analysed:", EpiClass.R)
Here we go to PyQt5.
class WinClass(QMainWindow):
"""Main Window"""
def __init__(self):
super().__init__()
self.title = 'EGFR Widget'
self.left = 10
self.top = 10
self.width = 1920
self.height = 1080
self.init_ui()
def init_ui(self):
"""Window Geometry"""
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
#label
# Create textbox
self.textbox = QLineEdit(self)
self.textbox.move(20, 20)
self.textbox.resize(280, 40)
# Create a button in the window
self.button = QPushButton('Run Analysis', self)
self.button.move(20, 80)
#Print affected Rows
self.textbox2 = QLineEdit(self)
self.textbox2.move(120, 120)
self.textbox2.resize(880, 140)
# connect button to function on_click
self.button.clicked.connect(self.on_click)
self.show()
#pyqtSlot()
def on_click(self):
"""Button Action function"""
tb_value = str(self.textbox.text())
new_class = Edb(tb_value)
new_class.eclass()
######Im messed up in this step to print that 3 statements in textbox2#############
tb2_value = str(self.textbox2.text(EpiClass.CT))
#tb3_value = str(self.textbox2.text(EpiClass.NR))
#tb4_value = str(self.textbox2.text(EpiClass.R))
if __name__ == '__main__':
APP = QApplication(sys.argv)
ex = WinClass()
sys.exit(APP.exec_())
Kindly suggest a code to resolve the print statement. Much thanks!
You're trying to write using a read-only method text, you should use setText instead. I would save those statements in some variable and access from your widget, but that's up to you. I hope it helps.
def on_click(self):
"""Button Action function"""
tb_value = "Total no of rows affected: {}".format(EpiClass.CT)
self.textbox2.setText(tb_value)

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:
Desired:
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_())
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)

Categories