PyQt4 application crashing after adding splash screen - python

I am trying to add a splashscreen to my PyQt4 GUI application. The code is working fine until I close the application which makes Python crash with "Python.exe has stopped working". Here's the code.
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
#Splashscreen
movie = QMovie("giphy-downsized.gif")
splash = MovieSplashScreen(movie)
splash.show()
start = time.time()
while movie.state() == QMovie.Running and time.time() < start + 10:
app.processEvents()
MainWindow = QtGui.QMainWindow()
splash.finish(MainWindow)
movie.stop()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
splash.close()
sys.exit(app.exec_())
I have tried everything. The application closes perfectly if I DO NOT add splashscreen. However, python crashes after I add splashscreen and close the application. Thus, the problem lies with the objects remaining in memory or something like that but I am not able to solve it yet. Please help.
class MovieSplashScreen(QSplashScreen):
def __init__(self, movie, parent = None):
movie.jumpToFrame(0)
pixmap = QPixmap(movie.frameRect().size())
QSplashScreen.__init__(self, pixmap)
self.movie = movie
self.movie.frameChanged.connect(self.repaint)
def showEvent(self, event):
self.movie.start()
def hideEvent(self, event):
self.movie.stop()
def paintEvent(self, event):
painter = QPainter(self)
pixmap = self.movie.currentPixmap()
self.setMask(pixmap.mask())
painter.drawPixmap(0, 0, pixmap)
def sizeHint(self):
return self.movie.scaledSize()

Related

How to change the image inside a Splash Screen

I am developing an app that when started needs to check various things like if the modules are found, if a connection to a microcontroller is working, etc. So I decided to make a splash screen where each of these steps show a message. What I thought was to make several images that have the text saying ('Loading modules...'), ('Checking connection...') and change them everytime the step is being run. The following code is what I thought of:
images = ["path1", "path2", ...]
app = QApplication(sys.argv)
for i in images:
pixmap = QPixmap(i)
splash = QSplashScreen(pixmap)
splash.show()
QTimer.singleShot(3000, splash.close) #the timer is just to pretend some process is running
app.processEvents()
app.exec_()
This code only shows the last of the images, not each separated by 3 seconds. Any clue on how I can fix this?
You must create signals that indicate the states and change the images:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class Manager(QtCore.QObject):
"""Class that simulates the loading steps"""
started = QtCore.pyqtSignal()
loaded_modules = QtCore.pyqtSignal()
connected = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
def start(self):
self.started.emit()
for i, step in enumerate((self.loaded_modules, self.connect, self.finish), 1):
QtCore.QTimer.singleShot(i * 2000, step)
def load_modules(self):
self.loaded_modules.emit()
def connect(self):
self.connected.emit()
def finish(self):
self.finished.emit()
class SplashScreen(QtWidgets.QSplashScreen):
#QtCore.pyqtSlot()
def handle_started(self):
self.show()
self.setPixmap(QtGui.QPixmap("started.png"))
#QtCore.pyqtSlot()
def handle_loaded_modules(self):
self.setPixmap(QtGui.QPixmap("loaded_modules.png"))
#QtCore.pyqtSlot()
def handle_connected(self):
self.setPixmap(QtGui.QPixmap("connected.png"))
#QtCore.pyqtSlot()
def handle_finished(self):
self.close()
def main():
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QMainWindow()
w.resize(640, 480)
manager = Manager()
splash_screen = SplashScreen()
manager.started.connect(splash_screen.handle_started)
manager.loaded_modules.connect(splash_screen.handle_loaded_modules)
manager.connected.connect(splash_screen.handle_connected)
manager.finished.connect(splash_screen.handle_finished)
manager.finished.connect(w.show)
manager.start()
app.exec_()
if __name__ == "__main__":
main()

How to make my title less Window drag-able in PyQt5?

