Refresh QLCDNumber and implementing generic function - python

I'm doing some preliminary tests before I start programming the GUI I need with pyqt5, and today I found a couple of things that I haven't been able to solve.
My code is the following:
from PyQt5 import QtCore, QtGui, QtWidgets
import time
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(398, 398)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setGeometry(QtCore.QRect(30, 40, 131, 61))
self.lineEdit.setText("")
self.lineEdit.setObjectName("lineEdit")
self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit_2.setGeometry(QtCore.QRect(30, 120, 131, 61))
self.lineEdit_2.setText("")
self.lineEdit_2.setObjectName("lineEdit_2")
self.lcdNumber = QtWidgets.QLCDNumber(self.centralwidget)
self.lcdNumber.setGeometry(QtCore.QRect(180, 40, 64, 23))
self.lcdNumber.setObjectName("lcdNumber")
self.lcdNumber_2 = QtWidgets.QLCDNumber(self.centralwidget)
self.lcdNumber_2.setGeometry(QtCore.QRect(180, 120, 64, 23))
self.lcdNumber_2.setObjectName("lcdNumber_2")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 398, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.number = 0
self.number_2 = 0
self.lcdNumber.display(self.number)
self.lcdNumber_2.display(self.number_2)
self.lineEdit.returnPressed.connect(self.change_number)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
def change_number(self):
ip = int(self.lineEdit.text())
if ip > self.number:
count = 1
elif ip < self.number:
count = -1
else:
count = 0
while self.number != ip :
self.number += count
self.lcdNumber.display(self.number)
time.sleep(1)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
As you can see I have two QLineEdit boxes and two QLCDNumber for displaying the number that I write in the corresponding QLineEdit.
Problem 1
I'm able to display the number in the QLCDNumber with the following code:
self.lineEdit.returnPressed.connect(self.change_number)
...
def change_number(self):
self.lcdNumber.display(int(self.lineEdit.text()))
However, if I want to change the displayed number one by one with a certain time delay, my code doesn't work as I expect.
For example, if the current number is 0 and I type 10 in the QLineEdit, the program freezes for 10 seconds and then the number 10 is displayed on the QLCDNumber, while I would expect it to be updated second by second. I really can't figure out where the problem is.
Problem 2
I have two QLineEdit and two QLCDNumber, and it doesn't make much sense to write two different functions change_number.
However, I can't find a way for writing a generic function that takes as an input which QLCDNumber will be updated and which QLineEdit will be the input.
In pseudocode, it would be something like this:
self.LINEEDIT_NAME.returnPressed.connect(self.change_number(LINEEDIT_NAME,QLCD_NAME))
...
def change_number(self,LINEEDIT_NAME,QLCD_NAME):
ip = int(self.LINEEDIT_NAME.text())
if ip > self.number:
count = 1
elif ip < self.number:
count = -1
else:
count = 0
while self.number != ip :
self.number += count
self.QLCD_NAME.display(self.number)
time.sleep(1)
but I'm not able to use the LINEEDIT_NAME and QLCD_NAME as variables of the functions.

