PyQt MenuBar Mac OSX Snow Leopard - python

I am attempting to add an item to the application menu-bar of a simple PyQt example. However, the following code does not seem to alter the menu-bar at all. The only item in the menu is "Python". Below is the bulk of the code, minus imports and instantiation.
class MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.resize(250, 150)
self.setWindowTitle('menubar')
self.modal = False
exit = QtGui.QAction( QtGui.QIcon('images/app_icon.png'), 'Exit', self )
exit.setShortcut('Ctrl+Q')
exit.setStatusTip('Exit application')
self.connect(exit, QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()'))
menubar = self.menuBar()
file = menubar.addMenu('File')
file.addAction(exit)
I've also tried creating a new QMenuBar and using the setMenuBar() method to manually swap out the menu bar.
Any glaring mistakes in the above snippet?

I know this question is old but, since I was stuck with the same problem, I found that because I was creating an action to quit the application and this action is reserved on OSX to the Application Menu, the File menu did not appear. As I created a new action on the same menu, it became available.
This worked by using the same approach for other OS's:
self.menubar = self.menuBar()
This was created inside a QMainWindow object.
Hope this helps anyone!

When using PyQt on a mac, the system will intercept certain commands contain the word 'Quit' or 'Exit' and remove them from your menubar because they exist elsewhere. if a menubar header has no items, it will not display, making it appear as if you haven't modified the menubar.
#exit = QtGui.QAction( 'Exit', self ) #this fails on my system
exit = QtGui.QAction( 'SomethingElse', self ) #this displays on my system
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(exit)
Also, calling raise_() doesn't change the menubar on my mac. I have to manually select the window (by clicking else where then reclicking), if i use raise_(), to get the correct menubar to show for my pyqt app.
Also remember that mac menubars are displayed in the system menubar not in the window like on a Windows or Linux machine. This leads us to the other solution, as suggested by Levi501 and Swdev. That is to use a non-native menu that appears in the window like so:
menubar = self.menuBar()
menubar.setNativeMenuBar(False)
As someone who uses windows and linux alot, this makes alot more sense for my projects.
I found the 'Exit' information here: http://python.6.x6.nabble.com/addAction-to-menubar-td1916296.html

I don't have PyQt installed on this machine to test this out, but I think on a Mac the QMainWindow.menuBar() function does not return the application wide menu bar.
You might try creating a menubar like:
menubar = QtGui.MenuBar()
I'm basing this on the docs for the QMainWindow.menuBar() function here:
http://doc.qt.io/qt-4.8/qmainwindow.html#menuBar
You might also check out the section labeled QMenuBar on Mac OS X on this page:
http://doc.qt.io/qt-4.8/qmenubar.html#details
Hope that helps!

Correct. On MAC OS we need to use menubar like this:
self.menubar = QtGui.QMenuBar()
And not like this:
self.menubar = QtGui.QMenuBar(MainWindow)
(without the MainWindow parameter)
I suggest the best solution is using QTDesiner to build the UI layout then using pyside-uic tool to convert to a Python class on different platform. When I used the UI layout class compiled on Windows in MAC I got this issue. Solve this issue by simply recompiling the UI layout XML on MAC with the command pyside-uic AppMain.ui -o ui_AppMain.pyp
After I compare the compiled UI layout class between MAC and Windows the only difference is that on Max OS X new QMenuBar object is created without MainWindow parameter.

Related

How to create a menu bar on OSX with PySide2?

I'm looking at the Data Visualization Tool Tutorial on the QT website where they have an example of creating a menu bar inside a QMainWindow:
self.menu = self.menuBar()
self.file_menu = self.menu.addMenu("File")
This doesn't work for me on OSX 10.13.6. I've also tried using QMenuBar to create my own menu bar rather than using the default one that comes with a QMainWindow:
menu_bar = QMenuBar()
menu_bar.addMenu('File')
self.setMenuBar(menu_bar)
This also has no effect. I never see the "File" option in the menu bar of my app. I just get a generic menu bar with a single "python" option.
I believe it is working, but "File" will only appear once you add actions to the file menu.
menu = self.menuBar()
file = menu.addMenu('File')
file.addAction(QAction('Open...', self))

Is it possible to edit menu items in runtime in Python using gtk?

I am writing simple app in python, I want to write a menu using PyGtk. The problem is that under "Connect" menu item I want to have a list of avaliable devices which changes during program operation. So far my code for creating menu items is as below:
import gtk
import gobject
class Foo(object):
def __init__(self):
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
gobject.timeout_add(2000, self.AddNewDevice_TEST)
table = gtk.Table(2,1,False)
window.add(table)
menubar = gtk.MenuBar()
self.connectMenu = gtk.Menu()
connectItem = gtk.MenuItem("Connect")
connectItem.set_submenu(self.connectMenu)
dev1 = gtk.MenuItem("device1")
dev1.connect("activate", self.connectToDev)
self.connectMenu.append(dev1)
menubar.append(connectItem)
table.attach(menubar, 0,1,0,1)
window.show_all()
def connectToDev(self, device):
pass
def AddNewDevice_TEST(self):
dev = gtk.MenuItem("device")
dev.connect("activate", self.connectToDev)
self.connectMenu.append(dev)
if __name__=='__main__':
gui = Foo()
gtk.main()
Problem is that when new device appears in my system or it is disconnected I want to add it or remove it from the list under "Connect".
I am able to edit list of devices in menu but after calling gtk.main() I can't make changes any more. Is there any way to do that in runtime?
You can change menu items during runtime in a different thread, e.g. GObject.idle_add(self.connectMenu.remove, dev1) or GObject.idle_add(self.connectMenu.append, dev1). The methods mentioned for GtkMenuShell in the GNOME Developer Documentation might be helpful.
Don't forget to call show() on the MenuItems as mentioned in the answer to this question.

PySide and menuBar on MacOSX not showing any menu entry due to naming

I am trying to create a menu with PySide. This is the code
def _createMenus(self):
self._menuBar = QtGui.QMenuBar()
self.setMenuBar(self._menuBar)
self._helpMenu = self._menuBar.addMenu("Help")
self._aboutAction = QtGui.QAction("About", self, statusTip="About", triggered=self._about)
self._helpMenu.addAction(self._aboutAction)
This code does not show anything in the menu bar, except the "python" entry.
Weird enough, if I change "About" in "Aout" it displays the menu. Is there some platform dependent weirdness I should be aware of ?
The menu items on Mac OS X can be moved automatically by Qt to the system-wide menubar depending on the action's text and/or menuRole property (see QMenuBar on Mac OS X for details).
So your "About" menu item should be the first item in the application menu.

Adding a program icon in Python GTK

I know this is very simple, just use the command self.set_icon_from_file("icon.png"), however my program still does not display the icon. I made sure the icon.png is in the same working directory as the Python file. I also tried giving the complete file path, but still it does not display the icon.
I am using Ubuntu 10.10 if that helps and using Python V2.6. I use Glade Interface Designer to design the GUI. However, I tried setting the icon both using Glade and using the command above.
I hope I have provided sufficient information.
EDIT: I got the status icon to work in my program.. However in the question I meant the program icon displayed in the task bar and also on the left side of the application bar.
I made sure the icon.png is in the same working directory of the python file.
This may be your problem — paths are looked up relative to the working directory of the Python interpreter, not the file containing the code. I often find myself defining a function like:
def get_resource_path(rel_path):
dir_of_py_file = os.path.dirname(__file__)
rel_path_to_resource = os.path.join(dir_of_py_file, rel_path)
abs_path_to_resource = os.path.abspath(rel_path_to_resource)
return abs_path_to_resource
Mine isn't actually quite that verbose, but hopefully the variable names make it clear what's going on. Also, getting the absolute path isn't strictly necessary, but might help if you need to debug.
Then you can just do:
self.set_icon_from_file(get_resource_path("icon.png"))
Update: Here is a demo program. "icon.png" is in the same directory as this script, and I run it using ./gtktest.py. I see the icon in the top left corner (standard place for my theme). icon.png is just a shape drawn in Inkscape and exported as a bitmap (it works with the original SVG too, anyway).
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gtk
class HelloWorld:
def delete_event(self, widget, event, data=None):
return False
def destroy(self, widget, data=None):
gtk.main_quit()
def __init__(self):
# create a new window
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_icon_from_file('icon.png')
self.window.connect("delete_event", self.delete_event)
self.window.connect("destroy", self.destroy)
# Creates a new button with the label "Hello World".
self.button = gtk.Button("Hello World")
self.window.add(self.button)
self.button.show()
self.window.show()
def main(self):
gtk.main()
if __name__ == "__main__":
hello = HelloWorld()
hello.main()
I am not sure what icon you are creating, but try this smallest PyGTK icon-showing example of taskbar icon I have thought of:
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gtk
# create icon object
statusIcon = gtk.StatusIcon()
# load it
statusIcon.set_from_file("icon.ico")
# show it
statusIcon.set_visible(True)
# and run main gtk loop
gtk.main()
Maybe you just missed the command statusIcon.set_visible(True)
For standard icons, use stock items, and find icons that suits your needs. that way
You don't have to pack icons whith your program
The icons change
according to the user's theme and will blend nicely in her
environment.
for pyGTK :
gtk.icon_theme_get_default().load_icon("folder-open", 128, 0)

wxPython: how to make taskbar icon respond to left-click

Using wxPython, I created a taskbar icon and menu.
Everything works fine (in Windows at least) upon right-click of the icon: i.e., the menu is displayed, and automatically hidden when you click somewhere else, like on Windows' taskbar.
Now I do want to have the menu appear when the icon is left-clicked as well.
So I inserted a Bind() to a left-click in the Frame class wrapper, calling the CreatePopupMenu() of the taskbar icon:
import wx
class BibTaskBarIcon(wx.TaskBarIcon):
def __init__(self, frame):
wx.TaskBarIcon.__init__(self)
self.frame = frame
icon = wx.Icon('test_icon.ico', wx.BITMAP_TYPE_ICO)
self.SetIcon(icon, "title")
def CreatePopupMenu(self):
self.menu = wx.Menu()
self.menu.Append(wx.NewId(), "dummy menu ")
self.menu.Append(wx.NewId(), "dummy menu 2")
return self.menu
class TaskBarFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, style=wx.FRAME_NO_TASKBAR)
...
self.tbicon = BibTaskBarIcon(self)
wx.EVT_TASKBAR_LEFT_UP(self.tbicon, self.OnTaskBarLeftClick)
...
def OnTaskBarLeftClick(self, evt):
self.PopupMenu(self.tbicon.CreatePopupMenu())
...
def main(argv=None):
app = wx.App(False)
TaskBarFrame(None, "testing frame")
app.MainLoop()
This works fine, except that the menu does not disappear automatically when you click somewhere else on your screen. In fact, left-clicking multiple times on the icon creates multiple menus. The only way to hide the menu(s) is to click on one of its items (which you don't always want). I've looked at the available methods of TaskbarIcon, but I failed to be clear about which one to use to hide the menu (.Destroy() didn't work). Moreover, I don't know which event to bind it to (there is a EVT_SET_FOCUS, but I couldn't find any EVT_LOOSE_FOCUS or similar).
So, how to hide the menu upon losing focus?
EDIT: I've inserted a bit more code, to make it more clear
Ah, I've discovered what went wrong. In the statement
self.PopupMenu(self.tbicon.CreatePopupMenu())
I had bound the popup menu to the frame, instead of to the taskbar icon.
By changing it to:
self.tbicon.PopupMenu(self.tbicon.CreatePopupMenu())
all is working well now.
Thanks for all remarks
I think the problem here is that the PopupMenu is usually used in a program's context, not a little icon in the system tray. What that means is that in a normal frame, the popup menu would detect the click the you clicked off of it. Here, you are clicking outside of the wxPython program. Also, the PopupMenu is usually used with EVT_CONTEXT_MENU, not this taskbar event.
You can try wx.EVT_KILL_FOCUS and see if that works since it should theoretically fire when you click off the menu. Or you could ask on the official wxPython forum here: http://groups.google.com/group/wxpython-users/topics
Mike Driscoll
Blog: http://blog.pythonlibrary.org

Categories