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())
Related
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 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)
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)
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)
When I decrease the window size all the widgets disappear.I want the widgets to move along when size is decreased.How do I solve this problem?
I have a drop-down menu from which a value is selected.When an "Add cmd" button is pressed the value is added to edit box.
Thanks in advance.
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class tabdemo(QTabWidget):
def __init__(self, parent = None):
super(tabdemo, self).__init__(parent)
self.setGeometry(50, 50, 400,400)
QShortcut(QKeySequence("Esc"), self, self.close)
self.tab1 = QWidget()
self.tab2 = QWidget()
self.addTab(self.tab1,"Tab 1")
self.tab1UI()
self.setWindowTitle("Main Window")
def tab1UI(self):
self.comboBox = QComboBox(self.tab1)
self.comboBox.addItem('ABC')
self.comboBox.addItem('BCD')
self.comboBox.addItem('CDE')
self.comboBox.move(5,20)
self.comboBox.resize(180,30)
self.button = QPushButton('Add Cmd', self.tab1)
self.button.move(190,20)
self.button.resize(80,30)
self.button.clicked.connect(self.handleTest)
self.b = QTextEdit(self.tab1)
self.b.move(20,75)
self.b.resize(290,200)
self.button = QPushButton('Send Batch', self.tab1)
self.button.move(40,300)
self.button.resize(150,30)
self.button = QPushButton('Clear', self.tab1)
self.button.move(200,300)
self.button.resize(80,30)
self.button.clicked.connect(self.deletevalue)
layout = QFormLayout()
self.setTabText(4,"BatchCMDS")
self.tab1.setLayout(layout)
def handleTest(self):
self.b.append(str(self.comboBox.currentText()))
def deletevalue(self):
self.b.clear()
def main():
app = QApplication(sys.argv)
ex = tabdemo()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
If you want the widgets to adapt to the size of the window you should use layouts, For this, the application must be designed, for this an image is used of how you want your application to be:
As we see the widgets that are inside a tab are divided into 3 groups, the first is made up of the QComboBox with the QPushButton, the second the QTextEdit, and the third the 2 remaining buttons. Each group is horizontally distributed, so in that case we should use QHBoxLayout except the QTextEdit that is alone, and each group should be in QVBoxLayout. I do not understand why you use the QFormLayout, also if you use the layouts the positions are not necessary.
Another error that I see in your code is that several buttons have the same name, this causes errors like for example that the Add CMD button does not work, you must give a different name to each widget.
class tabdemo(QTabWidget):
def __init__(self, parent = None):
super(tabdemo, self).__init__(parent)
self.setGeometry(50, 50, 400,400)
QShortcut(QKeySequence("Esc"), self, self.close)
self.tab1 = QWidget()
self.tab2 = QWidget()
self.addTab(self.tab1,"Tab 1")
self.addTab(self.tab2,"Tab 2")
self.tab1UI()
def tab1UI(self):
vlayout = QVBoxLayout(self.tab1)
hlayout1 = QHBoxLayout()
self.comboBox = QComboBox(self.tab1)
self.comboBox.addItems(['ABC', 'BCD', 'CDE'])
self.button = QPushButton('Add Cmd', self.tab1)
self.button.clicked.connect(self.handleTest)
hlayout1.addWidget(self.comboBox)
hlayout1.addWidget(self.button)
hlayout1.addItem(QSpacerItem(100, 10, QSizePolicy.Expanding, QSizePolicy.Preferred))
vlayout.addLayout(hlayout1)
self.b = QTextEdit(self.tab1)
vlayout.addWidget(self.b)
hlayout2 = QHBoxLayout()
self.buttonSend = QPushButton('Send Batch', self.tab1)
self.buttonClear = QPushButton('Clear', self.tab1)
self.buttonClear.clicked.connect(self.deletevalue)
hlayout2.addItem(QSpacerItem(100, 10, QSizePolicy.Expanding, QSizePolicy.Preferred))
hlayout2.addWidget(self.buttonSend)
hlayout2.addWidget(self.buttonClear)
hlayout2.addItem(QSpacerItem(100, 10, QSizePolicy.Expanding, QSizePolicy.Preferred))
vlayout.addLayout(hlayout2)
self.setTabText(4,"BatchCMDS")
def handleTest(self):
self.b.append(self.comboBox.currentText())
def deletevalue(self):
self.b.clear()