Consider the following example:
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from mplayer import *
class mplayerStarter(QMainWindow):
def __init__(self, parent=None):
super(mplayerStarter, self).__init__(parent)
the_button = QPushButton('Start Mplayer')
the_button.clicked.connect(self.start)
self.setCentralWidget(the_button)
def start(self):
player = Player()
player.loadfile('/tmp/video.mp4')
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
form = mplayerStarter()
form.show()
app.exec_()
If I invoke the program and press the button, the video appears but vanishes immediatly. Any idea how to fix this?
I think it might be being garbage collected. Try this:
class mplayerStarter(QMainWindow):
def __init__(self, parent=None):
super(mplayerStarter, self).__init__(parent)
the_button = QPushButton('Start Mplayer')
the_button.clicked.connect(self.start)
self.setCentralWidget(the_button)
self.player = None
def start(self):
self.player = Player()
self.player.loadfile('/tmp/video.mp4')
Related
When I try to show a message box from another class, it doesn't react anything.
On the other hand, I could succeed to show the box with the internal function.
I can print a message in console through another method of the class.
It seems just not working without any error.. I'm reading some articles but doesn't help.. Could you let me know which part I missed?
[Main.py]
class WinViewer(QWidget):
def __init__(self):
super().__init__()
def initUI(self):
self.setWindowTitle('Autolin')
self.move(300, 300)
self.resize(400, 200)
crw = Crawler.Crawler()
runBtn = QPushButton('Run', self)
runBtn.move(150, 50)
runBtn.clicked.connect(crw.putWebData)
tstBtn = QPushButton('Tst', self)
tstBtn.move(150, 100)
tstBtn.clicked.connect(self.tstmsg)
crw.testFunc()
self.show()
def tstmsg(self):
QMessageBox.about(self, "Tst", "Tst works.")
if __name__ == '__main__':
q_app = QApplication(sys.argv)
gui = WinViewer()
gui.initUI()
sys.exit(q_app.exec_())
[Sub.py]
class Crawler():
def putWebData(self):
QMessageBox.about(self, "Run", "Run works.")
def testFunc(self):
print('Hello')
try using this
Main.py
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
from Sub import Crawler
class WinViewer(QWidget):
def __init__(self, *args):
super(WinViewer, self).__init__(*args)
def initUI(self):
self.setWindowTitle('Autolin')
self.move(300, 300)
self.resize(400, 200)
crw = Crawler(self)
runBtn = QPushButton('Run', self)
runBtn.move(150, 50)
runBtn.clicked.connect(crw.putWebData)
tstBtn = QPushButton('Tst', self)
tstBtn.move(150, 100)
tstBtn.clicked.connect(self.tstmsg)
crw.testFunc()
self.show()
def tstmsg(self):
QMessageBox.about(self, "Tst", "Tst works.")
if __name__ == '__main__':
q_app = QApplication(sys.argv)
gui = WinViewer()
gui.initUI()
sys.exit(q_app.exec_())
Sub.py
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class Crawler(QMessageBox):
def __init__(self, *args):
super(Crawler, self).__init__(*args)
def putWebData(self):
self.about(self, "Run", "Run works.")
def testFunc(self):
print('Hello')
[EDIT]
I went to do something which gave me no time to add the explanation.
What you missed is the super().__init__() is a must when you are inheriting a class from Qt Classes and it works like this super({CLASS_NAME}, self) self represents the inherited class and after it .__init__(*args, **kwargs) it should have both args and kwargs so you can get the full functionality of the inhereted class. *args, **kwargs should be assigned as attributes inside def __init__(self, *args, **kwargs)
I have made a big app importing a big number of dialogs all in main app(main loop).These dialogs import time is pretty long so i made a splash screen but ofcourse splash screen in main loop is blocked from the long time imports.The think i'm not getting is that i cant move the imports in main loop because i get an error from classes creating the ui , witch running as the code is checked from interpreter.
Here the sample code:
from PyQt5 import QtCore, QtGui, QtWidgets, QtPrintSupport
from PyQt5.QtWidgets import QDialog,QWidget,QApplication, QInputDialog, QLineEdit, QFileDialog,QProgressDialog, QMainWindow, QFrame,QSplashScreen
from PyQt5.QtCore import QThread , pyqtSignal,Qt
from PyQt5.QtGui import QIcon,QPainter,QPixmap
#here the slow import dialogs
from ui import Ui_MainWindow,HoverButton
from dialog1 import Ui_Dialog
from dialog2 import Ui_Dialog2
from dialog3 import Ui_dialog3
from dialog4 import Ui_Dialog4
from dialog5 import Ui_dialog5
from dialog6 import Ui_dialog6
#....... and so on
###after class methods###
class Dialog1(QtWidgets.QDialog,Ui_Dialog): #fuel button prompt dialog for inputs
def __init__(self,parent=None):
super(Dialog1, self).__init__(parent)
self.setupUi(self)
class Dialog2(QtWidgets.QDialog,Ui_Dialog2): #all errors dialog
def __init__(self,parent=None):
super(Dialog2, self).__init__(parent)
self.setupUi(self)
class Dialog3(QtWidgets.QDialog,Ui_dialog3): #that might take a while dialog
def __init__(self,parent=None):
super(Dialog3, self).__init__(parent)
self.setupUi(self)
class Dialog4(QtWidgets.QDialog,Ui_Dialog4): #input gross weight dialog
def __init__(self,parent=None):
super(Dialog4, self).__init__(parent)
self.setupUi(self)
class Dialog5(QtWidgets.QDialog,Ui_dialog5): #map viewer specifications dialog
def __init__(self,parent=None):
super(Dialog5, self).__init__(parent)
self.setupUi(self)
#etc
###MAIN GUI###
class mainProgram(QtWidgets.QMainWindow, Ui_MainWindow): #main window
def __init__(self, parent=None):
super(mainProgram, self).__init__(parent)
self.setupUi(self)
self.dialog = Dialog1(self)
self.dialog2 = Dialog2(self)
self.dialog3 = Dialog3(self)
self.dialog3.close()
self.dialog4 = Dialog4(self)
self.dialog5 = Dialog5(self)
self.dialog6 = Dialog6(self)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
splash_pix = QPixmap('loading.jpg')
splash_pix.scaled(200, 400, QtCore.Qt.KeepAspectRatio)
splash = QSplashScreen(splash_pix,Qt.WindowStaysOnTopHint)
splash.setMask(splash_pix.mask())
splash.show()
app.processEvents()
nextGui = mainProgram()
# nextGui.setWindowFlags(QtCore.Qt.FramelessWindowHint)
splash.finish(nextGui)
nextGui.showMaximized()
sys.exit(app.exec_())
Assuming that the only problem is the large number of dialogues and not that each dialogue itself has a task that consumes a lot of time so a possible option is to load each dialog every T ms so in the interim time the QSplashScreen works correctly.
# ...
###MAIN GUI###
class mainProgram(QtWidgets.QMainWindow, Ui_MainWindow):
loadFinished = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(mainProgram, self).__init__(parent)
self.setupUi(self)
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self._T_dialogs = iter(
enumerate((Dialog1, Dialog2, Dialog3, Dialog4, Dialog5, Dialog6))
)
self._timer = QtCore.QTimer(self, timeout=self.create_dialogs, interval=100)
self._timer.start()
#QtCore.pyqtSlot()
def create_dialogs(self):
try:
i, T = next(self._T_dialogs)
w = T(self)
setattr(self, "dialog{}".format(i), w)
except StopIteration:
self._timer.stop()
self.showMaximized()
self.loadFinished.emit()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
splash_pix = QtGui.QPixmap("loading.jpg")
splash_pix.scaled(200, 400, QtCore.Qt.KeepAspectRatio)
splash = QtWidgets.QSplashScreen(splash_pix, QtCore.Qt.WindowStaysOnTopHint)
splash.setMask(splash_pix.mask())
splash.show()
nextGui = mainProgram()
nextGui.loadFinished.connect(splash.close)
sys.exit(app.exec_())
I am currently working on a GUI with PyQt5 (I'm a noob when it comes to python and Qt) and I need to emit a Signal from one class to another.
I read about this and googled around and also found a lot of helpful stuff but it still doesn't work for me.
This is my code-dummy:
Class Nr.1:
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import Class2
class Class1(QWidget):
eventButtonPressed = pyqtSignal(str)
def __init__(self, parent=None):
super().__init__(parent)
self.Class1Btn = QPushButton('Button')
self.Class1Edit = QLineEdit(self)
self.Class1Btn.clicked.connect(self.clicked)
# Layout stuff to mimic my real program
self.Class1Grid = QGridLayout(self)
self.Class1Grid.addWidget(self.Class1Btn)
self.Class1Grid.addWidget(self.Class1Edit)
self.groupBoxLayout1 = QGroupBox(self)
self.groupBoxLayout1.setLayout(self.Class1Grid)
def clicked(self):
self.eventButtonPressed.emit(self.Class1Edit.text())
Class Nr.2:
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import Class1
class Class2(QWidget):
def __init__(self):
super().__init__()
self.Class1OBJ = Class1.Class1(self)
self.Class1OBJ.eventButtonPressed.connect(self.StuffWhenSignalIsEmitted)
# Layout stuff to mimic my real program
self.Class2Edit = QLineEdit(self)
self.Class2Grid = QGridLayout(self)
self.Class2Grid.addWidget(self.Class2Edit)
self.groupBoxLayout2 = QGroupBox(self)
self.groupBoxLayout2.setLayout(self.Class2Grid)
def StuffWhenSignalIsEmitted(self, text):
print('Text from Class 2 Widget: {}'.format(self.Class2Edit))
print('Text from Class 1 Widget: {}'.format(text))
My Main Window:
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import Class1
import Class2
class MainWindow(QWidget, QApplication):
def __init__(self):
super().__init__()
self.Class1OBJ = Class1.Class1()
self.Class2OBJ = Class2.Class2()
self.WinLayout = QVBoxLayout(self)
self.WinLayout.addWidget(self.Class1OBJ.groupBoxLayout1)
self.WinLayout.addWidget(self.Class2OBJ.groupBoxLayout2)
self.setGeometry(1100, 300, 300, 300)
self.setWindowTitle("GUI")
self.show()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
I want the program to print the statements from the StuffWhenSignalIsEmitted method when I press the button (if it is possible). So I want to print what is in the LineEdit from Class one, as well as what is in the LineEdit from Class2.
It seems that you think that if a variable has the same name in different classes it is the same variable, because they are not, they are different objects. The self.Class1OBJ in Class2 is different from the self.Class1OBJ in MainWindow.
So the solution is just to create a single self.Class1OBJ:
Class2.py
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class Class2(QWidget):
def __init__(self):
super().__init__()
# Layout stuff to mimic my real program
self.Class2Edit = QLineEdit(self)
self.Class2Grid = QGridLayout(self)
self.Class2Grid.addWidget(self.Class2Edit)
self.groupBoxLayout2 = QGroupBox(self)
self.groupBoxLayout2.setLayout(self.Class2Grid)
def StuffWhenSignalIsEmitted(self, text):
print('Text from Class 2 Widget: {}'.format(self.Class2Edit))
print('Text from Class 1 Widget: {}'.format(text))
main.py
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import Class1
import Class2
class MainWindow(QWidget, QApplication):
def __init__(self):
super().__init__()
self.Class1OBJ = Class1.Class1()
self.Class2OBJ = Class2.Class2()
# add the following line
self.Class1OBJ.eventButtonPressed.connect(self.Class2OBJ.StuffWhenSignalIsEmitted)
self.WinLayout = QVBoxLayout(self)
self.WinLayout.addWidget(self.Class1OBJ.groupBoxLayout1)
self.WinLayout.addWidget(self.Class2OBJ.groupBoxLayout2)
self.setGeometry(1100, 300, 300, 300)
self.setWindowTitle("GUI")
self.show()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Try it:
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class ClassTwo(QWidget):
def __init__(self):
super().__init__()
self.classOneOBJ = ClassOne(self) # + self
self.classOneOBJ.eventButtonPressed.connect(self.StuffWhenSignalIsEmitted)
layout = QGridLayout(self)
layout.addWidget(self.classOneOBJ)
def StuffWhenSignalIsEmitted(self, text):
print('it worked ->{}'.format(text))
# and do stuff with instance variables of an existing object
class ClassOne(QWidget):
eventButtonPressed = pyqtSignal(str)
def __init__(self, parent=None):
super().__init__(parent)
self.lineEdit = QLineEdit()
self.Btn = QPushButton('Button')
self.Btn.clicked.connect(self.clicked)
layout = QGridLayout(self)
layout.addWidget(self.lineEdit)
layout.addWidget(self.Btn)
def clicked(self):
self.eventButtonPressed.emit(self.lineEdit.text())
if __name__ == '__main__':
app = QApplication(sys.argv)
main = ClassTwo()
main.show()
sys.exit(app.exec_())
I am trying to display a loading gif after a button is pressed. This is the code I currently have
import sys
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class MainWindow (QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow,self).__init__(parent)
self.setGeometry(50,50,240,320)
self.home()
def home(self):
but = QtGui.QPushButton("Example", self)#Creates the brew coffee button
but.clicked.connect(self.gif_display)
but.resize(200,80)
but.move(20,50)
self.show()
def gif_display(self):
l = QMovieLabel('loading.gif')
l.show()
class QMovieLabel(QLabel):
def __init__(self, fileName):
QLabel.__init__(self)
m = QMovie(fileName)
m.start()
self.setMovie(m)
def setMovie(self, movie):
QLabel.setMovie(self, movie)
s=movie.currentImage().size()
self._movieWidth = s.width()
self._movieHeight = s.height()
def run():
app = QtGui.QApplication(sys.argv)
GUI = MainWindow()
sys.exit(app.exec_())
run()
I would like to display the gif called "loading.gif" after the button is pressed. Nothing appears after pressing the button and I am unsure of what to do to get the gif to properly appear. The gif is the same size as the screen that I created (240x320).
The problem is that QMovieLabel is a local variable within gif_display so it will be deleted when the function finishes running, so the solution is to avoid deleting it. There are 2 options: make it an attribute of the class or make it a child of the window , I will show the second method since I think it is the one you want:
import sys
from PyQt4 import QtCore, QtGui
class MainWindow (QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow,self).__init__(parent)
self.setGeometry(50,50,240,320)
self.home()
def home(self):
but = QtGui.QPushButton("Example", self) # Creates the brew coffee button
but.clicked.connect(self.gif_display)
but.resize(200,80)
but.move(20,50)
self.show()
#QtCore.pyqtSlot()
def gif_display(self):
l = QMovieLabel('loading.gif', self)
l.adjustSize()
l.show()
class QMovieLabel(QtGui.QLabel):
def __init__(self, fileName, parent=None):
super(QMovieLabel, self).__init__(parent)
m = QtGui.QMovie(fileName)
self.setMovie(m)
m.start()
def setMovie(self, movie):
super(QMovieLabel, self).setMovie(movie)
s=movie.currentImage().size()
self._movieWidth = s.width()
self._movieHeight = s.height()
def run():
app = QtGui.QApplication(sys.argv)
GUI = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
run()
I am trying to display an image from another thread in the main thread or possibly even a new thread. The problem is I cannot get the image to show anywhere else. I am using the thread _thread to download the image so it won't freeze the gui but I can't seem to get it out of there properly using QImage or QPixmap.
I know how to use strings and such in signals as shown in the example below but I am not sure how to send the image in a signal properly. I have tried using requests to grab an image url and send it to the main which works but I wasn't able to fetch the string in the main and then just download it there real fast either. That also is not a good option due to freezing the GUI momentarily.
This code is an example that shows that I can do all of the work and download the image in the main if I want to but would rather not.
import urllib2
from PyQt4 import QtGui
from PyQt4.QtCore import QThread, pyqtSignal
from PyQt4.QtGui import QApplication, QPixmap
import sys
class MainWindow(QtGui.QWidget):
def __init__(self):
super(self.__class__, self).__init__()
layout = QtGui.QVBoxLayout(self)
self._Button = QtGui.QPushButton()
self._Button.setObjectName("_Button")
self.line_edit = QtGui.QLineEdit()
self.line_edit.setObjectName("line_edit")
self.txt_box = QtGui.QTextEdit()
self.txt_box.setObjectName("txt_Box")
self.img_label = QtGui.QLabel()
self.img_label.setObjectName("img_label")
layout.addWidget(self._Button)
layout.addWidget(self.line_edit)
layout.addWidget(self.img_label)
layout.addWidget(self.txt_box)
self.pixmap = QPixmap()
self._thread = test_thread()
self._Button.clicked.connect(self.start_thread)
self.get_Text = self._thread.test_Signal.connect(self.line_edit.setText)
self.urls = 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_120x44dp.png'
data = urllib2.urlopen(self.urls).read()
self.pixmap.loadFromData(data)
self.img_label.setPixmap(self.pixmap)
def start_thread(self):
self._thread.start()
self._thread.test_Signal.connect(self.txt_box.setText)
class test_thread(QThread):
test_Signal = pyqtSignal(str)
def __init__(self):
super(test_thread, self).__init__()
def run(self):
string = 'This is a test string.'
self.test_Signal.emit(string)
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
And this code shows more of what I am looking to do.
import urllib2
from PyQt4 import QtGui
from PyQt4.QtCore import QThread, pyqtSignal
from PyQt4.QtGui import QApplication, QPixmap
import sys
class MainWindow(QtGui.QWidget):
def __init__(self):
super(self.__class__, self).__init__()
layout = QtGui.QVBoxLayout(self)
self._Button = QtGui.QPushButton()
self._Button.setObjectName("_Button")
self.line_edit = QtGui.QLineEdit()
self.line_edit.setObjectName("line_edit")
self.txt_box = QtGui.QTextEdit()
self.txt_box.setObjectName("txt_Box")
self.img_label = QtGui.QLabel()
self.img_label.setObjectName("img_label")
layout.addWidget(self._Button)
layout.addWidget(self.line_edit)
layout.addWidget(self.img_label)
layout.addWidget(self.txt_box)
self.pixmap = QPixmap()
self._thread = test_thread()
self._Button.clicked.connect(self.start_thread)
self.get_Text = self._thread.test_Signal.connect(self.line_edit.setText)
"...Send signal here and show image. EX:"
"...self._thread.image_Signal.connect(self.img_label.setPixmap)...."
"...or...."
def show_image_here(self):
"....Send image here after downloaded in thread...."
def start_thread(self):
self._thread.start()
self._thread.test_Signal.connect(self.txt_box.setText)
class test_thread(QThread):
test_Signal = pyqtSignal(str)
"....Example image signal...."
"....image_Signal = pyqtSignal()...."
def __init__(self):
super(test_thread, self).__init__()
self.pixmap = QPixmap()
def run(self):
string = 'This is a test string.'
self.test_Signal.emit(string)
self.urls = 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_120x44dp.png'
data = urllib2.urlopen(self.urls).read()
self.pixmap.loadFromData(data)
"....Not sure what to do here...."
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
Can somebody help me out? Thanks.
After looking around some more I came across this thread PySide threading and http downloading
I wish I had found it sooner because I did a lot of searching before my post. The person who answered that thread reclosedev also posted this in the comments:
https://pastebin.com/b4MD5jKh
Which helped me immensely to understand some things better. I used his code and slightly altered it to fit mine and it will work great for what I would like to do.
Here is my full working code using my original example for anyone out there that may find it useful.
import urllib2
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import QThread, pyqtSignal
from PyQt4.QtGui import QApplication
import sys
class MainWindow(QtGui.QWidget):
def __init__(self):
super(self.__class__, self).__init__()
layout = QtGui.QVBoxLayout(self)
self._Button = QtGui.QPushButton()
self._Button.setObjectName("_Button")
self.line_edit = QtGui.QLineEdit()
self.line_edit.setObjectName("line_edit")
self.txt_box = QtGui.QTextEdit()
self.txt_box.setObjectName("txt_Box")
self.img_label = QtGui.QLabel()
self.img_label.setObjectName("img_label")
self.imagepreview = ImagePreview()
layout.addWidget(self._Button)
layout.addWidget(self.line_edit)
layout.addWidget(self.img_label)
layout.addWidget(self.txt_box)
layout.addWidget(self.imagepreview)
self._thread = test_thread()
self._Button.clicked.connect(self.start_thread)
self._Button.clicked.connect(self.imagepreview.startDownload)
self.get_Text = self._thread.test_Signal.connect(self.line_edit.setText)
def start_thread(self):
self._thread.start()
self._thread.test_Signal.connect(self.txt_box.setText)
class test_thread(QThread):
test_Signal = pyqtSignal(str)
def __init__(self):
super(test_thread, self).__init__()
def run(self):
string = 'This is a test string.'
self.test_Signal.emit(string)
class DownloadThread(QtCore.QThread):
data_downloaded = pyqtSignal()
def __init__(self, url):
QtCore.QThread.__init__(self)
self.url = url
self._data = None
def run(self):
self._data = urllib2.urlopen(self.url).read()
self.data_downloaded.emit()
def get_data(self):
return self._data
class ImagePreview(QtGui.QWidget):
def __init__(self, parent=None):
super(ImagePreview, self).__init__(parent)
self.setMinimumSize(50, 50)
self.pixmap = None
def paintEvent(self, paintEvent):
painter = QtGui.QPainter(self)
if (self.pixmap):
painter.drawPixmap(0, 0, self.pixmap)
def startDownload(self):
self.download_thread = DownloadThread('https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_120x44dp.png')
self.download_thread.start()
self.download_thread.data_downloaded.connect(self.ondownloadFinished)
def ondownloadFinished(self):
self.paintImage()
print("download finished")
def paintImage(self):
print("Painting")
pixmap = QtGui.QPixmap()
pixmap.loadFromData(self.download_thread.get_data())
self.setPixmap(pixmap)
def setPixmap(self, pixmap):
self.pixmap = pixmap
self.setMinimumSize(pixmap.width(), pixmap.height())
self.update()
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())