2011-10-19 9 views
14

Sto scrivendo un'applicazione GUI utilizzando python e Qt. Quando lancio la mia applicazione su Mac, la prima voce di menu nella barra dei menu del Mac nella parte superiore dello schermo è "Python". Preferirei che il nome dell'applicazione fosse il nome della mia domanda. Come posso ottenere il nome del mio programma lassù?Impostazione della voce di menu del menu dell'applicazione Mac OSX diversa da "Python" nella mia applicazione Qt Python

Il seguente programma dimostrativo crea una finestra con due menu: "Python" e "Foo". Non mi piace, perché non fa differenza per i miei utenti se ho scritto l'app in python o COBOL. Invece voglio i menu "MyApp" e "Foo".

#!/usr/bin/python 

# This example demonstrates unwanted "Python" 
# application menu name on Mac. 

# Makes no difference whether we use PySide or PyQt4 
from PySide.QtGui import * 
# from PyQt4.QtGui import * 

import sys 

app = QApplication(sys.argv) 
# Mac menubar application menu is always "Python". 
# I want "DesiredAppTitle" instead. 
# setApplicationName() does not affect Mac menu bar. 
app.setApplicationName("DesiredAppTitle") 
win = QMainWindow() 
# need None parent for menubar on Mac to get custom menus at all 
mbar = QMenuBar() 
# Add a custom menu to menubar. 
fooMenu = QMenu(mbar) 
fooMenu.setTitle("Foo") 
mbar.addAction(fooMenu.menuAction()) 
win.setMenuBar(mbar) 
win.show() 
sys.exit(app.exec_()) 