I want to build a window which has no title bar, so i do. But it is not any more draggable. You cannot make my window move from here to there.
I know it is because of me, removing the title bar, but how to fix it?
This is my code:
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QWidget
import sys
def window():
app = QApplication(sys.argv)
win = QMainWindow()
win.setGeometry(300, 300, 300, 300)
win.setWindowTitle("Test")
win.setWindowFlags(QtCore.Qt.FramelessWindowHint)
label = QLabel(win)
label.setText("Hello world")
win.show()
sys.exit(app.exec_())
window()
Any help will be appreciated. Please help me with this...
You need to reimplement the mousePress and mouseMove methods of the widget (mouseRelease is technically not mandatory, but is actually required for consistency, as the release event has to be correctly intercepted by Qt to avoid any confusion). The former will get the current cursor position relative to the geometry (self.offset), while the latter will compute the new "window" position by adding the new position to the current one and subtracting the offset.
I would also suggest you to use a QWidget instead of a QMainWindow. While QMainWindow implementation is very similar to that of QWidgets, subclassing a QMainWindow for your purpose might be a bit harder, as it's widget more complex than it seems.
If you only need a QMainWindow to get a status bar, just add a new one to the widget layout; if you also need a menubar, add it to the widget's layout using setMenuBar.
class FramelessWidget(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Test")
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.label = QLabel("Hello world", self)
self.offset = None
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
self.offset = event.pos()
else:
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
if self.offset is not None and event.buttons() == QtCore.Qt.LeftButton:
self.move(self.pos() + event.pos() - self.offset)
else:
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.offset = None
super().mouseReleaseEvent(event)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = FramelessWidget()
win.setGeometry(300, 300, 300, 300)
win.show()
sys.exit(app.exec_())

Close and Open new Window PYQT5

I would like to press a button in a window and close that window,after that open a new window
How can I do it?
I already tried it but it sends this message the console:
QCoreApplication::exec: The event loop is already running
class Window(QWidget):
def __init__(self,parent = None):
super().__init__(parent)
self.title = 'pySim Z-eighty'
self.left = 0
self.top = 0
self.width = 1200
self.height = 3000
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.button = QPushButton("Z80")
self.button1 = QPushButton()
self.button2 = QPushButton()
self.container = QWidget()
self.layout = QGridLayout()
self.layout.addWidget(self.button1, 1, 0)
self.layout.addWidget(self.button, 1, 1)
self.layout.addWidget(self.button2, 1, 2)
self.container.setLayout(self.layout)
self.layoutPrincipal = QBoxLayout(0)
self.layoutPrincipal.addWidget(self.container)
self.setLayout(self.layoutPrincipal)
self.button.pressed.connect(self.IniciarInterfaz)
def IniciarInterfaz(self):
self.hide()
app = QApplication(sys.argv)
ex = mainWindow()
ex.setStyleSheet("background-color: #fff")
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Window()
ex.show()
sys.exit(app.exec_())
My main problem is when i pressed the button I can't open the new window
There can only be one QApplication within the PyQt application, so if you already created it, do not do it again.
Another problem is that the variables exist only within the context, in your case mainWindow, so at the end of the function StartInterface will eliminate this variable and the window, the solution is to make the mainWindow member of the class, so the context will be the class and no longer the function, so it will stay correctly.
def IniciarInterfaz(self):
self.hide()
self.ex = mainWindow()
self.ex.setStyleSheet("background-color: #fff")
self.ex.show()
PYQT No open and close method,...
hide() and show() method you can use buttons what ever you want,...
def PlatformType_Clicked(self):
dialog.hide()
dialog1.show()

How do hide a window on launch, leaving only the tray icon?

import sys
from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
style = self.style()
# Set the window and tray icon to something
icon = style.standardIcon(QtGui.QStyle.SP_MediaSeekForward)
self.tray_icon = QtGui.QSystemTrayIcon()
self.tray_icon.setIcon(QtGui.QIcon(icon))
self.setWindowIcon(QtGui.QIcon(icon))
# Restore the window when the tray icon is double clicked.
self.tray_icon.activated.connect(self.restore_window)
# why this doesn't work?
self.hide()
self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.Tool)
def event(self, event):
if (event.type() == QtCore.QEvent.WindowStateChange and
self.isMinimized()):
# The window is already minimized at this point. AFAIK,
# there is no hook stop a minimize event. Instead,
# removing the Qt.Tool flag should remove the window
# from the taskbar.
self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.Tool)
self.tray_icon.show()
return True
else:
return super(Example, self).event(event)
def closeEvent(self, event):
reply = QtGui.QMessageBox.question(
self,
'Message',"Are you sure to quit?",
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes:
event.accept()
else:
self.tray_icon.show()
self.hide()
event.ignore()
def restore_window(self, reason):
if reason == QtGui.QSystemTrayIcon.DoubleClick:
self.tray_icon.hide()
# self.showNormal will restore the window even if it was
# minimized.
self.showNormal()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I want to make it only show the tray icon on startup, the example is from here:
PyQt4 Minimize to Tray
I added the following to initUI(), but still it shows a blank window on startup. If I minimize the window, it disppears, leaving only the tray icon - but how can I make this happen on startup automatically?
self.hide()
self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.Tool)
edit: I tried this code on two different machines with Fedora 13 , and CentOS 7
The solution is to show the tray-icon, but hide the window. Your example works for me on Windows if I make the following changes:
def initUI(self):
...
self.hide()
self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.Tool)
# explicitly show the tray-icon
self.tray_icon.show()
def main():
...
ex = Example()
# don't re-show the window!
# ex.show()
sys.exit(app.exec_())
QWidget::hide() should do what you want. The problem is you are calling show() on the new instance which is undoing the call to self.hide() in the constructor.
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.show() # Remove this line
sys.exit(app.exec_())

