When I run my wxPython app in Mac OS X, the "Quit" menu item under the Application menu has the label "Quit Myapp", where myapp.py is the name of the main python script. If I rename it to, for example, coolapp.py, the label on the menu item becomes "Quit Coolapp".
Even when I package the application using py2app, although the Application menu changes from 'Python' to the name specified in my setup.py, the Quit menu item remains the same.
How can I change this menu item to use a different application name? Is there any way to use the pyobjc bridge with wxPython?
As it turns out, PyObjC is not required, and this can be done from wxPython only.
The function to call is SetAppName(name), but this must be done from the OnInit(self): method. Previously I was calling this function after the App instance had been created, and it did nothing.
Your code should look like this:
class MyApp(wx.App):
def OnInit(self):
# Set application name before anything else
self.SetAppName("My App Name")
mainframe = MyMainFrame(None, wx.ID_ANY, "")
self.SetTopWindow(mainframe)
mainframe.Show()
return 1
if __name__ == '__main__':
myapp = MyApp()
myapp.MainLoop()
Related
I have been building an application in Python 3.10 and PyQt6. This application has 3 parts: A main window that has a grid of buttons, a settings window that settings which change depending on the button clicked, and a window where a task is run using those settings.
The application works 100% in PyCharm. When packaged using PyInstaller 5.0.1, the main and settings windows load fine. In the settings, I have a button to launch a QFileDialog so the user can select a directory. However, for half of the settings windows, when the user either hits "Cancel" or selects a directory, the entire program crashes. For the other half, everything works as intended (the selected directory is stored as a string). The specific windows that fail or don't never change.
The function to open the QFileDialog, the button to launch that function, and the class variable where the string is store are all part of the parent class. I have included a snippet below that has my general structure: A settings class (which is in settings.py) and two children of that class, DdSettings and PdSettings, which inherit from it (and are in discount.py). All of the code is public on my GitHub too.
class Settings(QWidget):
def __init__(self, task):
super().__init__()
# Window title
self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
# setting the geometry of window
self.setGeometry(0, 0, 700, 400)
# Default directory
self.wd = 'No directory selected'
# Make overarching layout
self.over_layout = QVBoxLayout()
# Make a label with instructions
self.header = QLabel('Enter the appropriate values:', self)
self.header.setFont(QFont('Helvetica', 30))
self.header.setAlignment(Qt.AlignmentFlag.AlignCenter)
# Add header to overarching layout
self.over_layout.addWidget(self.header)
# Make form layout for all the settingsguis
self.layout = QFormLayout()
# ID
self.idform = QLineEdit()
self.idform.setText('9999')
self.layout.addRow(QLabel('Subject ID:'), self.idform)
# Session form
self.sessionin = QLineEdit()
self.sessionin.setText('Pretest')
self.layout.addRow(QLabel('Session name/number (enter \"Practice\" to not have output):'), self.sessionin)
# WD input
self.wdset = QPushButton('Select Directory')
self.wdset.clicked.connect(self.fileselect)
self.wdlabel = QLabel(self.wd)
# Submit button
self.submit = QPushButton('Submit')
self.submit.clicked.connect(self.checksettings)
# Quit button
self.quitbutton = QPushButton('Quit')
self.quitbutton.clicked.connect(QApplication.instance().quit)
self.quitbutton.resize(self.quitbutton.sizeHint())
# Add in elements
self.elements()
# Show all elements
self.show()
def fileselect(self):
"""
This function creates a dialog window to select a directory that will be the output directoty and then sets
the class variable (and associated QLabel) for the working directory to the directory you chose
"""
folder = QFileDialog.getExistingDirectory(self, 'Select Directory')
self.wd = str(folder)
self.wdlabel.setText(self.wd)
# This works
class DdSettings(settings.Settings):
def __init__(self, task):
super().__init__(task)
def elements(self):
# Make form layout for all the settingsguis
self.layout.addRow(QLabel('Current output directory:'), self.wdlabel)
self.layout.addRow(QLabel('Click to choose where to save your output:'), self.wdset)
self.layout.addRow(self.quitbutton, self.submit)
# Add form layout to overarching layout
self.over_layout.addLayout(self.layout)
self.setLayout(self.over_layout)
# This does not work
class PdSettings(settings.Settings):
def __init__(self, task):
super().__init__(task)
def elements(self):
self.layout.addRow(QLabel('Current output directory:'), self.wdlabel)
self.layout.addRow(QLabel('Click to choose where to save your output:'), self.wdset)
self.layout.addRow(self.quitbutton, self.submit)
# Add form layout to overarching layout
self.over_layout.addLayout(self.layout)
self.setLayout(self.over_layout)
Nothing is changed from the parent, and this only crashes when the application is packaged. No error messages are thrown when I run the executable in the console window, so I have no idea how I can provide error messages for insight.
Is it possible to set up a Python script with a PyQt5 GUI such that an active terminal can interact with it?
An example project:
from PyQt5 import QtWidgets from PyQt5.QtCore import pyqtSlot
class Machine:
"""Simpel state machine"""
STATE_IDLE = 'idle'
STATE_OPERATION = 'operation'
def __init__(self):
self.state = self.STATE_IDLE
def get_state(self):
return self.state
def set_state(self, new_state):
self.state = new_state
#pyqtSlot() def on_click():
"""Callback for the PyQt button"""
print('State:', machine.get_state())
if __name__ == '__main__':
# Create machine instance
machine = Machine()
# Set up GUI
app = QtWidgets.QApplication([])
window = QtWidgets.QWidget()
layout = QtWidgets.QVBoxLayout()
label = QtWidgets.QLabel('Hello World!')
button = QtWidgets.QPushButton('Go')
button.clicked.connect(on_click)
layout.addWidget(label)
layout.addWidget(button)
window.setLayout(layout)
window.show()
code = app.exec()
exit(code)
I would like to run this script and to then be able to access the objects from the same terminal. Something like:
$ python main.py
State: idle [< I just pressed the GUI button]
>> machine.set_state(Machine.STATE_OPERATION)
State: operation [< I just pressed the GUI button again]
If I run it like:
python -i main.py
The command line hangs until the application was closed (that's what .exec() does after all), but then I can access machine. Can I make .exec() not hang like this? Maybe run app from a separate thread?
EDIT: I found that thy Pyzo IDE allows you to create a shell with PyQt5 support, which handles the PyQt event loop. So when using the script above with such a Pyzo shell, I can remove code = app.exec() exit(code) because Pyzo will run the event loop and keep the window alive. Now I'd like to do the same across all IDEs.
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.
We were using Python2.3 and wxPython V2.4.2.4 in our project. And it was working fine. Now we are upgrading it to Python2.7 and wxPython2.8.12.1. Our project is compiled fine with new version. But in our project at one stage in the code we destroy the current window and then create & open new window again. And I have noticed that our code after creating new window does not execute. While in the old version it was executing.
In the following code. It is displaying the message "doRead 1" then open the window. But it does not display the message "doRead 2". While in old Python version it was displaying the message "do Read 2" means it was executing the code after that.
I found that, it does not come out from the line "self.MainLoop()" in OnInit(...) function in new project. But it was coming out and thus executing the next line in old project.
-----------------------------------------
Here is the code:
#Close existing window.
self.Destroy()
print 'doRead 1'
#create new window
app = App()
print 'doRead 2'
app.frame.saveContents()
------------------------------------
class App(wx.App):
"""Application class.
"""
def OnInit(self):
wx.InitAllImageHandlers()
resetOptions()
setOptions()
self.frame = pdtpFrame()
self.frame.SetTitle(std.getTitle())
self.frame.Show()
self.SetTopWindow(self.frame)
self.MainLoop()
return True
def main():
""" Start up the pdtp main window application.
"""
app = App()
if __name__ == '__main__':
main()
Your trouble (as far as I can tell) is that you have your MainLoop inside of your OnInit function, which is halting your program flow. I can't speak for how it worked like that before, to be honest, because you shouldn't be able to enter the MainLoop for an App until it's OnInit has returned True. The OnInit could return False in which case the App didn't fully initialize (common if you're doing single instance apps with a lock file, for example). A more common approach (pseudo-code) would look like this:
app = wx.PySimpleApp()
f = Frame(None, -1, "Some Title For This Frame")
f.Show()
app.MainLoop()
# Down here more code can follow.
It won't execute more code until after all Top Level Windows are closed from the prior App instance, or something else calls wx.GetApp().ExitMainLoop().
I have a PyGTK program which is hidden most of the time, but with a keypress it shall come up as a popup. Therefore I want the program not to be activated when its opened. I tried several options to to that, with no success:
self.window.show()
self.window.set_focus(None)
Activates the program, but sets no focus.
self.window.set_accept_focus(False)
self.window.show()
self.window.set_accept_focus(True)
With the last command, the window gets activated.
self.window.show()
self.window.unset_flags(gtk.HAS_FOCUS)
Does nothing...
Btw. I am using Ubuntu 9.10 (metacity)
Build the window but don't call show() on it until it is ready to be activated. Then use self.window.present().
EDIT:
If you never want the window to be activated, why not try a notification popup? You need libnotify for this. There are Python bindings. Here is an example: http://roscidus.com/desktop/node/336
In combination with a toolbar applet, this could do what you want -- i.e. the notification is raised when the user either clicks on the applet or presses the key combination.
I figured out how to do it. See the example below:
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gtk
import gobject
class HelloWorld:
window=None
def hello(self, widget, data=None, data2=None):
HelloWorld.window.set_accept_focus(True)
HelloWorld.window.present()
def __init__(self):
HelloWorld.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.button = gtk.Entry(50)
self.button.connect("focus-in-event", self.hello, None)
HelloWorld.window.add(self.button)
self.button.show()
HelloWorld.window.set_accept_focus(False)
self.button.connect('button-press-event', self.hello)
HelloWorld.window.show()
def main(self):
gtk.main()
if __name__ == "__main__":
hello = HelloWorld()
hello.main()