I have been experimenting around with using QT in python3 and figured out how to make a simple .ui file and import it directly into a python program. However I have to use python QT app while I would like to have my own custom loop in order to be able to add things to it. So what I have now is:
import sys
from PyQt4 import QtCore, QtGui, uic
class MyWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.desktop = uic.loadUi('mytest.ui')
self.desktop.show()
if __name__ == '__main__':
app = QtGui.QApplication.instance()
window = MyWindow()
sys.exit(app.exec_())
I've played around a bit with PGU where I have been able to do this with what would be
while True:
window.loop()
in the main which allows me to put in my own extra code that is unrelated to the GUI without dealing with multiple threads. However I have been unable find some equivalent to "loop" in qt and searching for "qt custom loop/update/blit python" hasn't found anything relevant besides suggestions to add a 0 second timer to my app and place extra code there which seems... inelegant to me. I would like to import a GUI into my app rather then building my app around a GUI.
Edit: Here is my updated code taking Phyatt's answer into account for anyone else looking for the same answer I was.
import sys
from PyQt4 import QtGui, QtCore, uic
class TestApp(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.ui = uic.loadUi('mytest.ui')
self.ui.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
win = TestApp()
app.processEvents()
while True:
app.processEvents()
Instead of using your own custom loop, the more common way to do that is to have a timer event scheduled on the Qt loop, or to launch another thread.
If you still really wanted to use your own loop, you need to manually call QApplication.processEvents() in your loop and it probably should work.
http://qt-project.org/doc/qt-4.8/qcoreapplication.html#processEvents
http://doc.qt.io/qt-5/qtimerevent.html#details
MyWindow.start(100) # start the built in timer event for that QObject 10 times a second
And then in MyWindow put def timerEvent and it should work.
Hope that helps.
Related
Don't critisize me using different classes - the reasons for his is becausethere will be more GUIs in my project created by the QtDesigner, but this should not be important for now.
In general, I have two Python scripts:
main.py:
from PyQt5 import QtCore, QtWidgets, QtGui
import sys
import time
from gui_class import Gui
app = QtWidgets.QApplication(sys.argv)
gui = Gui()
sys.exit(app.exec_())
gui_class.py:
from PyQt5 import QtWidgets
class Gui():
def __init__(self):
w = QtWidgets.QWidget()
w.resize(500, 500)
self.button = QtWidgets.QPushButton(w)
self.button.setGeometry(100, 100, 300, 300)
w.show()
If I run the main.py-script, then the window appears for a split second and disappears right away. I can't see it, I can't click it. The code does not terminate, though. It's still waiting for the application to finish - I can't do anything, though.
If I put a breakpoint before the line saying w.show() in the gui_class.py and simply continue the code after it stopped in that line, then the GUI is visible and I can click the button and the code terminates after I close the window - everything works as expected.
I am using PyQt5: 5.15.2 with Python3.7.
The problem is that w is a local variable that will be destroyed when the scope where it was created finishes executing. The solution is to extend its life cycle by increasing its scope by making it an attribute of the class, for this you must change w with self.w.
i'm having some trouble in building my app, I have a GUI made in pyqt4 and Python, I use QThread to check the cpu load every 2 seconds and I want to diplay it on a progress bar. My GUI is in one class and my Qthread is in the other.
This is my code: pyqt classes, my code printscreen
I want to know how to pass my values collected in QThread to Qobjects in my other Class.
import sys,os,module,config_read,time,threading,datecs_print,mysql.connector as mariadb,commandList
import psutil,logging
from PyQt4 import QtGui, uic ,QtSql,QtCore
from PyQt4.QtCore import QThread, SIGNAL
import resources
import webbrowser
sys.stderr = open("errlog.txt", "w")
class systemValues(QThread):
def __init__(self):
QThread.__init__(self)
def __del__(self):
self.wait()
def cpuRunValue(self):
while (1):
for x in range(2):
p = psutil.cpu_percent(1,False)
return p
def cpuProgressBarUpdate(self):
while(1):
# MyWindow.setcpuBarValue(val=77)
MyWindow.cpuBar.setValue(value=77)
def run(self):
# self.cpuRunValue()
print(self.cpuRunValue())
# self.cpuProgressBarUpdate()
class MyWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QDialog.__init__(self)
super(MyWindow, self).__init__()
file_path = os.path.abspath("ui/sales_window.ui")
uic.loadUi(file_path, self)
self.myThread = systemValues()
self.myThread.start()
def setcpuBarValue(self):
threading.Thread(target=self.cpuBar.setValue(systemValues.cpuRunValue())).start()
This is my code, I get no error. I just cant transfer my value I get from cpuRunValue() to QprogressBar from MyWindow. I'm not very experienced with this.
PS: I eliminated lots of code that's not necessary, but please let me know if you need more info.
Thank You.
If you want to use threads in Qt then you must understand them well. For instance read this page first. Certainly don't mix the QThread with the threading package from the Python standard library.
I hope you're not offended if I think that your probably fairly new to programming. I advise you to not use threads (in general and in Qt) until you have more experience. Threads are hard to use correctly, even for seasoned programmers, and therefore should only be used if necessary. For this reason the Qt documentation on threads even includes a section about alternatives.
You want to execute a function every 2 seconds, so in your case the best solution is to use a QTimer and connect its timeout signal to a slot that updates the progress bar. Like so:
#!/usr/bin/env python
import sys
import psutil
from PyQt5 import QtCore, QtWidgets
class MyWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.layout = QtWidgets.QVBoxLayout()
self.setLayout(self.layout)
self.progressBar = QtWidgets.QProgressBar()
self.layout.addWidget(self.progressBar)
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.updateCpu)
self.timer.start(100) # Every 0.1 seconds
def updateCpu(self):
cpu = psutil.cpu_percent(None, False)
#print("cpu = {}%".format(cpu))
self.progressBar.setValue(cpu)
def main():
app = QtWidgets.QApplication(sys.argv)
win = MyWidget()
win.show()
win.raise_()
app.exec_()
if __name__ == "__main__":
main()
Note that I changed the first parameter of cpu_percent to None. This makes the call return immediately instead of lasting one second (and therefore you can update the progress bar more often if you want). Setting it to None causes the first call of cpu_percent to return a meaningless value, but in your cause that's not an issue I think. See the documention.
Finally, even though you removed a lot of unnecessary code, your code example was not yet minimal (e.g. the import datecs_print is not necessary to run it, and I don't have this module). I was also not complete (e.g. the "ui/sales_window.ui" file was missing so I couldn't run it). Please read the page on how to make an MCVE. You will get a lot more help next time if you include a small program that we can just copy-paste-execute.
Hope this helps
So I'm quit new to working with UI in python. I'm not really grasping a core concept and i think this simple question will help flip on the light switch.
As seen in the code snippet below, I imported a ui file made in Qt. This ui has a pushbutton on it. How do I make a click event on that button? I have gone through tutorials on how to code a button and use it. I understand that. It is the question of how to access the objects and manipulate the objects that are created by the ui file. What i really want to do is see how to perform a function (or instantiate a class or whatever) when a button is clicked. that function being one that i wrote. baby steps though. any answers and elaborations would be appreciated.
import sys
from PyQt4 import QtGui, uic, QtCore
class MyWindow(QtGui.QMainWindow):
def __init__(self):
super(MyWindow, self).__init__()
uic.loadUi('myWidget.ui', self)
self.show()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = MyWindow()
sys.exit(app.exec_())
like i said. very simple question but I'm just not really grasping the core concept here. thanks you.
self.ui=uic.loadUi('curveViewer.ui', self)
#where `your_pushbutton` is the button name specified in your .ui file:
self.ui.your_pushbutton.clicked.connect(self.onBtnClicked)
or just:
uic.loadUi('curveViewer.ui', self)
self.your_pushbutton.clicked.connect(self.onBtnClicked)
then define method onBtnClicked inside your class MyWindow:
def onBtnClicked():
print 'pushbutton clicked'
see New-style Signal and Slot Support
btw, it's better to remove self.show(), and make it:
window = MyWindow()
window.show()
I have a QT4 and python 2.4 based GUI. The user starts using it by opening a file. In addition to explicit browsing, I would like to allow the user to specify a file to open as a command line argument. I am looking for some event in the QMainWindow (or wherever) that would allow me to detect when the application completed its initialization and is ready for user interaction at which point I could automatically open the file and populate the widgets. So far I could not find anything better than overriding showEvent which is not exactly it because the main window is still not visible at this point. It might be okay but I am looking for a proper way to do this. In some other UI toolkits that I have used in the past that would be something like “main form layout completed” event that would signal that the UI is safe to deal with. Is there something similar in QT4? I am running this on Linux if that matters.
You insights are greatly appreciated.
You don't need an event here. It is guaranteed that everything is loaded after __init__() and show() have run, so you can just put your code for the file opening after that.
import sys
from PyQt4 import QtGui
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.setupUI()
self.show()
# normal __init__ done
if len(sys.argv) > 1:
with open(sys.argv[1]) as f:
# do stuff with file
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
I am trying to get a minimal example for an application designed by the qt designer with pyqt involving a QTreeView to work
1) i can start the app this way but if i push the butten, no entry in the TreeView widget is shown, i do not get any error message, and the layout looks fine, is there some kind of update method?
if you answer, please be specific, as i am still a beginner with qt and much of the documentation is written with c++ examples, and i only have some experience with basic c and python
from PyQt4 import uic, QtGui, QtCore
(Ui_MainWindow, QMainWindow) = uic.loadUiType('main_window.ui')
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.model = QtGui.QStandardItemModel()
self.connect(self.ui.pushButton_NeuesMoebel, QtCore.SIGNAL('clicked()'), self.add_item)
def add_item(self):
t = self.ui.lineEdit_Moebel.text()
if len(t) > 0:
item = QtGui.QStandardItem(t)
self.model.appendRow(item)
self.ui.lineEdit_Moebel.clear()
else:
self.ui.statusBar.showMessage('error: no text in Moebel')
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
2) additionally, is there a cleaner way to directly use the *.ui file than this, to sort of directly subclass the MainWindow of the that file? the ui stuff seems a bit messy
3) for example it would be nicer to have the add_item method in a subclass of the window created by the *.ui file, are we supposed to use the intermediate step of translating the *.ui file to a *.py file?
You just forgot to set the model on your QTreeView. Right now the tree view has no model so it never sees the data update:
def __init__(self, parent=None):
....
self.ui.treeView.setModel(self.model)
Also as a suggestion, save yourself some typing and use the new-style signal/slot connections that are more pythonic and don't make you type out signatures:
self.ui.pushButton_NeuesMoebel.clicked.connect(self.add_item)
I just came across this question and am really glad I did. It caused me to look into using the uic module, which I've been ignoring. In all the years that I've used pyqt I've always generated a .py file from the designer .ui file, and then importing the generated file as a module.
Using uic instead to directly load the .ui file saves a step and simplifies things quite a bit. It's easy to do.
So yes, in answer to question #2 there's a simpler way than calling the ui stuff:
from PyQt4 import uic, QtGui, QtCore
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self,parent)
uic.loadUi('main_window.ui',self)
....