Ok I hope I can make this understandable...
So I created an UI in QT designer - named heatwindow.ui
Next I wrote this following script in a file named heatwindow.py:
from PySide import QtGui, QtCore, QtUiTools
from HeatModel import *
from vsmutils import *
class HeatWindow:
"""Main window class for the Flow application"""
def __init__(self, app):
"""Class constructor"""
# Assign our application instance as a member variable
self.app = app
# Create an instance of our HeatModel class
#self.heatModel = HeatModel()
# Load and show our user interface
self.ui = loadUiWidget('heatwindow.ui')
self.ui.show()
self.ui.raise_()
if __name__ == '__main__':
app = appInstance()
app.Create()
HeatWindow(app)
window = HeatWindow(app)
app.Run()
Ok, so vsmutils is a script that we got from our teacher...
Anyways - my problem is that nothing happens when running the script. Actually it seems the process in Python gets killed entirely, I have to press "Run again this program" (Spyder) in the Console. When debugging it seems this happens after the line
window = HeatWindow(app)
I hope this is enough info to help me, if not please tell what I should add!
Regards
Ok, solved it finally.
So I am going to post how I did it for others to see if they had the same problem... Cause this was just frustrating.
So- I use Windows 7, Python 2.7.6, Spyder... The script crashed all the time when using QT/Pyside. The solution was to delete a file qt.conf that is inside a Python 2.7.6 folder... And now it works... Don't know why though, but it took me 16 hours to find out.
Related
What I want to achieve:
when I run application from start menu, app starts (if app not running).
If an app is already running, then don't create another instance, just show the previous running app window.
What I've tried:
created a .txt file in a directory, write 'running' & 'not running' into the file while opening & exiting the window. And checking the file contents at very start. For ex:
When starting app: 1.) Check the file content, 2.) If file content is 'running', show warning & exit the app 3.) If file content is 'not running', write 'running' into the file & start app 4.) Write 'not running' into the file on exit.
Issues I'm facing:
This method doesn't feel like the right way to achieve this.
If file item says 'not running', app shows warning and exits. While I want it to show already running instance.
File items not updated to 'not running' when app exits because of some error in code (because that part is never reached due to error)
Can anybody please help me out regarding this?
You can achieve something similar with the win32gui module. To install it type into CMD pip install pywin32. Now this is the code:
from win32 import win32gui
import sys
def windowEnumerationHandler(hwnd, top_windows):
top_windows.append((hwnd, win32gui.GetWindowText(hwnd)))
top_windows = []
win32gui.EnumWindows(windowEnumerationHandler, top_windows)
for i in top_windows:
if "Program" in i[1]: #CHANGE PROGRAM TO THE NAME OF YOUR WINDOW
win32gui.ShowWindow(i[0],5)
win32gui.SetForegroundWindow(i[0])
sys.exit()
from PyQt5.QtWidgets import QApplication, QWidget
def main():
#YOUR PROGRAM GOES HERE
app = QApplication(sys.argv)
w = QWidget()
w.setGeometry(500, 500, 500, 500)
w.setWindowTitle('Simple')
w.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Basically, at the beginning, the program gets the name of every open window. If the window name is equal to the name of the program, then it brings the program to the front and closes the program. If not, then it opens a new program.
PyWin32 link
Stack Overflow get a list of every open window
This solution doesn't require you to install win32 or any other module, works with PyQt5 package itself.
import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import QSystemSemaphore, QSharedMemory
from ui import window_ui # .py file compiled from .ui file
class LoginWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.ui = window_ui.Ui_MainWindow() # call to init ui
self.ui.setupUi(self)
def launch():
app = QtWidgets.QApplication(sys.argv) # create app instance at top, to able to show QMessageBox is required
window_id = 'pingidapplication'
shared_mem_id = 'pingidsharedmem'
semaphore = QSystemSemaphore(window_id, 1)
semaphore.acquire() # Raise the semaphore, barring other instances to work with shared memory
if sys.platform != 'win32':
# in linux / unix shared memory is not freed when the application terminates abnormally,
# so you need to get rid of the garbage
nix_fix_shared_mem = QSharedMemory(shared_mem_id)
if nix_fix_shared_mem.attach():
nix_fix_shared_mem.detach()
shared_memory = QSharedMemory(shared_mem_id)
if shared_memory.attach(): # attach a copy of the shared memory, if successful, the application is already running
is_running = True
else:
shared_memory.create(1) # allocate a shared memory block of 1 byte
is_running = False
semaphore.release()
if is_running: # if the application is already running, show the warning message
QtWidgets.QMessageBox.warning(None, 'Application already running',
'One instance of the application is already running.')
return
# normal process of creating & launching MainWindow
window = LoginWindow()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
launch()
This solution I converted from a C++ code posted on this website originally.
I'm trying to create an application that contains a web browser within it, but when I add the web browser my menu bar visually disappears but functionally remains in place. The following are two images, one showing the "self.centralWidget(self.web_widget)" commented out, and the other allows that line to run. If you run the example code, you will also see that while visually the entire web page appears as if the menu bar wasn't present, you have to click slightly below each entry field and button in order to activate it, behaving as if the menu bar was in fact present.
Web Widget Commented Out
Web Widget Active
Example Code
import os
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtWebEngineWidgets import *
class WebPage(QWebEngineView):
def __init__(self, parent=None):
QWebEngineView.__init__(self)
self.current_url = ''
self.load(QUrl("https://facebook.com"))
self.loadFinished.connect(self._on_load_finished)
def _on_load_finished(self):
print("Url Loaded")
class MainWindow(QMainWindow):
def __init__(self, parent=None):
# Initialize the Main Window
super(MainWindow, self).__init__(parent)
self.create_menu()
self.add_web_widet()
self.show()
def create_menu(self):
''' Creates the Main Menu '''
self.main_menu = self.menuBar()
self.main_menu_actions = {}
self.file_menu = self.main_menu.addMenu("Example File Menu")
self.file_menu.addAction(QAction("Testing Testing", self))
def add_web_widet(self):
self.web_widget = WebPage(self)
self.setCentralWidget(self.web_widget)
if __name__ == "__main__":
app = QApplication(sys.argv)
main_window = MainWindow()
main_window.showMaximized()
sys.exit(app.exec_()) # only need one app, one running event loop
Development Environment
Windows 10, PyQt5, pyqt5-5.9
EDIT
The problem doesn't seem to be directly related to the menu bar. Even removing the menu bar the issue still occurs. That said, changing from showMaximized() to showFullScreen() does seem to solve the problem.
I no longer believe this is an issue with PyQt5 specifically but rather a problem with the graphics driver. Specifically, if you look at Atlassian's HipChat application it has a similar problem which is documented here:
https://jira.atlassian.com/browse/HCPUB-3177
Some individuals were able to solve the problem by running the application from the command prompt with the addendum "--disable-gpu" but that didn't work for my python application. On the other hand, rolling back the Intel(R) HD Graphics Driver did solve my problem. Version 21.20.16.4627 is the one that seems to be causing problems.
I purchased this book called Building Mapping Applications with QGIS and I am trying to work through one of the exercises. There is one script that I try to run that crashes python, generating the error message "python.exe has stopped working".
import sys
import os
from qgis.core import *
from qgis.gui import *
from PyQt4.QtGui import *
from PyQt4.QtCore import Qt
#############################################################################
class MapViewer(QMainWindow):
def __init__(self, shapefile):
QMainWindow.__init__(self)
self.setWindowTitle("Map Viewer")
canvas = QgsMapCanvas()
canvas.useImageToRender(False)
canvas.setCanvasColor(Qt.white)
canvas.show()
layer = QgsVectorLayer(shapefile, "layer1", "ogr")
if not layer.isValid():
raise IOError("Invalid shapefile")
QgsMapLayerRegistry.instance().addMapLayer(layer)
canvas.setExtent(layer.extent())
canvas.setLayerSet([QgsMapCanvasLayer(layer)])
layout = QVBoxLayout()
layout.addWidget(canvas)
contents = QWidget()
contents.setLayout(layout)
self.setCentralWidget(contents)
#############################################################################
def main():
""" Our main program.
"""
QgsApplication.setPrefixPath(os.environ['QGIS_PREFIX'], True)
QgsApplication.initQgis()
app = QApplication(sys.argv)
viewer = MapViewer("C:/folder/shapefile.shp")
viewer.show()
app.exec_()
QgsApplication.exitQgis()
#############################################################################
if __name__ == "__main__":
main()
I don't know a whole lot about Python with QGIS so I'm not too sure what is causing python to crash. I am positive that all of the modules are importing correctly because if I define my paths and then import the modules in the script using the OSGeo4W Shell, there are no error messages.
This is how my paths are defined:
SET OSGEO4W_ROOT=C:\OSGeo4W64
SET QGIS_PREFIX=%OSGEO4W_ROOT%\apps\qgis
SET PATH=%PATH%;%QGIS_PREFIX%\bin
SET PYTHONPATH=%QGIS_PREFIX%\python;%PYTHONPATH%
Given all of this, I think there has to be something wrong in the script. However, when I check the script using http://pep8online.com/ there are no errors that I can fix that will result in python not crashing.
Note that I have tried I have tried SET PATH=%QGIS_PREFIX%\bin;%PATH% instead of SET PATH=%PATH%;%QGIS_PREFIX%\bin with no success.
I was fortunate enough to get in touch with the author of the book so I will share his response here:
I suspect I may know what the problem is...after looking at this
reader's problems in more depth, I've discovered that something has
changed in newer versions of QGIS, and the example code no longer
works as it is written. In technical terms, it seems that you now
need to instantiate the QApplication object before making the call to
QgsApplication.initQgis() -- the example program in the book
instantiates the QApplication object after calling
QgsApplication.initQgis(), which causes the program to crash. To fix
this, change the main() function to look like the following:
def main():
""" Our main program.
"""
app = QApplication(sys.argv)
QgsApplication.setPrefixPath(os.environ['QGIS_PREFIX'],True)
QgsApplication.initQgis()
viewer = MapViewer("C:/folder/shapefile.shp")
viewer.show()
app.exec_()
QgsApplication.exitQgis()
As you can see, I've moved the "app = QApplication(sys.argv)" line to the top.
Important Note: Make sure that forward slashes are used in viewer = MapViewer("C:/folder/shapefile.shp") - using a backslash will result in an error message stating that the shapefile is invalid.
I also thought it would be worth mentioning that none of the above fixes (comments on the question) were necessary. So, the script will work if the paths are defined as follows:
SET OSGEO4W_ROOT=C:\OSGeo4W64
SET QGIS_PREFIX=%OSGEO4W_ROOT%\apps\qgis
SET PATH=%PATH%;%QGIS_PREFIX%\bin
SET PYTHONPATH=%QGIS_PREFIX%\python;%PYTHONPATH%
Then, the entire script looks like this:
import sys
import os
from qgis.core import *
from qgis.gui import *
from PyQt4.QtGui import *
from PyQt4.QtCore import Qt
#############################################################################
class MapViewer(QMainWindow):
def __init__(self, shapefile):
QMainWindow.__init__(self)
self.setWindowTitle("Map Viewer")
canvas = QgsMapCanvas()
canvas.useImageToRender(False)
canvas.setCanvasColor(Qt.white)
canvas.show()
layer = QgsVectorLayer(shapefile, "layer1", "ogr")
if not layer.isValid():
raise IOError("Invalid shapefile")
QgsMapLayerRegistry.instance().addMapLayer(layer)
canvas.setExtent(layer.extent())
canvas.setLayerSet([QgsMapCanvasLayer(layer)])
layout = QVBoxLayout()
layout.addWidget(canvas)
contents = QWidget()
contents.setLayout(layout)
self.setCentralWidget(contents)
#############################################################################
def main():
""" Our main program.
"""
app = QApplication(sys.argv)
QgsApplication.setPrefixPath(os.environ['QGIS_PREFIX'],True)
QgsApplication.initQgis()
viewer = MapViewer("C:/folder/shapefile.shp")
viewer.show()
app.exec_()
QgsApplication.exitQgis()
#############################################################################
if __name__ == "__main__":
main()
Execute it in the OSGEO4W Shell using the following command:
python "C:\script.py"
Lastly, note that at the time of this writing, the script works properly and launches a viewer showing the shapefile referenced, but returns a few errors in the shell that do not seem to be problematic:
ERROR: Opening of authentication db FAILED
ERROR: Unable to establish authentication database connection
ERROR: Auth db could not be created and opened
QSqlDatabasePrivate::database: unable to open database: "unable to open database file Error opening database"
ERROR: Opening of authentication db FAILED
Much thanks to the author Erik Westra for providing me with this solution.
One thing that seems suspect is that you're creating a gui element without giving it a parent - QgsMapCanvas() - and then trying to manually show() it before adding it to a layout. You should never have to call show() on subwidgets, and all subwidgets should be parented to the main widget (or one of its other subwidgets).
Also, you should store persistent references to the python objects; otherwise, it's possible the underlying C++ object with get garbage collected and cause your program to crash. You do this by assigning your widgets and layouts to an attribute on self
Ex.
self.layout = QVBoxLayout(...
self.layer = ...
You should be adding the canvas like this, you should not need to call .show()
self.canvas = QgsMapCanvas(self)
layout.addWidget(self.canvas)
Recently I have created an simple PyQt based app. All it have to do is to make a system tray icon. The problem is that I can see the application is running, however no tray icon is being made. When I move the tray icon code outside the class its working fine. So why is the class a problem here?
My code:
# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtGui, QtCore
app = QtGui.QApplication(sys.argv)
class myApp(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.createTrayIcon()
def createTrayIcon(self):
self.trayIconMenu = QtGui.QMenu()
self.trayIconMenu.addAction("Close", lambda : exit(1))
self.trayIcon = QtGui.QSystemTrayIcon()
self.trayIcon.setIcon(QtGui.QIcon(r"icon.png"))
self.trayIcon.setToolTip("Tooltip")
self.trayIcon.setContextMenu(self.trayIconMenu)
self.trayIcon.show()
self.trayIcon.showMessage("Title", u"Content")
myApp()
sys.exit(app.exec_())
As you don't store the object created in the call to myApp() in a variable, it is garbage collected by Python at some point. Your tray icon may thus be visible for a very brief moment, but will be cleaned up and disappear at some point (which is what you are seeing).
As long as you do myapp = myApp() instead, you will be fine.
Have your forget this line at main ?
.
.
.
objectMyApp = myApp()
objectMyApp.show() # Or don't show please comment this in.
sys.exit(app.exec_())
Problem is your create object but not put in variable. It better if your put in variable.
Is there a way to restart PyQt application QApplication
I have an app created with pyqt4 and python 2.6 using below code
app = QtGui.QApplication(sys.argv)
i have settings options where i set some settings. Now when i save settings i need to reload the application so that new settings are effected. Without the need of end user to exit and launch the app again.
I had a similar problem and simply used this at the appropriate place:
subprocess.Popen([__file__])
sys.exit(0)
It was a simple application, and didn't need any further arguments.
I explain how I did it :
I create a extra one file main.py which calls my actual main program file dash.py.
And I emits a signal for restarting (my programs auto updates at the closeEvent) so I required to emit a signal for it. This is the snippets hope this will help you.
This one is in my main program file in dash.py
def restart(self):
# create a signal equivalent to "void someSignal(int, QWidget)"
self.emit(QtCore.SIGNAL("RESTARTREQUIRED"), True)
This one in main.py which calls actual program only and restarts the app
import sys
from PyQt4 import QtGui,QtCore
from bin import dash
if __name__ == "__main__":
application = QtGui.QApplication(sys.argv)
uDesk = dash.app()
uDesk.show()
uDesk.actionRestart.triggered.disconnect()
# define restart slot
#QtCore.pyqtSlot()
def restartSlot():
print 'Restarting app'
global uDesk
uDesk.deleteLater()
uDesk = dash.app()
uDesk.show()
uDesk.actionRestart.triggered.disconnect()
uDesk.actionRestart.triggered.connect(restartSlot)
print 'New app started !'
QtCore.QObject.connect(uDesk,
QtCore.SIGNAL("RESTARTREQUIRED"),
restartSlot)
uDesk.actionRestart.triggered.connect(restartSlot)
sys.exit(application.exec_())
Hope this was helpful !!
EDIT: Changing the way to get the application path
You could just start a new process and exit yours, something like this: (CODE NOT TESTED, but based on this answer)
// Restart Application
def restart(self, abort):
// Spawn a new instance of myApplication:
proc = QProcess()
//proc.start(self.applicationFilePath());
import os
proc.start(os.path.abspath(__file__))
self.exit(0);
Code it as a method of your Qapplication or even a function if you don't feel like subclassing
This is how I restart TicTacToe game in PySide (it should be the same in PyQt):
I have a single class - a QWidget class - in which is coded the Tic Tac Toe game. To restart the application I use:
import subprocess
a QPushButton() like so:
self.button = QPushButton("Restart", self)
the connection of the button to Slot:
self.buton.clicked.connect(self.restartGame)
the Slot for this button, like so:
def restartGame(self):
self.close()
subprocess.call("python" + " TicTAcToe.py", shell=True)
All these are in the same - single - class. And what these do: close the active window of the game and create a new one.
How this code looks in the TicTacToe class:
import subprocess
class TicTacToe(QWidget):
def __init__(self):
QWidget.__init__(self)
self.button = QPushButton("Restart", self)
self.buton.clicked.connect(self.restartGame)
def restartGame(self):
self.close()
subprocess.call("python" + " TicTacToe.py", shell=True)
def main():
app = QApplication(sys.argv)
widget = TicTacToe()
widget.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
EDIT
I know this doesn't answer the question (it doesn't restart a QApplication), but I hope this helps those who want to restart their QWidget single class.