Come posso cambiare quel nome menu delle applicazioni su Mac? EDIT: preferirei continuare ad usare il system python (o qualunque python sia sul PATH dell'utente) se possibile.

+0

Come stai iniziando il tuo programma?So molto poco dei mac, ma sembra che stia semplicemente mettendo il valore di sys.argv [0] lì. – Falmarri

+0

Inizio il programma digitando "python MyApp.py" o "./MyApp.py". In entrambi i casi, sys.argv [0] è "MyApp.py" o "./MyApp.py". "Python" non fa parte di argv. –

+0

@Christpher Bruns: Hmm, hai ragione. Non so perché pensavo che l'argv di python avesse dato a python il suo 'argv [0]'. Però non conosco quasi niente di mac, quindi sono tutto fuori di idee. – Falmarri

risposta

8

Sembra che sia necessario un OSX .app perché funzioni, poiché il file Info.plist contiene il nome visibile all'utente per l'applicazione inserita. Di default è Python, che è il titolo che vedi per il menu del programma. This blog post descrive i passaggi che è necessario eseguire, mentre lo OSX Developer Library ha i documenti nell'elenco delle proprietà che è necessario compilare.

+0

Sono disposto a creare un pacchetto di app se necessario. Ma sono abbastanza scontento della conclusione "non puoi usare il system python" di quel post sul blog. Non c'è davvero modo di usare il Python di sistema e non avere la voce di menu "Python"? –

+0

Apparentemente ... per citare [una fonte diversa] (http://arstechnica.com/open-source/guides/2009/03/how-to-deploying-pyqt-applications-on-windows-and-mac-os -x.ars/2): _ "È assolutamente imperativo configurare l'ambiente per usare la giusta versione di Python prima di costruire le dipendenze basate su Python." _ Da quello che posso ricordare da un incarico qualche tempo fa, in questo modo funziona di sicuro, e una volta che la distribuzione è stata automatizzata, non era più un problema. Non conosco un modo per aggirare questo, quindi ... immagino che non ci sia un altro modo, no. – jro

+0

Ho trovato un modo. Vedi la mia risposta. Vi incoraggio ad avviare una seconda risposta se pensate di poterla sfruttare in una soluzione più completa. –

-3

Credo che hai bisogno di fare questo:

win.setWindowTitle("MyApp") 

Edit: Questo è per PyQt. Non conosco l'equivalente in PySide.

+2

setWindowTitle() posiziona il testo nella barra del titolo dell'applicazione, non nella barra dei menu. Devo cambiare la voce del menu Applicazione nella barra dei menu del Mac. setWindowTitle() non lo fa. –

5

Ho trovato il kernel di una risposta a questa domanda. Perché voglio assegnare la generosità a qualcuno diverso da me (io sono l'OP), per favore, chiunque, prendi questo kernel ed elaboralo in una risposta più completa della tua.

posso ottenere il menu dell'applicazione di essere "MyApp" come segue:

ln -s /System/Library/Frameworks/Python.framework/Versions/2.6/Resources/Python.app/Contents/MacOS/Python MyApp 

./MyApp MyApp.py 

ci sono due elementi necessari per arrivare a questo lavoro:

  1. Il collegamento simbolico deve essere denominato "MyApp "(o qualunque cosa si desideri visualizzare nel menu Applicazione)
  2. Il collegamento simbolico deve puntare all'eseguibile Python all'interno del pacchetto di applicazioni python di sistema. Non funziona se si collega a/usr/bin/python, ad esempio.

Ci deve essere un modo intelligente per creare un pacchetto app o script di shell che sfrutta questo meccanismo in modo robusto ...

+0

Se ho capito bene, stai semplicemente cambiando il nome dell'eseguibile, per così dire (comprendo i link simbolici, ma per essere chiari)? Anche se sono ancora a favore della creazione di un pacchetto di app e ci metto lo sforzo di automazione, puoi semplicemente creare un launcher per la tua applicazione che per prima cosa crea il link simbolico, avvia la tua app e, dopo averla chiusa, rimuove il collegamento. Ma come detto, sono più favorevole alla creazione di un pacchetto app appropriato ... quindi qualcuno può sentirsi libero di compilare questo in una propria risposta. – jro

+0

@jro Sono d'accordo che sarà probabilmente necessario un pacchetto di app per implementare elegantemente la tattica symlink. Sto cercando una soluzione che mostri come creare e utilizzare il link simbolico in un pacchetto di app. Se non viene visualizzata alcuna risposta specifica, la risposta "usa un pacchetto di app" potrebbe rivelarsi la migliore. –

1

Sulla Christopher Bruns risposta, così come il script from "How to create Mac application bundle for Python script via Python", ecco un Script Python che crea un pacchetto (app) per uno script Python utente, che mostrerà il nome dell'app anziché "Python" nei menu. Per fare questo, cerca di localizzare una versione in bundle di Python, e symlink con il nome dell'app. L'ho provato con uno script wxpython, ma dovrebbe funzionare anche per Qt.

Lo script utente viene eseguito dalla posizione originale anziché collocarlo nell'app. Se si desidera posizionare gli script in un pacchetto (insieme a python) per la ridistribuzione, vedere invece py2app.

#!/usr/bin/env python 
'''This creates an app to launch a python script. The app is 
created in the directory where python is called. A version of Python 
is created via a softlink, named to match the app, which means that 
the name of the app rather than Python shows up as the name in the 
menu bar, etc, but this requires locating an app version of Python 
(expected name .../Resources/Python.app/Contents/MacOS/Python in 
directory tree of calling python interpreter). 

Run this script with one or two arguments: 
    <python script> 
    <project name> 
The script path may be specified relative to the current path or given 
an absolute path, but will be accessed via an absolute path. If the 
project name is not specified, it will be taken from the root name of 
the script. 
''' 
import sys, os, os.path, stat 
def Usage(): 
    print("\n\tUsage: python "+sys.argv[0]+" <python script> [<project name>]\n") 
    sys.exit() 

version = "1.0.0" 
bundleIdentifier = "org.test.test" 

if not 2 <= len(sys.argv) <= 3: 
    Usage() 

script = os.path.abspath(sys.argv[1]) 
if not os.path.exists(script): 
    print("\nFile "+script+" not found") 
    Usage() 
if os.path.splitext(script)[1].lower() != '.py': 
    print("\nScript "+script+" does not have extension .py") 
    Usage() 

if len(sys.argv) == 3: 
    project = sys.argv[2] 
else: 
    project = os.path.splitext(os.path.split(script)[1])[0] 

# find the python application; must be an OS X app 
pythonpath,top = os.path.split(os.path.realpath(sys.executable)) 
while top: 
    if 'Resources' in pythonpath: 
     pass 
    elif os.path.exists(os.path.join(pythonpath,'Resources')): 
     break 
    pythonpath,top = os.path.split(pythonpath) 
else: 
    print("\nSorry, failed to find a Resources directory associated with "+str(sys.executable)) 
    sys.exit() 
pythonapp = os.path.join(pythonpath,'Resources','Python.app','Contents','MacOS','Python') 
if not os.path.exists(pythonapp): 
    print("\nSorry, failed to find a Python app in "+str(pythonapp)) 
    sys.exit() 

apppath = os.path.abspath(os.path.join('.',project+".app")) 
newpython = os.path.join(apppath,"Contents","MacOS",project) 
projectversion = project + " " + version 
if os.path.exists(apppath): 
    print("\nSorry, an app named "+project+" exists in this location ("+str(apppath)+")") 
    sys.exit() 

os.makedirs(os.path.join(apppath,"Contents","MacOS")) 

f = open(os.path.join(apppath,"Contents","Info.plist"), "w") 
f.write('''<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 
<plist version="1.0"> 
<dict> 
    <key>CFBundleDevelopmentRegion</key> 
    <string>English</string> 
    <key>CFBundleExecutable</key> 
    <string>main.sh</string> 
    <key>CFBundleGetInfoString</key> 
    <string>{:}</string> 
    <key>CFBundleIconFile</key> 
    <string>app.icns</string> 
    <key>CFBundleIdentifier</key> 
    <string>{:}</string> 
    <key>CFBundleInfoDictionaryVersion</key> 
    <string>6.0</string> 
    <key>CFBundleName</key> 
    <string>{:}</string> 
    <key>CFBundlePackageType</key> 
    <string>APPL</string> 
    <key>CFBundleShortVersionString</key> 
    <string>{:}</string> 
    <key>CFBundleSignature</key> 
    <string>????</string> 
    <key>CFBundleVersion</key> 
    <string>{:}</string> 
    <key>NSAppleScriptEnabled</key> 
    <string>YES</string> 
    <key>NSMainNibFile</key> 
    <string>MainMenu</string> 
    <key>NSPrincipalClass</key> 
    <string>NSApplication</string> 
</dict> 
</plist> 
'''.format(projectversion, bundleIdentifier, project, projectversion, version) 
    ) 
f.close() 

# not sure what this file does 
f = open(os.path.join(apppath,'Contents','PkgInfo'), "w") 
f.write("APPL????") 
f.close() 
# create a link to the python app, but named to match the project 
os.symlink(pythonapp,newpython) 
# create a script that launches python with the requested app 
shell = os.path.join(apppath,"Contents","MacOS","main.sh") 
# create a short shell script 
f = open(shell, "w") 
f.write('#!/bin/sh\nexec "'+newpython+'" "'+script+'"\n') 
f.close() 
os.chmod(shell, os.stat(shell).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) 
2

Se avete intenzione di distribuire l'applicazione, quindi un collegamento simbolico il file binario Python non è garantito il funzionamento, visto che in genere su macchine di sviluppo del pitone sistema non è il pitone di default, e gli utenti regolari molto probabilmente non avrà Qt e PyQt installati.

Un approccio più affidabile è quello di avere un nativo OSX bootstrapping binario che si sarebbe preso cura di iniziare la PyQt applicazione. Sia py2app e PyInstaller possono generare wrapper nativi. Mentre py2app ha funzionato bene per la creazione di un app alias, vale a dire un wrapper che link simbolici ai file esistenti nel sistema, ricevendo per impacchettare solo le dipendenze necessarie PyQt ha dimostrato di essere non banale. Inoltre l' 'applicazione alias' generata dal py2app con la bandiera --aliased smetterà di funzionare se lo si sposta in un'altra cartella dal momento che i link simbolici sono relative alla cartella dove era stato eseguito lo script di build.

PyInstaller ha funzionato out-of-the-box e ho ottenuto un pacchetto OSX che includeva tutte le dipendenze e il codice PyQt tutto a circa 16 MB.

Ho usato questo comando per convertire il mio script PyQt ad un autonomo OSX app:

pyinstaller -w --noconfirm -i=myappicon.icns --clean -F myscript.py 

Questo genera un bundle indipendente che mostrerà tutto ciò che avete nel vostro .setWindowTitle() come il nome dell'applicazione nella barra del titolo OSX.

NB: per qualche motivo, la versione di pyinstaller installata tramite pip non ha funzionato per me. Così ho rimosso la versione pip, clonato il git version of pyinstaller, fatto un python setup.py install e poi ha funzionato come un fascino.

Ancora un'altra opzione per creare un wrapper di applicazione è quello di utilizzare Automator (digitare il nome nella Spotlight), andare su File> Nuovo> Applicazioni> ricerca e trascinare Run shell script di nell'editor e sotto Shell selezionare bash, python. È inoltre possibile utilizzare il Run Applescript e bootstrap tua app tramite AppleScript - può essere utile se avete bisogno di, per esempio, di chiedere la password dell'utente per eseguire con privilegi elevati.

Una migliore alternativa per Automator è Platypus - un'applicazione gratuita e open-source che avvolge i vari tipi di script in applicazioni OSX, e offre anche alcune funzioni extra, come le finestre di uscita di testo gui, in esecuzione con privilegi di amministratore, l'impostazione icone personalizzate, ecc. Il codice è disponibile su github.

Infine, c'è la possibilità di creare un'app OSX barebone in Xcode che lancerà il tuo script PyQt (alcuni esempi here) e svolgerà altre attività personalizzate richieste dalla tua app.

0

So che questo non è ciò che l'OP vuole esattamente, ma ho pensato che potrebbe aggiungere un valore alla ricerca di una soluzione a questo problema.

È possibile effettuare i menu dei file vengono visualizzati nella finestra di interfaccia utente anziché nella nativa per Mac OS X sistema barra dei menu:

menubar.setNativeMenuBar(False) 

Questo farà sì che la barra dei menu di apparire come apparirebbe in es Finestre.

Problemi correlati