time.sleep() is a task that blocks the PyQt loop so it is not recommended to use it, the task can easily be substituted with a QTimer.
To facilitate the work we will create a class that inherits from QLCDNumber and that uses a QTimer to update the values
TimerLCDNumber.py
from PyQt5 import QtCore, QtGui, QtWidgets
class TimerLCDNumber(QtWidgets.QLCDNumber):
def __init__(self, *args, **kwargs):
QtWidgets.QLCDNumber.__init__(self, *args, **kwargs)
self.timer = QtCore.QTimer(self)
self.timer.setInterval(1000)
self.timer.timeout.connect(self.onTimeout)
self.finished = self.value()
def setValue(self, value):
self.finished = value
self.timer.start()
def onTimeout(self):
current = self.value()
if self.finished != current:
count = 1 if self.finished > current else -1
self.display(current + count)
else:
self.timer.stop()
This task can be promoted through Qt Designer or simply change, assuming that the file generated by Qt Designer is called design.py:
design.py
self.lcdNumber = QtWidgets.QLCDNumber(self.centralwidget)
self.lcdNumber_2 = QtWidgets.QLCDNumber(self.centralwidget)
to:
self.lcdNumber = TimerLCDNumber(self.centralwidget)
self.lcdNumber_2 = TimerLCDNumber(self.centralwidget)
In addition, the TimerLCDNumber class must be imported:
from TimerLCDNumber import TimerLCDNumber
It is advisable to separate the design from the logic so a new file called main.py is created that imports the design class and implements the logic:
main.py
from PyQt5 import QtCore, QtGui, QtWidgets
from design import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
self.setupUi(self)
self.lineEdit.returnPressed.connect(lambda: self.lcdNumber.setValue(int(self.lineEdit.text())))
self.lineEdit_2.returnPressed.connect(lambda: self.lcdNumber_2.setValue(int(self.lineEdit_2.text())))
self.lcdNumber.display(0)
self.lcdNumber_2.display(0)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
At the end in our folder we must have the following structure:
.
├── design.py
├── main.py
└── TimerLCDNumber.py
A possible solution for the second question is to use the lambda functions:
first option:
self.lineEdit.returnPressed.connect(lambda: self.lcdNumber.setValue(int(self.lineEdit.text())))
self.lineEdit_2.returnPressed.connect(lambda: self.lcdNumber_2.setValue(int(self.lineEdit_2.text())))
second option:
self.lineEdit.returnPressed.connect(lambda: change_number(self.lineEdit, self.lcdNumber))
self.lineEdit_2.returnPressed.connect(lambda: change_number(self.lineEdit_2, self.lcdNumber_2))
def change_number(self,LINEEDIT_NAME,QLCD_NAME):
QLCD_NAME.setValue(int(LINEEDIT_NAME.text()))
The complete code can be found at the following link.

Related

Get selected item in QListView

I'm trying to get the selected item when its pushed a button. I want to disable the button until the item be selected. I don't know if the methods that I need are in model class, QListView class, or if I should use a combination of methods of both classes
This it's my code:
QListView.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_QListView(object):
def setupUi(self, QListView):
QListView.setObjectName("QListView")
QListView.resize(357, 300)
self.centralwidget = QtWidgets.QWidget(QListView)
self.centralwidget.setObjectName("centralwidget")
self.listView = QtWidgets.QListView(self.centralwidget)
self.listView.setGeometry(QtCore.QRect(45, 34, 256, 192))
self.listView.setObjectName("listView")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(141, 238, 75, 23))
self.pushButton.setObjectName("pushButton")
QListView.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(QListView)
self.menubar.setGeometry(QtCore.QRect(0, 0, 357, 21))
self.menubar.setObjectName("menubar")
QListView.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(QListView)
self.statusbar.setObjectName("statusbar")
QListView.setStatusBar(self.statusbar)
self.retranslateUi(QListView)
QtCore.QMetaObject.connectSlotsByName(QListView)
def retranslateUi(self, QListView):
_translate = QtCore.QCoreApplication.translate
QListView.setWindowTitle(_translate("QListView", "List View"))
self.pushButton.setText(_translate("QListView", "Selected"))
mainQListView.py
from QListView import Ui_QListView
from PyQt5 import QtCore, QtGui, QtWidgets
class ListView(QtWidgets.QMainWindow, Ui_QListView):
def __init__(self):
super().__init__()
self.setupUi(self)
self.pushButton.setEnabled(False)
model = QtGui.QStandardItemModel()
for i in range(10):
model.appendRow(QtGui.QStandardItem(str(i)))
self.listView.setModel(model)
self.pushButton.clicked.connect(self.getSelectedItem)
def getSelectedItem(self):
pass
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ui = ListView()
ui.show()
sys.exit(app.exec_())
You have to use the selectedIndexes method to get the QModelIndex of the selected items and use itemFromIndex to get the QStandardItem:
class ListView(QtWidgets.QMainWindow, Ui_QListView):
def __init__(self):
super().__init__()
self.setupUi(self)
self.pushButton.setEnabled(False)
model = QtGui.QStandardItemModel()
for i in range(10):
model.appendRow(QtGui.QStandardItem(str(i)))
self.listView.setModel(model)
self.listView.selectionModel().selectionChanged.connect(
self.handle_selection_changed
)
self.pushButton.clicked.connect(self.handle_clicked)
def handle_selection_changed(self):
self.pushButton.setEnabled(bool(self.listView.selectedIndexes()))
def handle_clicked(self):
for index in self.listView.selectedIndexes():
item = self.listView.model().itemFromIndex(index)
print(item.text())
Note: It is not recommended that the names of new classes, variables or new files coincide with names of existing elements since it can generate silent errors (which are the most complicated to debug) so I recommend you change name of the QListView.py file.

