Qt splash screen not shown in python - python

I'm trying to add an splash screen to my program, coded in python 2.7 and using pyqt4 libraries. My main file is:
#!/usr/bin/env python
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from logindialog import LoginDialog
from mainwindow import MainWindow
import time
import sys
if __name__ == "__main__":
try:
app = QApplication(sys.argv)
mw = MainWindow()
# Create and display the splash screen
splash_pix = QPixmap('images/sherlock_splash.png')
splash = QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint)
splash.setMask(splash_pix.mask())
# adding progress bar
progressBar = QProgressBar(splash)
# adding message
splash.showMessage('Discovering Nodes...', Qt.AlignRight | Qt.AlignBottom, Qt.darkRed)
splash.show()
app.processEvents()
for i in range(0, 100):
progressBar.setValue(i)
# Simulate something that takes time
time.sleep(0.1)
splash.close()
# Show main window
mw.show()
app.exec_()
except Exception:
sys.exit(1)
sys.exit(0)
I've coded it using Pycharm IDE. If I run it using pycharm RUN functionality the splash screen is shown up properly, however if I run it in linux command line (./main.py) it does not show up splash screen when I start my application.
Anybody could help me?
Thanks a lot!
UPDATE & FIX
...
# Create and display the splash screen
image_path = os.path.dirname(os.path.realpath(__file__))
splash_pix = QPixmap('/'.join([image_path, 'images/sherlock_splash.png']))
splash = QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint)
...
Thanks!

Check your project structure and be sure if the relative path to your .png file is correct
'images/sherlock_splash.png' when running from command line.
Also add following checking
if splash_pix is not None:
...

Related

Pyqt5 | How to properly combine multiple windows in one app

