Using Qt Designer, and python2.7. I am trying to create a "count up" timer out of a Qt Designer button and LCD number. I would like a single button to start and reset the timer and the LCD number to display the amount of time that has passed with hh:mm:ss format. I am also trying to have a window "pop-up" at 40 minutes, and display a message "Good Job You Made It!"
I have searched for answers, tried many different combinations of google searches... and now all my results are showing up purple (I've already followed the link)! LOL I see many examples in other languages and for countdown timers and for, what seems like, any other and all other combinations of timers and languages... but none for python! Seriously, I've been trying to figure this out for days, and just haven't got anywhere with it.
Below is the code that I do have. I'm thinking the part I need is the rest of the "def doStartReset(self):" function/method.
Hope I am clear enough. Thanks!
#!/usr/bin/python2.7
import sys
from PyQt4 import QtGui,QtCore
from timer_ui import *
class MyForm(QtGui.QMainWindow):
def __init__(self, parent=None):
#build parent user interface
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
QtCore.QObject.connect(self.ui.btnStartReset, QtCore.SIGNAL('clicked()'), self.doStartReset)
def doStartReset(self):
if __name__ == "__main__":
#This function means this was run directly, not called from another python file.
app = QtGui.QApplication(sys.argv)
myapp = MyForm()
myapp.show()
sys.exit(app.exec_())
Here is the code for the GUI in _ui.py format if you need it.
# -*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8 except AttributeError:
_fromUtf8 = lambda s: s
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(340, 205)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.widget = QtGui.QWidget(self.centralwidget)
self.widget.setGeometry(QtCore.QRect(40, 50, 261, 81))
self.widget.setObjectName(_fromUtf8("widget"))
self.gridLayout = QtGui.QGridLayout(self.widget)
self.gridLayout.setMargin(0)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.btnStartReset = QtGui.QPushButton(self.widget)
self.btnStartReset.setObjectName(_fromUtf8("btnStartReset"))
self.gridLayout.addWidget(self.btnStartReset, 0, 0, 1, 1)
self.lcd40MinTimer = QtGui.QLCDNumber(self.widget)
self.lcd40MinTimer.setObjectName(_fromUtf8("lcd40MinTimer"))
self.gridLayout.addWidget(self.lcd40MinTimer, 0, 1, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
self.btnStartReset.setText(QtGui.QApplication.translate("MainWindow", "Start / Reset", None, QtGui.QApplication.UnicodeUTF8))
Thank you in advance.
Hey Guys.. here is some progress that i've made... sad that its taken me three days to accomplish this much, but hey, none the less it is progress! Now i am going to work on setting format to hh:mm:ss and have button function include start, stop, and reset... Maybe this will help some people and maybe someone can help me! Together I am convinced that we can make it happen! CHEERS!!!
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.lcd = QtGui.QLCDNumber(self)
self.lcd.setGeometry(30, 40, 200, 25)
self.btn = QtGui.QPushButton('Start', self)
self.btn.move(40, 80)
self.btn.clicked.connect(self.doAction)
self.timer = QtCore.QBasicTimer()
self.step = 0
self.setGeometry(300, 300, 280, 170)
self.setWindowTitle('QtGui.QLCDNumber')
self.show()
def timerEvent(self, e):
if self.step >= 100:
self.timer.stop()
self.btn.setText('Finished')
return
self.step = self.step + 1
self.lcd.display(self.step)
def doAction(self):
if self.timer.isActive():
self.timer.stop()
self.btn.setText('Start')
else:
self.timer.start(100, self)
self.btn.setText('Stop')
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
xopenex, some time ago I've coded a count-up timer in Python using Qt. Could this be what you've been looking for?
https://github.com/twigmac/count-up-timer
Related
I have a GUI made in Designer (pyqt5). A function in my main class needs to work on a separate thread. I also catch the stdout on a QtextEdit LIVE during operations. Everything so far works.
Right now I'm trying to implement a ProgressBar onto my main GUI form. The bar needs to show live progression just like it does on the textEdit.
The example code below works on Linux without any warnings. But on Windows I get the error:
QObject::setParent: Cannot set parent, new parent is in a different thread
I know that this is due to me having a ui element modification within my threaded function. I did my research but all the answers point to using QThreads (just when I started to understand basic threading!). I would prefer a way to update my GUI without having to change the current threading system below.
Here is the example code:
import sys
import threading
import time
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtGui import QTextCursor
from ui_form import Ui_Form
class EmittingStream(QObject):
textWritten = pyqtSignal(str)
def write(self, text):
self.textWritten.emit(str(text))
class Form(QMainWindow):
finished = pyqtSignal()
def __init__(self, parent=None):
super(Form, self).__init__(parent)
# Install the custom output stream
sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)
self.ui = Ui_Form()
self.ui.setupUi(self)
self.ui.pushButton_run.clicked.connect(self.start_task)
self.finished.connect(self.end_task)
def start_task(self):
self.thread = threading.Thread(target=self.run_test)
self.thread.start()
self.ui.pushButton_run.setEnabled(False)
def end_task(self):
self.ui.pushButton_run.setEnabled(True)
def __del__(self):
# Restore sys.stdout
sys.stdout = sys.__stdout__
def normalOutputWritten(self, text):
"""Append text to the QTextEdit."""
cursor = self.ui.textEdit.textCursor()
cursor.movePosition(QTextCursor.End)
cursor.insertText(text)
self.ui.textEdit.setTextCursor(cursor)
self.ui.textEdit.ensureCursorVisible()
def run_test(self):
for i in range(100):
per = i + 1
self.ui.progressBar.setValue(per)
print("%%%s" % per)
time.sleep(0.15) # simulating expensive task
print("Task Completed!")
time.sleep(1.5)
self.ui.progressBar.reset()
self.finished.emit()
def main():
app = QApplication(sys.argv)
form = Form()
form.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
the ui:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'form.ui'
#
# Created: Mon Apr 30 13:43:19 2018
# by: PyQt5 UI code generator 5.2.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(Form)
self.centralwidget.setObjectName("centralwidget")
self.pushButton_run = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_run.setGeometry(QtCore.QRect(40, 20, 311, 191))
self.pushButton_run.setObjectName("pushButton_run")
self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
self.textEdit.setGeometry(QtCore.QRect(40, 230, 721, 241))
self.textEdit.setObjectName("textEdit")
self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
self.progressBar.setGeometry(QtCore.QRect(40, 490, 721, 23))
self.progressBar.setObjectName("progressBar")
Form.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(Form)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 25))
self.menubar.setObjectName("menubar")
Form.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(Form)
self.statusbar.setObjectName("statusbar")
Form.setStatusBar(self.statusbar)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "MainWindow"))
self.pushButton_run.setText(_translate("Form", "RUN"))
Somehow I need to -instantly- inform the gui thread (from my running thread) that the progress bar value is changing (a process that could take up minutes to complete).
Define a custom signal that sends updates to the progress-bar:
class Form(QMainWindow):
finished = pyqtSignal()
updateProgress = pyqtSignal(int)
def __init__(self, parent=None):
super(Form, self).__init__(parent)
...
self.updateProgress.connect(self.ui.progressBar.setValue)
def run_test(self):
for i in range(100):
per = i + 1
self.updateProgress.emit(per)
...
I am trying to get stdout and error messages to show on my main window. The window is by pyqt and made via designer. I have a QTextEdit on it. This is where the output should show itself. Also I have a dialog box (again made via designer) where i set some settings for my program before running it. The dialog box is opened like this:
def open_settings(self):
dialog = SettingsDialog()
dialog.open_settings_tab() # its on a tab widget
I already read and used the info on these links to achieve my goal:
Print out python console output to Qtextedit
How to capture output of Python's interpreter and show in a Text widget?
Both are pretty much the same with different object names. The issue I'm having is that whenever I open a dialog box and return to the main window the stdout no longer shows itself on the QTextEdit. Instead it goes back to showing itself on Sublime Editor.
I believe it has something to do with the class instancing.
Here is how the Dialog class starts:
class SettingsDialog(QDialog):
def __init__(self, parent=None):
super(SettingsDialog, self).__init__(parent)
self.ui = Ui_SettingsDialog()
self.ui.setupUi(self)
and finally here is how my main window (form) class starts:
class MyForm(QMainWindow):
def __init__(self, parent=None):
super(MyForm, self).__init__(parent)
# Install the custom output stream
sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)
self.ui = Ui_MyForm()
self.ui.setupUi(self)
Any ideas of why the stdout stops working (in qtextedit) once i go into the dialog screen and come back?
NEW Update:
The code is very long. I made a small program thats showing the issue:
PS: I found that the problem is related with this line shown below:
self.ui.pushButton_path.clicked.connect(Form(self).change_path)
if i comment it out the problem goes away.. But I need to call that function (which opens a QDialog, from the main form). What is the proper way?
main:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog
from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtGui import QTextCursor
from ui_form import Ui_Form
from ui_dialog import Ui_Dialog
class EmittingStream(QObject): # test
textWritten = pyqtSignal(str)
def write(self, text):
self.textWritten.emit(str(text))
class Form(QMainWindow):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
# Install the custom output stream
sys.stdout = EmittingStream(textWritten=self.normalOutputWritten) # test
self.ui = Ui_Form()
self.ui.setupUi(self)
self.ui.pushButton_open.clicked.connect(self.open_dialog)
self.ui.pushButton_text.clicked.connect(self.test_write)
def __del__(self): # test
# Restore sys.stdout
sys.stdout = sys.__stdout__
def normalOutputWritten(self, text): # test
"""Append text to the QTextEdit."""
# Maybe QTextEdit.append() works as well, but this is how I do it:
# self.ui.tEdit_cli.insertPlainText(text)
cursor = self.ui.textEdit.textCursor()
cursor.movePosition(QTextCursor.End)
cursor.insertText(text)
self.ui.textEdit.setTextCursor(cursor)
self.ui.textEdit.ensureCursorVisible()
def open_dialog(self):
dialog = Dialog()
dialog.open_tab()
def test_write(self):
print("something written")
def change_path(self):
pass
class Dialog(QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.pushButton_close.clicked.connect(self.close_dialog)
self.ui.pushButton_path.clicked.connect(Form(self).change_path) # this is what causes the issue. but i need to use it!
def open_tab(self):
self.ui.tabWidget.setCurrentIndex(0)
self.exec_()
def close_dialog(self):
self.close()
def main():
app = QApplication(sys.argv)
form = Form()
form.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
ui_dialog:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'dialog.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(400, 300)
self.horizontalLayout = QtWidgets.QHBoxLayout(Dialog)
self.horizontalLayout.setObjectName("horizontalLayout")
self.tabWidget = QtWidgets.QTabWidget(Dialog)
self.tabWidget.setObjectName("tabWidget")
self.tab = QtWidgets.QWidget()
self.tab.setObjectName("tab")
self.pushButton_close = QtWidgets.QPushButton(self.tab)
self.pushButton_close.setGeometry(QtCore.QRect(100, 80, 211, 131))
self.pushButton_close.setObjectName("pushButton_close")
self.pushButton_path = QtWidgets.QPushButton(self.tab)
self.pushButton_path.setGeometry(QtCore.QRect(30, 30, 75, 23))
self.pushButton_path.setObjectName("pushButton_path")
self.tabWidget.addTab(self.tab, "")
self.tab_2 = QtWidgets.QWidget()
self.tab_2.setObjectName("tab_2")
self.tabWidget.addTab(self.tab_2, "")
self.horizontalLayout.addWidget(self.tabWidget)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton_close.setText(_translate("Dialog", "close"))
self.pushButton_path.setText(_translate("Dialog", "path"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("Dialog", "Tab 1"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("Dialog", "Tab 2"))
"""
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
"""
ui_form:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'form.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(Form)
self.centralwidget.setObjectName("centralwidget")
self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
self.textEdit.setGeometry(QtCore.QRect(90, 230, 601, 271))
self.textEdit.setObjectName("textEdit")
self.pushButton_open = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_open.setGeometry(QtCore.QRect(140, 80, 241, 81))
self.pushButton_open.setObjectName("pushButton_open")
self.pushButton_text = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_text.setGeometry(QtCore.QRect(440, 80, 251, 81))
self.pushButton_text.setObjectName("pushButton_text")
Form.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(Form)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
self.menubar.setObjectName("menubar")
Form.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(Form)
self.statusbar.setObjectName("statusbar")
Form.setStatusBar(self.statusbar)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "MainWindow"))
self.pushButton_open.setText(_translate("Form", "open dialog"))
self.pushButton_text.setText(_translate("Form", "write somthing"))
"""
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QMainWindow()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
"""
You must use the object to invoke a method, you must not use the class, so the instruction Form(self) is not valid.
You must make the connection where you can access the signal and the slot simultaneously, for example open_dialog would be a good place:
class Form(QMainWindow):
...
def open_dialog(self):
dialog = Dialog(self)
dialog.ui.pushButton_path.clicked.connect(self.change_path) # +++
dialog.open_tab()
def test_write(self):
print("something written")
def change_path(self):
pass
class Dialog(QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.pushButton_close.clicked.connect(self.close_dialog)
# self.ui.pushButton_path.clicked.connect(Form(self).change_path) ---
...
I have class Ui_MainWindow(object) that creates a window with a progress bar and class OtherClass(object) that contains method in which the local int variable increments in cycle.
How to connect local variable value change to progres bar value change?
mainGUI.py
import sys
from PyQt4.uic.Compiler.qtproxies import QtGui
from PyQt4 import QtGui
from Ui_MainWindow import Ui_MainWindow
def main():
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Ui_MainWindow.py
from PyQt4 import QtCore, QtGui
from MainGui.OtherClass import OtherClass
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
class Ui_MainWindow(object):
def myButtonSlot(self):
objVar=OtherClass()
objVar.method()
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(389, 332)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.pushButton = QtGui.QPushButton(self.centralwidget)
self.pushButton.setObjectName(_fromUtf8("pushButton"))
self.pushButton.clicked.connect(self.myButtonSlot)
self.verticalLayout.addWidget(self.pushButton)
self.progressBar = QtGui.QProgressBar(self.centralwidget)
self.progressBar.setProperty("value", 24)
self.progressBar.setObjectName(_fromUtf8("progressBar"))
self.verticalLayout.addWidget(self.progressBar)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 389, 21))
self.menubar.setObjectName(_fromUtf8("menubar"))
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName(_fromUtf8("statusbar"))
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
self.pushButton.setText(QtGui.QApplication.translate("MainWindow", "PushButton", None, QtGui.QApplication.UnicodeUTF8))
OtherClass.py
class OtherClass(object):
def method(self):
for i in range(100): # i want to connect variable i to progress bar value
print i
for j in range(100500):
pass
You need to re-organize your code a little bit.
Firstly, you should never edit the code in the UI module generated by pyuic. Instead, import it into your main module and implement all your application logic there.
Secondly, you should create a main-window class in your main module, and do all the setup inside its __init__ method.
One way to solve your problem of connecting the loop variable to the progress bar, is to make OtherClass a subclass of QObject and emit a custom signal:
from PyQt4 import QtCore
class OtherClass(QtCore.QObject):
valueUpdated = QtCore.pyqtSignal(int)
def method(self):
# i want to connect variable i to progress bar value
for i in range(100):
print i
self.valueUpdated.emit(i)
for j in range(100500):
pass
With that in place, you would then move the setup for pushButton and its slot to "mainGUI.py", and re-generate "Ui_MainWindow.py" with pyuic. A slot would then be added to handle the custom valueChanged signal, which would update the progress bar and also process any pending GUI events.
So "mainGUI.py" would end up looking something like this:
import sys
from PyQt4 import QtGui
from Ui_MainWindow import Ui_MainWindow
from OtherClass import OtherClass
class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setupUi(self)
self.pushButton.clicked.connect(self.myButtonSlot)
self.otherclass = OtherClass(self)
self.otherclass.valueUpdated.connect(self.handleValueUpdated)
def myButtonSlot(self):
self.otherclass.method()
def handleValueUpdated(self, value):
self.progressBar.setValue(value)
QtGui.qApp.processEvents()
def main():
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The following post has a version that increments the progress bar 10% each time you press the button. And a version which uses a timer to increment the progress bar. (I'm just in the process of learning this myself)
In Qt Designer, add a progress bar and a button. Click on 'Edit Signals/Slots', drag a line from the button to somewhere in the window and when the button is 'pressed()' add a slot(or signal??) called 'button_pressed()' (use the + button to make this). When you have done this, the OK button is greyed out - select the slot you made, and press OK.
Save the file as ui_MainWindow.ui (note the capitals carefully).
Convert to a py file using the batch file >
pyuic4 -x ui_MainWindow.ui -o ui_MainWindow.py
This file should look something like....(you don't need to edit this).
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(800, 600)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.progressBar = QtGui.QProgressBar(self.centralwidget)
self.progressBar.setGeometry(QtCore.QRect(110, 90, 118, 23))
self.progressBar.setProperty("value", 24)
self.progressBar.setObjectName(_fromUtf8("progressBar"))
self.pushButton = QtGui.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(120, 200, 75, 23))
self.pushButton.setObjectName(_fromUtf8("pushButton"))
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
self.menubar.setObjectName(_fromUtf8("menubar"))
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName(_fromUtf8("statusbar"))
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL(_fromUtf8("pressed()")), MainWindow.button_pressed)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
self.pushButton.setText(_translate("MainWindow", "PushButton", None))
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Create a 'program.py' file. This is the file you will run...
import sys
from PyQt4 import QtGui
#from PyQt5 import QtCore, QtGui, QtWidgets #works for pyqt5
from mainWindow import MainWindow
def main():
#app = QtWidgets.QApplication (sys.argv) #works for pyqt5
app = QtGui.QApplication (sys.argv) #works for pyqt4
m = MainWindow ()
m.show ()
sys.exit (app.exec_ () )
if __name__ == '__main__':
main ()
Now this is where the good stuff happens when you subclass the mainwindow. Call this file 'mainWindow.py'. Careful with the capitalizations.
from PyQt4 import QtCore, QtGui
from ui_MainWindow import Ui_MainWindow #note the capitalization
class MainWindow (QtGui.QMainWindow):
def __init__ (self, parent = None):
super (MainWindow, self).__init__ ()
self.ui = Ui_MainWindow ()
self.ui.setupUi (self)
#------------do your custom stuff from here on-----------
self.progress = 0 #Start value of progress bar
self.ui.progressBar.setValue(self.progress)
def button_pressed(self):
print('button pressed')
self.ui.statusbar.showMessage(str(self.progress)) #this is at bottom left of window. Discovered this accidentially when doing this!
self.ui.progressBar.setValue(self.progress)
self.progress+=10
There is a good tutorial here which I used to create an alternate 'mainWindow.py' which uses a timer to increment the progress bar. It does not block the code with a loop using sleep or by doing a CPU intensive loop. I don't understand multithreading, multi-processor options yet to comment on using these.
#from PyQt5 import QtCore, QtGui, QtWidgets #works for PyQt5
from PyQt4 import QtCore, QtGui
from ui_MainWindow import Ui_MainWindow #note the capitalization
class MainWindow (QtGui.QMainWindow):
def __init__ (self, parent = None):
super (MainWindow, self).__init__ ()
self.ui = Ui_MainWindow () #same name as appears in mainWindowUi.py
self.ui.setupUi (self)
self.progress = 0 #Start value of progress bar
self.ui.progressBar.setValue(self.progress)
self.timer = QtCore.QBasicTimer()
def button_pressed(self):
self.timerEvent(64) #this needs an argument to work but I'm not sure what is is yet so I just put in some random number
def timerEvent(self, e):
self.ui.progressBar.setValue(self.progress)
if self.progress >=100:
self.timer.stop()
else:
if self.timer.isActive():
pass
else:
self.timer.start(10,self) #10 milliseconds
self.progress+=1
You have to use a signal and slot...and multiprocessing or multithreading.
There's a good example here that specifically takes you through the progress bar:
ZetCode Progress Bar
Also, question has been answered here before:
SO Progress Bar
I want to create a simple programm (in QtDesigner) that executes a function when button is clicked, and displays the value of this function in a LineEdit.
And here is my code:
class MyForma1(object):
def AddWidgets1(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(613, 545)
self.pushButton = QtGui.QPushButton(Form)
self.pushButton.setGeometry(QtCore.QRect(244, 352, 111, 51))
self.pushButton.setObjectName(_fromUtf8("pushButton"))
self.lineEdit = QtGui.QLineEdit(Form)
self.lineEdit.setGeometry(QtCore.QRect(242, 290, 111, 20))
self.lineEdit.setObjectName(_fromUtf8("lineEdit"))
self.retranslateUi(Form)
QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL(_fromUtf8("clicked()")), Form.changeText)
def retranslateUi(self, Form):
self.pushButton.setText(_translate("Form", "Click me", None))
self.lineEdit.setText(_translate("Form", "functionvalue", None))
class MyForma2(QtGui.QDialog, MyForma1):
def __init__(self, z11=0):
QtGui.QDialog.__init__(self)
self.AddWidgets1(self)
self.z = z11
def myfunc1(self):
self.z+=1
def changeText(self):
self.myfunc1()
self.lineEdit.setText(str(self.z))
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
Forma = MyForma2()
Forma.show()
sys.exit(app.exec_())
Actually, it works fine, but i dont like the way it is done, i want to make it more exquisite. The problem here, is that the button "executes" a function and value translation together.
And i think it would be better if the button executes only a function and additionaly there is something that constantly translates the value of this function to LineEdit separately from the button. For example, there could be a situation when the function value, which needs to be constantly monitored, could be affected not only by the button, but also by some other events (ex: incoming signal from COM-port). And in this case, it would be great to emmit a signal every time the function is changed, not only when button is pressed.
Checkout this example:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
#---------
# IMPORT
#---------
from PyQt4 import QtGui, QtCore
#---------
# MAIN
#---------
class MyWindow(QtGui.QWidget):
valueChanged = QtCore.pyqtSignal(int)
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.value = 0
self.pushButtonAdd = QtGui.QPushButton(self)
self.pushButtonAdd.setText("Add!")
self.pushButtonAdd.clicked.connect(self.on_pushButtonAdd_clicked)
self.pushButtonSubtract = QtGui.QPushButton(self)
self.pushButtonSubtract.setText("Subtract!")
self.pushButtonSubtract.clicked.connect(self.on_pushButtonSubtract_clicked)
self.lineEditValue = QtGui.QLineEdit(self)
self.lineEditValue.setText(str(self.value))
self.layoutVertical = QtGui.QVBoxLayout(self)
self.layoutVertical.addWidget(self.pushButtonAdd)
self.layoutVertical.addWidget(self.pushButtonSubtract)
self.layoutVertical.addWidget(self.lineEditValue)
#QtCore.pyqtSlot()
def on_pushButtonAdd_clicked(self):
self.valueChanged.emit(1)
#QtCore.pyqtSlot()
def on_pushButtonSubtract_clicked(self):
self.valueChanged.emit(-1)
def setValue(self, value):
self.value += value
self.lineEditValue.setText(str(self.value))
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWindow')
main = MyWindow()
main.resize(333, 111)
main.valueChanged.connect(main.setValue)
main.show()
sys.exit(app.exec_())
In this example, to change the value manually you can call main.setValue(34)
I wrote the following program which draws a minefield for game the sapper
# -*- coding: utf-8 -*-
import mainw, sys
from PyQt4 import QtCore, QtGui
class WindowSapper(QtGui.QMainWindow):
buttons=[]
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self,parent)
self.ui=mainw.Ui_mainwin()
self.ui.setupUi(self)
for i in xrange(10):
l=[]
for j in xrange(10):
b=QtGui.QPushButton()
l.append(b)
self.ui.gridLayout.addWidget(b, i, j, 1, 1)
self.buttons.append(l)
def main():
app=QtGui.QApplication(sys.argv)
window=WindowSapper()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I apply also the form module
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'mainw.ui'
#
# Created: Tue Nov 27 08:52:39 2012
# by: PyQt4 UI code generator 4.9.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
class Ui_mainwin(object):
def setupUi(self, mainwin):
mainwin.setObjectName(_fromUtf8("mainwin"))
mainwin.resize(546, 530)
self.centralwidget = QtGui.QWidget(mainwin)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.gridLayoutWidget = QtGui.QWidget(self.centralwidget)
self.gridLayoutWidget.setGeometry(QtCore.QRect(10, 30, 521, 461))
self.gridLayoutWidget.setObjectName(_fromUtf8("gridLayoutWidget"))
self.gridLayout = QtGui.QGridLayout(self.gridLayoutWidget)
self.gridLayout.setMargin(0)
self.gridLayout.setHorizontalSpacing(6)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
mainwin.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(mainwin)
self.menubar.setGeometry(QtCore.QRect(0, 0, 546, 21))
self.menubar.setObjectName(_fromUtf8("menubar"))
mainwin.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(mainwin)
self.statusbar.setObjectName(_fromUtf8("statusbar"))
mainwin.setStatusBar(self.statusbar)
self.retranslateUi(mainwin)
QtCore.QMetaObject.connectSlotsByName(mainwin)
def retranslateUi(self, mainwin):
mainwin.setWindowTitle(QtGui.QApplication.translate("mainwin", "Сапер", None, QtGui.QApplication.UnicodeUTF8))
class mainwin(QtGui.QMainWindow, Ui_mainwin):
def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()):
QtGui.QMainWindow.__init__(self, parent, f)
self.setupUi(self)
But it did not meet my expectations: the buttons are not completely filled GridLayout, among them there are free spaces, that is, they are not completely filled cell GridLayout. How to get rid of these gaps?
The first reason you are seeing a ton of spacing is actually not because of the QGridLayout, but because nothing is constraining your layout objects to make them bunch up together. What you would need to do is add a stretch to the layout to eat up as much space as possible, forcing the rest of the items to push together.
QGridLayout does allow you to add stretch items to it, but I think that makes the grid more complicated to navigate later because you always have to account for that spacer row/col. So instead you can just wrap the grid layout in a vertical/horizontal layout and add spacers to those.
Once you do this, you will notice a tiny amount of space left between the rows. Apparently this is just a known thing with QGridLayout (see this other question). But you can play with the size of the buttons, and the min size of the row and columns to get it right:
Here is an example (standalone - not needing your UI module)
class WindowSapper(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self,parent)
self.resize(450,350)
self.centralwidget = QtGui.QWidget()
self.setCentralWidget(self.centralwidget)
self.vLayout = QtGui.QVBoxLayout(self.centralwidget)
self.hLayout = QtGui.QHBoxLayout()
self.gridLayout = QtGui.QGridLayout()
self.gridLayout.setSpacing(0)
# center the grid with stretch on both sides
self.hLayout.addStretch(1)
self.hLayout.addLayout(self.gridLayout)
self.hLayout.addStretch(1)
self.vLayout.addLayout(self.hLayout)
# push grid to the top of the window
self.vLayout.addStretch(1)
self.buttons = []
for i in xrange(10):
l=[]
for j in xrange(10):
b=QtGui.QPushButton()
b.setFixedSize(40,30)
l.append(b)
self.gridLayout.addWidget(b, i, j)
self.gridLayout.setColumnMinimumWidth(j, 40)
self.buttons.append(l)
self.gridLayout.setRowMinimumHeight(i, 26)