Python right click popup menu items not enabled

Hello,

I am trying to get a menu to popup at the coordinates of mouse pointer with a set of actions.

This is part of the work to convert the D-rats application from PyGtk to at least Gtk 3 with close to the same functionality. I am not the original author.

I am getting the menu popup to appear on the right click, but none of the actions can be selected.

# map/mappopupmenu.py
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gio
class MapPopupModel(Gio.Menu):
    def __init__(self, position):
        Gio.Menu.__init__(self)

        menu_popup = Gio.Menu()
        menu_popup.append(_("Center here"), 'win.center')

    @staticmethod
    def add_actions(window):
        action_center = Gio.SimpleAction(name='center',
                                         parameter_type=None,
                                         enabled=True)
        action_center.connect('activate', window.popup_center_handler)
        window.add_action(action_center)
#mapwidget.py
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
from gi.repository import Gdk
class MapWidget(Gtk.DrawingArea):
    def __init__(self, width, height, tilesize=256, window=None):
        Gtk.DrawingArea.__init__(self)
        self.tilesize = tilesize
        self.set_size_request(self.tilesize * self.width,
                              self.tilesize * self.height)
#mapwindow.py
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GLib

from . import mappopmodel.MapPopupModel
from . import mapwidget.MapWidget

class MapWindow(Gtk.ApplicationWindow):
    def __init__(self, application, config):
        Gtk.ApplicationWindow.__init__(self, application=application)
        self.map_widget = MapWidget(width=9, height=9,
                                     window=self)
        self.map_widget.show()
        self.scrollw = Gtk.ScrolledWindow()
        self.scrollw.add(self.map_widget)
        self.scrollw.show()
        self.map_widget.add_events(Gdk.EventMask.POINTER_MOTION_MASK)
        self.map_widget.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
        self.map_widget.connect("motion-notify-event", self._mouse_move_event)
        self.scrollw.connect("button-press-event", self._mouse_click_event)
        self.set_default_size(800, 600)
        MapPopupModel.add_actions(self)

    def _mouse_click_event(self, widget, event):
            position="10, 100" # Actually where mouse is on map
            popup_model = Map.PopupModel(position)
            popup_menu = Gtk.Menu.new_from_model(popup_model)
            popup_menu.popup_at_pointer()

    def popup_center_handler(self, _action, _value):
        print("action", type(_action))
        print("value", type(_value))

add_actions() misses

        window.add_action(action_center);

I missed pasting that in extracting code for the example, I do have the window.add_action(action_center). I have corrected that.

I locally have diagnostic code and the “center” action is in the ‘win’ action group for the window object.

It looks like the menu widget resulting from popup_at_pointer() that is launched from the button event from the Gtk.ScrolledWindow can not see the ‘win’ action group in the application window that is its parent.

Before I just extracted the parts of the code that I thought would show the issue.

Here is full program to demonstrate that the menu does not get enabled.

#!/bin/python
'''popup menu test.'''
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gio
from gi.repository import Gtk
from gi.repository import Gdk

class MapPopupModel(Gio.Menu):
    '''MapPopupModel.'''
    def __init__(self, position):
        Gio.Menu.__init__(self)

        menu_popup = Gio.Menu()
        menu_popup.append("Center here", 'win.center')
        self.append_section(str(position), menu_popup)

    @staticmethod
    def add_actions(window):
        '''Add actions.'''
        action_center = Gio.SimpleAction(name='center',
                                         parameter_type=None,
                                         enabled=True)
        action_center.connect('activate', window.popup_center_handler)
        window.add_action(action_center)

class MapWidget(Gtk.DrawingArea):
    '''MapWidget Class'''
    def __init__(self, width, height, tilesize=256):
        Gtk.DrawingArea.__init__(self)
        self.tilesize = tilesize
        self.set_size_request(self.tilesize * width,
                              self.tilesize * height)
        # self.connect("draw", Map.Draw.handler)
        self.queue_draw()

class MapWindow(Gtk.ApplicationWindow):
    '''Map Window.'''
    def __init__(self, application):
        Gtk.ApplicationWindow.__init__(self, application=application)
        self.map_widget = MapWidget(width=9, height=9)
        self.map_widget.show()
        box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 2)
        self.scrollw = Gtk.ScrolledWindow()
        self.scrollw.add(self.map_widget)
        self.scrollw.show()
        self.map_widget.add_events(Gdk.EventMask.POINTER_MOTION_MASK)
        self.map_widget.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
        self.scrollw.connect("button-press-event", self._mouse_click_event)
        box.pack_start(self.scrollw, True, True, True)
        box.show()
        self.set_default_size(800, 600)
        self.add(box)
        MapPopupModel.add_actions(self)

    # pylint: disable=no-self-use
    def _mouse_click_event(self, _widget, event):  # type: ignore
        popup_model = MapPopupModel("%s, %s" % (event.x, event.y))
        popup_menu = Gtk.Menu.new_from_model(popup_model)
        popup_menu.popup_at_pointer()

    # pylint: disable=no-self-use
    def popup_center_handler(self, _action, _value):
        '''popup_center_handler'''
        print("action", type(_action))
        print("value", type(_value))

class MapDisplay(Gtk.Application):
    '''MapDisplay.'''
    def __init__(self):
        Gtk.Application.__init__(self,
                                 application_id='localhost.popup_menu',
                                 flags=Gio.ApplicationFlags.NON_UNIQUE)

    # pylint: disable=arguments-differ
    def do_activate(self):
        map_window = MapWindow(self)
        map_window.show()

def main():
    '''Main function for unit testing.'''
    map_display = MapDisplay()
    map_display.run(None)

if __name__ == "__main__":
    main()

A minor change to above and the menu is working.

    def _mouse_click_event(self, _widget, event):  # type: ignore
        popup_model = MapPopupModel("%s, %s" % (event.x, event.y))
        popup_menu = Gtk.Menu.new_from_model(popup_model)
        popup_menu.attach_to_widget(self)
        popup_menu.popup_at_pointer()

I had to attach the created popup window to the application window.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.