Very basic pyqt5 dialog app quits with exit code -1073740791

I tried to design a very basic GUI app that shows the entered height on a dialog, but after I press the ‘OK’ button on the main window, the whole program crashes and the process finishes with this exit code:
Process finished with exit code -1073740791 (0xC0000409)
Here’s the full code for the app, the UI files are below:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.uic import *
class My_Dialog(QDialog):
def __init__(self):
super(My_Dialog, self).__init__()
loadUi("dialog.ui", self)
self.mid_label.setText(My_Window.mid_label_nexttext)
class My_Window(QMainWindow):
def __init__(self):
super(My_Window, self).__init__()
loadUi("mainwindow.ui", self)
self.mid_label_nexttext = None
self.height_selecter_spinbox.textChanged.connect(lambda x: self.spin_changed(x))
self.pushButton.clicked.connect(self.onMyPushButtonClick)
def onMyPushButtonClick(self):
dlg = My_Dialog()
if dlg.exec_():
print("Success!")
else:
print("Cancel!")
def spin_changed(self, s):
self.mid_label_nexttext = s
self.update()
def main():
app = QApplication(sys.argv)
window = My_Window()
window.show()
app.exec_()
if __name__ == "__main__":
main()
The main window’s UI:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'mainwindow.ui'
#
# Created by: PyQt5 UI code generator 5.15.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(513, 171)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(310, 80, 75, 23))
self.pushButton.setObjectName("pushButton")
self.layoutWidget = QtWidgets.QWidget(self.centralwidget)
self.layoutWidget.setGeometry(QtCore.QRect(90, 40, 209, 29))
self.layoutWidget.setObjectName("layoutWidget")
self.layout = QtWidgets.QHBoxLayout(self.layoutWidget)
self.layout.setContentsMargins(0, 0, 0, 0)
self.layout.setObjectName("layout")
self.label_firstpart = QtWidgets.QLabel(self.layoutWidget)
font = QtGui.QFont()
font.setPointSize(15)
self.label_firstpart.setFont(font)
self.label_firstpart.setObjectName("label_firstpart")
self.layout.addWidget(self.label_firstpart)
self.height_selecter_spinbox = QtWidgets.QSpinBox(self.layoutWidget)
font = QtGui.QFont()
font.setPointSize(13)
self.height_selecter_spinbox.setFont(font)
self.height_selecter_spinbox.setMinimum(100)
self.height_selecter_spinbox.setMaximum(250)
self.height_selecter_spinbox.setProperty("value", 175)
self.height_selecter_spinbox.setObjectName("height_selecter_spinbox")
self.layout.addWidget(self.height_selecter_spinbox)
self.label_lastpart = QtWidgets.QLabel(self.layoutWidget)
font = QtGui.QFont()
font.setPointSize(15)
self.label_lastpart.setFont(font)
self.label_lastpart.setObjectName("label_lastpart")
self.layout.addWidget(self.label_lastpart)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 513, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "OK"))
self.label_firstpart.setText(_translate("MainWindow", "My height is "))
self.label_lastpart.setText(_translate("MainWindow", "cm."))
The dialog’s UI:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'dialog.ui'
#
# Created by: PyQt5 UI code generator 5.15.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(400, 300)
self.dialog_buttonbox = QtWidgets.QDialogButtonBox(Dialog)
self.dialog_buttonbox.setGeometry(QtCore.QRect(30, 240, 341, 32))
self.dialog_buttonbox.setOrientation(QtCore.Qt.Horizontal)
self.dialog_buttonbox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.dialog_buttonbox.setObjectName("dialog_buttonbox")
self.widget = QtWidgets.QWidget(Dialog)
self.widget.setGeometry(QtCore.QRect(80, 90, 151, 41))
self.widget.setObjectName("widget")
self.dialog_layout = QtWidgets.QHBoxLayout(self.widget)
self.dialog_layout.setContentsMargins(0, 0, 0, 0)
self.dialog_layout.setObjectName("dialog_layout")
self.left_label = QtWidgets.QLabel(self.widget)
font = QtGui.QFont()
font.setPointSize(12)
self.left_label.setFont(font)
self.left_label.setObjectName("left_label")
self.dialog_layout.addWidget(self.left_label)
self.mid_label = QtWidgets.QLabel(self.widget)
font = QtGui.QFont()
font.setPointSize(12)
self.mid_label.setFont(font)
self.mid_label.setObjectName("mid_label")
self.dialog_layout.addWidget(self.mid_label)
self.right_label = QtWidgets.QLabel(self.widget)
font = QtGui.QFont()
font.setPointSize(12)
self.right_label.setFont(font)
self.right_label.setObjectName("right_label")
self.dialog_layout.addWidget(self.right_label)
self.retranslateUi(Dialog)
self.dialog_buttonbox.accepted.connect(Dialog.accept)
self.dialog_buttonbox.rejected.connect(Dialog.reject)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.left_label.setText(_translate("Dialog", "You are"))
self.mid_label.setText(_translate("Dialog", "100"))
self.right_label.setText(_translate("Dialog", "cm tall."))
I would appreciate some help on fixing this error, and on why it occured.
You are trying to access an attribute that does not exist:
self.mid_label.setText(My_Window.mid_label_nexttext)
My_Window is a class, while mid_label_nexttext was assigned to the instance of that class (self is always the reference to the current instance).
If you want to set the text for that label from a "parent" window, you either add an extra argument to the __init__ that allows to get the text, or you set it from the main window.
Use the text as init argument
class My_Dialog(QDialog):
def __init__(self, text):
super(My_Dialog, self).__init__()
loadUi("dialog.ui", self)
# ensure that "text" is a valid string, you can't use setText(None)
if text:
self.mid_label.setText(text)
class My_Window(QMainWindow):
# ...
def onMyPushButtonClick(self):
dlg = My_Dialog(self.mid_label_nexttext)
# ...
Set the text from the parent
class My_Dialog(QDialog):
def __init__(self):
super(My_Dialog, self).__init__()
loadUi("dialog.ui", self)
# NO setText() here!!!
class My_Window(QMainWindow):
# ...
def onMyPushButtonClick(self):
dlg = My_Dialog()
if self.mid_label_nexttext:
dlg.mid_label.setText(self.mid_label_nexttext)
# ...
Note that the first method is usually better, mostly for modularity reasons: let's say that you create that dialog from different classes in different situations, whenever you need to change the object name of the label (or the whole interface structure) you can easily change its reference in the dialog subclass, otherwise you'll need to change every reference in your code.
Note: the call to self.update() is useless; if you want to update the label on the dialog whenever the spinbox value is changed, you need to directly access the label (like in the last example) or use signals. Also, you don't need to use lambda if you're using the same argument parameter, just connect to the function.