Drawing a line consisting of multiple points using PyQt

I want to draw a line consisting of multiple points via mouse click in a Python script using PyQt. I need all coordinates of the ponts and I want to be able to delete the line. Here's my script doing all the work, except for the graphical line drawing itself, it just prints what it does:
#!/usr/bin/python3
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class endomess(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.draw = False
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
if self.draw == False:
print('Starting to draw at', str(event.pos()))
self.draw = True
self.linePoints = []
elif self.draw == True:
print('Appending', str(event.pos()))
self.linePoints.append(event.pos())
elif event.button() == Qt.RightButton:
if self.draw == True:
print('Finished drawing. List of all points:', str(self.linePoints))
self.draw = False
def main(argv):
app = QApplication(argv, True)
wnd = endomess()
wnd.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main(sys.argv)
So, here's my problem: how do I actually draw that line that can be defined via the above script? I already had a look at scribble.py and some Qt paint docs, but I don't get it. Probably, this is not a problem for someone more experienced with Qt?
Thanks in advance for all help!
You should probably use the graphics view framework for drawing the lines, rather than attempting to paint them directly.
Here's a basic demo to get you started:
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.view = View(self)
self.button = QtGui.QPushButton('Clear View', self)
self.button.clicked.connect(self.handleClearView)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.view)
layout.addWidget(self.button)
def handleClearView(self):
self.view.scene().clear()
class View(QtGui.QGraphicsView):
def __init__(self, parent):
QtGui.QGraphicsView.__init__(self, parent)
self.setScene(QtGui.QGraphicsScene(self))
self.setSceneRect(QtCore.QRectF(self.viewport().rect()))
def mousePressEvent(self, event):
self._start = event.pos()
def mouseReleaseEvent(self, event):
start = QtCore.QPointF(self.mapToScene(self._start))
end = QtCore.QPointF(self.mapToScene(event.pos()))
self.scene().addItem(
QtGui.QGraphicsLineItem(QtCore.QLineF(start, end)))
for point in (start, end):
text = self.scene().addSimpleText(
'(%d, %d)' % (point.x(), point.y()))
text.setBrush(QtCore.Qt.red)
text.setPos(point)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.resize(640, 480)
window.show()
sys.exit(app.exec_())

Categories