I have an application that consists of multiple uis(windows) and a main script, that should tie them all together into one program. Here is the video showing it: https://youtu.be/B4-PKmbyvjY.
The first problem is that when the active window changes, the application icon on the taskbar flashes. And it's very annoying. The second problem is that my computer is quite strong, and the delay between switching windows is not particularly noticeable. But when my friend started this program on his laptop, the delay between hiding one window and opening another was huge. For a whole second there was a desktop instead of the program. And so it is with every window switch.
Here's a main.py script:
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import Qt, pyqtSlot
from downloadPage import DownloadPage
from mainPage import MainPage
from managerPage import ManagerPage
from registrationPage import RegistrationPage
from loginPage import LoginPage
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
def switch(_from, _to):
# Open new window on the position of the last opened window
# Otherwise it just appears in the center
lastPos = _from.pos()
modifiedPos = (lastPos.x() + _from.width() // 2,
lastPos.y() + _from.height() // 2)
newPos = (modifiedPos[0] - _to.width() // 2,
modifiedPos[1] - _from.height() // 2)
_to.move(*newPos)
_to.show()
_from.hide()
if __name__ == '__main__':
app = QApplication(sys.argv)
# Pages (uis)
registerWin = RegistrationPage()
mainWin = MainPage()
downloadWin = DownloadPage()
managerWin = ManagerPage()
loginWin = LoginPage()
mainWin.show()
# Switch windows on button clicks
loginWin.registerButton.clicked.connect(
lambda: switch(loginWin, registerWin))
registerWin.loginButton.clicked.connect(
lambda: switch(registerWin, loginWin))
mainWin.downloadButton.clicked.connect(
lambda: switch(mainWin, downloadWin))
mainWin.browseButton.clicked.connect(
lambda: switch(mainWin, managerWin))
downloadWin.returnButton.clicked.connect(
lambda: switch(downloadWin, mainWin))
# After register/login was successful
#pyqtSlot(str)
def successfulLogin(login):
mainWin.upperText.setText(
f'Welcome, {login}! What brings you here today?')
switch(registerWin, mainWin)
registerWin.successfulRegister.connect(successfulLogin)
loginWin.successfulLogin.connect(successfulLogin)
sys.exit(app.exec_())
I've heard about QTabWidget, but i'm not quite sure if it's the solution in my case. There should be buttons to switch between tabs and my program just can't allow that.
Thanks in advance for any help

How to attach and detach an external app with PyQT5 or dock an external application?

I'm developing an GUI for multi-robot system using ROS, but i'm freezing in the last thing i want in my interface: embedding the RVIZ, GMAPPING or another screen in my application. I already put an terminal in the interface, but i can't get around of how to add an external application window to my app. I know that PyQt5 have the createWindowContainer, with uses the window ID to dock an external application, but i didn't find any example to help me with that.
If possible, i would like to drag and drop an external window inside of a tabbed frame in my application. But, if this is not possible or is too hard, i'm good with only opening the window inside a tabbed frame after the click of a button.
I already tried to open the window similar to the terminal approach (see the code bellow), but the RVIZ window opens outside of my app.
Already tried to translate the attaching/detaching code code to linux using the wmctrl command, but didn't work wither. See my code here.
Also already tried the rviz Python Tutorial but i'm receveing the error:
Traceback (most recent call last):
File "rvizTutorial.py", line 23, in
import rviz
File "/opt/ros/indigo/lib/python2.7/dist-packages/rviz/init.py", line 19, in
import librviz_shiboken
ImportError: No module named librviz_shiboken
# Frame where i want to open the external Window embedded
self.Simulation = QtWidgets.QTabWidget(self.Base)
self.Simulation.setGeometry(QtCore.QRect(121, 95, 940, 367))
self.Simulation.setTabPosition(QtWidgets.QTabWidget.North)
self.Simulation.setObjectName("Simulation")
self.SimulationFrame = QtWidgets.QWidget()
self.SimulationFrame.setObjectName("SimulationFrame")
self.Simulation.addTab(rviz(), "rViz")
# Simulation Approach like Terminal
class rviz(QtWidgets.QWidget):
def __init__(self, parent=None):
super(rviz, self).__init__(parent)
self.process = QtCore.QProcess(self)
self.rvizProcess = QtWidgets.QWidget(self)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.rvizProcess)
# Works also with urxvt:
self.process.start('rViz', [str(int(self.winId()))])
self.setGeometry(121, 95, 940, 367)
I've not tested this specifically, as I've an old version of Qt5 I can't upgrade right now, while from Qt5 5.10 startDetached also returns the pid along with the bool result from the started process.
In my tests I manually set the procId (through a static QInputBox.getInt()) before starting the while cycle that waits for the window to be created.
Obviously there are other ways to do this (and to get the xid of the window).
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
import gi
gi.require_version('Wnck', '3.0')
from gi.repository import Wnck, Gdk
class Container(QtWidgets.QTabWidget):
def __init__(self):
QtWidgets.QTabWidget.__init__(self)
self.embed('xterm')
def embed(self, command, *args):
proc = QtCore.QProcess()
proc.setProgram(command)
proc.setArguments(args)
started, procId = proc.startDetached()
if not started:
QtWidgets.QMessageBox.critical(self, 'Command "{}" not started!')
return
attempts = 0
while attempts < 10:
screen = Wnck.Screen.get_default()
screen.force_update()
# this is required to ensure that newly mapped window get listed.
while Gdk.events_pending():
Gdk.event_get()
for w in screen.get_windows():
if w.get_pid() == procId:
window = QtGui.QWindow.fromWinId(w.get_xid())
container = QtWidgets.QWidget.createWindowContainer(window, self)
self.addTab(container, command)
return
attempts += 1
QtWidgets.QMessageBox.critical(self, 'Window not found', 'Process started but window not found')
app = QtWidgets.QApplication(sys.argv)
w = Container()
w.show()
sys.exit(app.exec_())
I couldn't get the code in the accepted answer to work on Ubuntu 18.04.3 LTS; even when I got rid of the exceptions preventing the code to run, I'd still get a separate PyQt5 window, and separate xterm window.
Finally after some tries, I got the xterm window to open inside the tab; here is my code working in Ubuntu 18.04.3 LTS (with all the misses commented):
#!/usr/bin/env python3
# (same code seems to run both with python3 and python2 with PyQt5 in Ubuntu 18.04.3 LTS)
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
import gi
gi.require_version('Wnck', '3.0')
from gi.repository import Wnck, Gdk
import time
class Container(QtWidgets.QTabWidget):
def __init__(self):
QtWidgets.QTabWidget.__init__(self)
self.embed('xterm')
def embed(self, command, *args):
proc = QtCore.QProcess()
proc.setProgram(command)
proc.setArguments(args)
#started, procId = proc.startDetached()
#pid = None
#started = proc.startDetached(pid)
# https://stackoverflow.com/q/31519215 : "overload" startDetached : give three arguments, get a tuple(boolean,PID)
# NB: we will get a failure `xterm: No absolute path found for shell: .` even if we give it an empty string as second argument; must be a proper abs path to a shell
started, procId = proc.startDetached(command, ["/bin/bash"], ".")
if not started:
QtWidgets.QMessageBox.critical(self, 'Command "{}" not started!'.format(command), "Eh")
return
attempts = 0
while attempts < 10:
screen = Wnck.Screen.get_default()
screen.force_update()
# do a bit of sleep, else window is not really found
time.sleep(0.1)
# this is required to ensure that newly mapped window get listed.
while Gdk.events_pending():
Gdk.event_get()
for w in screen.get_windows():
print(attempts, w.get_pid(), procId, w.get_pid() == procId)
if w.get_pid() == procId:
self.window = QtGui.QWindow.fromWinId(w.get_xid())
#container = QtWidgets.QWidget.createWindowContainer(window, self)
proc.setParent(self)
#self.scrollarea = QtWidgets.QScrollArea()
#self.container = QtWidgets.QWidget.createWindowContainer(self.window)
# via https://vimsky.com/zh-tw/examples/detail/python-method-PyQt5.QtCore.QProcess.html
#pid = proc.pid()
#win32w = QtGui.QWindow.fromWinId(pid) # nope, broken window
win32w = QtGui.QWindow.fromWinId(w.get_xid()) # this finally works
win32w.setFlags(QtCore.Qt.FramelessWindowHint)
widg = QtWidgets.QWidget.createWindowContainer(win32w)
#self.container.layout = QtWidgets.QVBoxLayout(self)
#self.addTab(self.container, command)
self.addTab(widg, command)
#self.scrollarea.setWidget(self.container)
#self.container.setParent(self.scrollarea)
#self.scrollarea.setWidgetResizable(True)
#self.scrollarea.setFixedHeight(400)
#self.addTab(self.scrollarea, command)
self.resize(500, 400) # set initial size of window
return
attempts += 1
QtWidgets.QMessageBox.critical(self, 'Window not found', 'Process started but window not found')
app = QtWidgets.QApplication(sys.argv)
w = Container()
w.show()
sys.exit(app.exec_())

VTK with Qt5 - Timer stops running when window is interacted with

I've been trying to do animation with VTK, so I've been using TimerEvent. When I tried to move over to the Qt binding, it broke. The problem is that as soon as I interact with the view (say scrolling to zoom, or clicking to rotate) the timer stops. Here's a simple minimal example:
import vtk
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
from PyQt5 import Qt
message = "tick"
def onTimerEvent(object, event):
global message
print(message)
if message == "tick":
message = "tock"
else:
message = "tick"
app = Qt.QApplication([])
mainWindow = Qt.QMainWindow()
renderer = vtk.vtkRenderer()
vtkWidget = QVTKRenderWindowInteractor(mainWindow)
vtkWidget.GetRenderWindow().AddRenderer(renderer)
mainWindow.setCentralWidget(vtkWidget)
vtkWidget.GetRenderWindow().GetInteractor().Initialize()
timerId = vtkWidget.CreateRepeatingTimer(100)
vtkWidget.AddObserver("TimerEvent", onTimerEvent)
mainWindow.show()
app.exec_()
This script should display the words "tick" and "tock" over and over again, but stop as soon as you click inside the window.
One odd behavior is that pressing "T" to switch to trackball interaction style seems to have some effect. If I press T and then click inside the window, the timer only stops running while I'm clicking: when I let go it starts up again. If I then press J to go back to "joystick mode", the problem returns: clicking stops the timer forever.
Python 3.6, VTK 8, Qt 5.
The problem is reproducible in Linux 16.04, VTK8.1.1 and Qt5.5.1.
As you are using Qt, a workaround for your problem is to use QTimer(). It is a solution if you want to work with a timing.
This is your minimal example changing the TimerEvent for QTimer():
import vtk
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
from PyQt5 import Qt
from PyQt5.QtCore import QTimer
message = "tick"
def onTimerEvent():
global message
print(message)
if message == "tick":
message = "tock"
else:
message = "tick"
app = Qt.QApplication([])
mainWindow = Qt.QMainWindow()
renderer = vtk.vtkRenderer()
vtkWidget = QVTKRenderWindowInteractor(mainWindow)
vtkWidget.GetRenderWindow().AddRenderer(renderer)
mainWindow.setCentralWidget(vtkWidget)
vtkWidget.GetRenderWindow().GetInteractor().Initialize()
#timerId = vtkWidget.CreateRepeatingTimer(100)
#vtkWidget.AddObserver("TimerEvent", onTimerEvent)
timer = QTimer()
timer.timeout.connect(onTimerEvent)
timer.start(100)
mainWindow.show()
app.exec_()

Window is closing immediately after I run program in PyQt 4 (anaconda) [PyCharm 4.5]

So, I am trying to run a very simple program (a window) in Pycharm that is running anaconda 2.7 & PyQt4. Whenever I click the Run button it opens my program but closes the window too fast for me to even see it. May anyone, please help? Thank you!
P.S.
I'm very new to programming.
{__author__ = 'Jay'
import sys
from PyQt4 import QtGui
app = QtGui.QApplication(sys.argv)
window = QtGui.QWidget()
window.show()}
You need to block the execution of the program after you call window.show() so that the window object remains active otherwise it will be garbage collected. app.exec_() does this for you.
{__author__ = 'Jay'
import sys
from PyQt4 import QtGui
app = QtGui.QApplication(sys.argv)
window = QtGui.QWidget()
window.show()
app.exec_()} # added this line

Getting PySide Hello App to run under Canopy

A Canopy user here learning about PySide. When I run the demo code below, QApplication complains the event loop is already running.'
import sys
from PySide.QtCore import *
from PySide.QtGui import *
# Create a Qt application
#app = QApplication(sys.argv) #QApplication complains an instance already exists
app = QApplication.instance() #So we just ask for the instance.
#app.aboutToQuit.connect(app.deleteLater)
# Create a Label and show it
label = QLabel("Hello World")
label.show()
# Enter Qt application main loop
app.exec_()
sys.exit()
So how can I get this simple code to run?
Yes, Pylab is a mode of IPython which starts an event loop for the IPython front end so that you can interact at the IPython command line with your GUI.
Here's an simple example of code which will run with or without Pylab.
import sys
from PySide import QtGui
app = QtGui.QApplication.instance()
standalone = app is None
if standalone:
app = QtGui.QApplication(sys.argv)
wid = QtGui.QWidget()
wid.resize(250,150)
wid.setWindowTitle('Simple')
wid.show()
if standalone:
sys.exit(app.exec_())
else:
print "We're back with the Qt window still active"

Categories