why a RuntimeError: wrapped C/C++ object of type QPlainTextEdit has been delete appears after running a PyQt5 GUI to display other windows

I am trying to let a user choose from a GUI a choice of procedures to be executed. Without the GUI section, i can execute the procedures and both appear at the same time on separate windows that i can run independently. Now i want the user to choose from a GUI which procedure to run first to avoid multiple windows open at the same time. While the procedures execute properly when i choose the second pushbutton i have this error message : RuntimeError: wrapped C/C++ object of type QPlainTextEdit has been deleted. I ve seen this issue around and tried what has been proposed but without success. Following sugestions from
[https://stackoverflow.com/questions/63302430/call-different-window-classes-into-a-main-window-in-pqt5-python], I tried to reduce the code as much as possible. Despite some specific packages utilized these are not responsible for the error observed and anyone should be able to run this code. the Mainwindow class is already using Qt for displaying a window but when used standalone i do not have any error. The error is inherent to the Ui_MainWindow(object) class, i also tried with item list the same issue occurs.The error appears each time i press Queue when choosing the Run 2 procedure.
import logging
log = logging.getLogger(__name__)
log.addHandler(logging.NullHandler())
import sys
import random
import pandas as pd
from pymeasure.log import console_log
from pymeasure.display.Qt import QtGui
from PyQt5 import QtCore, QtGui, QtWidgets
from pymeasure.display.windows import ManagedWindow
from pymeasure.experiment import Procedure, Results
from pymeasure.experiment import IntegerParameter, FloatParameter, Parameter
import tempfile
# this class uses the Pymeasure package to run and display experiments here it s just generating a random number. the iterations
#number being the input parameter on the window and one can queue several runs
# execute is the method generating the random number and Mainwindow is the dipsplay and the queue of the runs. the data are
# save in a temp file
class RandomProcedure_1(Procedure):
iterations = IntegerParameter('Loop Iterations', default=10)
DATA_COLUMNS = ['Iteration', 'Random Number']
#
def startup(self):
log.info("Setting the time of the random number generator")
random.seed(self.seed)
def execute(self):
log.info("Starting the loop of %d iterations" % self.iterations)
for i in range(self.iterations):
data = {
'Iteration': i,
'Random Number': random.randint(1, 50)
}
self.emit('results', data)
log.debug("Emitting results: %s" % data)
if self.should_stop():
log.warning("Caught the stop flag in the procedure")
break
class MainWindow_1(ManagedWindow):
# this define the window where the random number vs iteration plot is displayed
def __init__(self):
super(MainWindow_1, self).__init__(
procedure_class=RandomProcedure_1,
inputs=['iterations'],
displays=['iterations'],
x_axis='Iteration',
y_axis='Random Number',
)
self.setWindowTitle('RandomProcedure_1')
def queue(self, *, procedure=None):
if procedure is None:
procedure = self.make_procedure()
filename = tempfile.mktemp()
log.info("Constructing the Results with a data file: %s" % filename)
results = Results(procedure, filename)
experiment = self.new_experiment(results)
self.manager.queue(experiment)
# the GUI with 2 pushbuttons for each procedure (here the same duplicated for simplicity)
# i also tried with a list of item but the same error occurs
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(110, 160, 112, 34))
self.pushButton.setObjectName("EXP1")
self.pushButton.clicked.connect(self.startProcedure_1)
self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_2.setGeometry(QtCore.QRect(580, 170, 112, 34))
self.pushButton_2.setObjectName("EXP2")
self.pushButton_2.clicked.connect(self.startProcedure_1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def startProcedure_1(self):
self.window = MainWindow_1()
self.window.show()
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Procedures"))
self.pushButton.setText(_translate("MainWindow", "Run 1"))
self.pushButton_2.setText(_translate("MainWindow", "Run 2"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())

Timer Using QTime in PyQt5

I used this code to manage a countdown using PyQt5. code -
import time
import serial
from PyQt5 import QtCore
argument = serial.Serial('COM5',9600)
countDown = 9999
def timerEvent():
global time
time = time.addSecs(-1)
global argument
global new
data = time.toString("mmss")
print(data)
argument.write(data.encode());
if data == '0000':
argument.close()
timer.stop()
global countDown
countDown = data
time.sleep(2);
app = QtCore.QCoreApplication(sys.argv)
timer = QtCore.QTimer()
time = QtCore.QTime(0, 1,0)
timer.timeout.connect(timerEvent)
timer.start(200)
But i want is i will input the minute and increment value using a GUI.But, can not implement. Any suggestions how can i implement that?
heres my GUI
I created a new self function under class Ui_Mainwindow that connects the button to implement timer. However, it always says self error. i know how to get the lineEdit values but when i want to put it in
line 38 time = QtCore.QTime(0, 1,0) it shows self error. again the line no 40 timer.timeout.connect(timerEvent) timerevent shows error.
any idea how to implement using the GUI ? Sorry for my poor explanation. is there any other way to do this?
heres the code, i just tried to do similar like base code mentioned above.
import time
countDown = 9999
from PyQt5 import QtCore, QtGui, QtWidgets
inc = 9999
newTime = 9999
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
self.groupBox.setGeometry(QtCore.QRect(70, 180, 131, 121))
self.groupBox.setTitle("")
self.groupBox.setObjectName("groupBox")
self.label_2 = QtWidgets.QLabel(self.groupBox)
self.label_2.setGeometry(QtCore.QRect(6, 50, 51, 20))
self.label_2.setObjectName("label_2")
self.lineEdit_Time = QtWidgets.QLineEdit(self.groupBox)
self.lineEdit_Time.setGeometry(QtCore.QRect(60, 20, 61, 20))
self.lineEdit_Time.setObjectName("lineEdit_Time")
self.lineEdit_Increment = QtWidgets.QLineEdit(self.groupBox)
self.lineEdit_Increment.setGeometry(QtCore.QRect(60, 50, 61, 20))
self.lineEdit_Increment.setObjectName("lineEdit_Increment")
self.pushButton_Start = QtWidgets.QPushButton(self.groupBox)
self.pushButton_Start.setGeometry(QtCore.QRect(10, 90, 111, 23))
self.pushButton_Start.setObjectName("pushButton_Start")
self.label = QtWidgets.QLabel(self.groupBox)
self.label.setGeometry(QtCore.QRect(10, 20, 47, 13))
self.label.setObjectName("label")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.pushButton_Start.clicked.connect(self.update)
global inc
inc = self.lineEdit_Time.text()
global newTime
newTime = self.lineEdit_Increment.text()
def update(self):
global time
time = time.addSecs(-1)
global argument
global new
data = time.toString("mmss")
print(data)
argument.write(data.encode());
if data == '0000':
timer.stop()
global countDown
countDown = data
return time
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label_2.setText(_translate("MainWindow", "Increment"))
self.pushButton_Start.setText(_translate("MainWindow", "START"))
self.label.setText(_translate("MainWindow", "Time"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
global time
timer = QtCore.QTimer()
time = QtCore.QTime(0, inc,0)
timer.timeout.connect(update)
timer.start(newTime)
MainWindow.show()
sys.exit(app.exec_())
Something like this? You want to access your increment and start time from the text values of the self.lineEdit_Time and self.lineEdit_Increment widgets. Then you use this in a start_timer method, which you connect to the start buttons clicked signal.
In the start_timer method, we create a timer which is a member of the main_window object,
and this timer's timeout signal is connected to our update_clock method, which updates the countdown based on the self.increment value.
class Ui_MainWindow(object):
#...
self.pushButton_Start.pressed.connect(self.start_timer)
def start_timer(self):
self.countdown = int(self.lineEdit_Time.text())
self.increment = int(self.lineEdit_Increment.text())
self.countdownTimer = QtCore.QTimer()
self.countdownTimer.timeout.connect(self.update_clock)
self.countdownTimer.start(1000) # fires every 1000ms = 1s
def update_clock(self):
self.countdown -= self.increment
#update a clock label that shows the countdown value
self.clockLabel.setText(self.countdown)
#or just print the vaule for now
print(self.countdown)

PyQt5 - cannot create new widgets dynamically on button press to function [duplicate]

I have a method named 'test()' that loads 3 one-row tables into a scrollbar.
For some reason that I cannot figure out, however, the while it works if I simply activate test() on load, it doesn't work if I comment it out and then try to activate it via the push of a button.
Here is the main module (with test())
from PyQt5 import QtCore, QtWidgets
from design import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
self.setupUi(self)
#test(self)
def test(self):
from random import randint
x = randint(0, 99)
print(x)
height = 30
yPos = 0
for i in range(3):
rowVals = ['test%s' % str(x + i)]
qTbl = QtWidgets.QTableWidget(self.sawDoc)
qTbl.setObjectName("tbl%s" % (i))
qTbl.setGeometry(QtCore.QRect(0, yPos, 880, height))
qTbl.horizontalHeader().setVisible(False)
qTbl.verticalHeader().setVisible(False)
yPos += height
qTbl.setRowCount(1)
qTbl.setColumnCount(len(rowVals))
for r, cell in enumerate(rowVals):
item = QtWidgets.QTableWidgetItem()
item.setText(str(cell))
qTbl.setItem(0, r, item)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
And here is the design module (with the button)
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(896, 453)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.scrDoc = QtWidgets.QScrollArea(self.centralwidget)
self.scrDoc.setGeometry(QtCore.QRect(0, 0, 891, 391))
self.scrDoc.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.scrDoc.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.scrDoc.setWidgetResizable(False)
self.scrDoc.setObjectName("scrTest")
self.sawDoc = QtWidgets.QWidget()
self.sawDoc.setGeometry(QtCore.QRect(0, 0, 869, 300))
self.sawDoc.setObjectName("sawDoc")
self.scrDoc.setWidget(self.sawDoc)
self.btnTest = QtWidgets.QPushButton(self.centralwidget)
self.btnTest.setGeometry(QtCore.QRect(430, 400, 80, 15))
self.btnTest.setObjectName("btnTest")
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.btnTest.clicked.connect(self.test)
def test(self):
import main
main.test(self)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "昊珩のCAT工具"))
self.btnTest.setText(_translate("MainWindow", "Test"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Simply nothing happens when I push the button (except for the print out working successfully).
Can someone tell what's wrong?
The parents show the children at the beginning, but afterwards it is the responsibility of the children to show themselves, the simple solution is to use show():
qTbl = QtWidgets.QTableWidget(self.sawDoc)
qTbl.show()
But I see that you are implementing the solution in an inelegant way, the connection do it in main.py, do not modify the file generated by Qt Designer (delete the connection and the test method in design.py)
You must use a layout and there add the QTableWidget.
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
self.setupUi(self)
self.btnTest.clicked.connect(self.test)
def test(self):
from random import randint
x = randint(0, 99)
lay = QtWidgets.QVBoxLayout(self.sawDoc)
for i in range(3):
rowVals = ['test%s' % str(x + i)]
qTbl = QtWidgets.QTableWidget()
qTbl.setObjectName("tbl%s" % (i))
qTbl.horizontalHeader().hide()
qTbl.verticalHeader().hide()
qTbl.setRowCount(1)
qTbl.setColumnCount(len(rowVals))
for r, cell in enumerate(rowVals):
item = QtWidgets.QTableWidgetItem()
item.setText(str(cell))
qTbl.setItem(0, r, item)
qTbl.resize(qTbl.sizeHint())
lay.addWidget(qTbl)

Categories