带有Popover菜单的切换按钮:当从弹出菜单中选择菜单项时,切换按钮保持活动状态,我发现了粗略的解决方案,请优化

问题描述

我正在学习PyGobject(pygtk3),在pygtk popover tutorial处给出的示例包括一些用于菜单项的XML文件。我不想在我的pygtk程序中使用xml或glade .ui。因此创建了具有3个菜单项的菜单。这个例子效果很好,但看起来更像是hack。托管弹出窗口的切换按钮需要手动激活/停用,如本例中的功能/方法所示。有没有更好的方法来使按钮切换和菜单/隐藏显示有这样的切换?我在观看Michael B. Popover Tutorial - Youtube时有一些想法,我们确实需要更多的pygtk / pygobject教程以及一些实用的示例,以使更多的人加入自由软件。

#!/usr/bin/python3
import gi

gi.require_version("Gtk","3.0")
from gi.repository import Gtk


class PopoverWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self,title="Popover Demo")
        self.set_border_width(10)
        self.set_default_size(300,200)

        outerBox = Gtk.Box(spacing=6,orientation=Gtk.Orientation.VERTICAL)
        self.add(outerBox)

        #Menu button which will have popover
        self.menuButton = Gtk.ToggleButton.new_with_label("Click Me")
        self.menuButton.connect("toggled",self.on_click_me_clicked)
        outerBox.pack_start(self.menuButton,False,True,0)

        self.popover = Gtk.Popover()
        vBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        
        #popover menu adding items with buttons in vBox container
        vBox = Gtk.Box(spacing=1,orientation=Gtk.Orientation.VERTICAL)
        vBox.set_border_width(5)
        menu_item_button1=Gtk.ModelButton()
        menu_item_button1.set_label("Menu Item 1")
        menu_item_button1.connect("clicked",self.start_menu_item1_function)
        vBox.pack_start(menu_item_button1,5)

        menu_item_button2=Gtk.ModelButton()
        menu_item_button2.set_label("Menu Item 2")
        menu_item_button2.connect("clicked",self.start_menu_item2_function)
        vBox.pack_start(menu_item_button2,5)
        
        #add quit menu item
        menu_item_button3=Gtk.ModelButton()
        menu_item_button3.set_label("Quit")
        menu_item_button3.connect("clicked",Gtk.main_quit)
        vBox.pack_start(menu_item_button3,5)
        
        #put the buttons in popover menu using vBox container
        self.popover.add(vBox)
        self.popover.set_position(Gtk.PositionType.BottOM)
                
    def start_menu_item1_function(self,button):
        #on selection of the menu in the popover
        #we need to manually toggle the button
        self.menuButton.set_active(False)
        print("1st menu item selected")
        
    def start_menu_item2_function(self,button):
        #on selection of the menu in the popover
        #we need to manually toggle the button
        self.menuButton.set_active(False)
        print("2nd menu item selected")

    # to make toggle button hide the show/hide the menu   
    def on_click_me_clicked(self,button):
        if  button.get_active():
            self.popover.set_modal(False)
            self.popover.set_relative_to(button)
            self.popover.show_all()
            self.popover.popup()
        else:
            self.popover.popdown()


win = PopoverWindow()
win.connect("destroy",Gtk.main_quit)
win.show_all()
Gtk.main()

解决方法

Menu Popover使用XML文件,但是我只需要手动菜单项就不需要XML。找到了解决方案,但必须将gtk.Window放入Gtk.ApplicationWindow

enter image description here enter image description here

#!/usr/bin/python3
import gi

# Popover menubutton without MENU XML
# manual Menu Items without XML using menu model
# Needs Application Window for Gtk.MenuButton + menuModel 

gi.require_version("Gtk","3.0")
from gi.repository import Gtk,Gio


class PopoverWindow(Gtk.ApplicationWindow):
    def __init__(self,*args,**kwargs):
        Gtk.Window.__init__(self,title="Popover Demo")
        self.set_border_width(10)
        self.set_default_size(300,200)

        outerbox = Gtk.Box(spacing=6,orientation=Gtk.Orientation.VERTICAL)

        #Menu button which will have popover
        self.menuButton = Gtk.MenuButton()
        self.menuButton.set_label("Click Me!")
        
        # Put the button in the container box
        outerbox.pack_start(self.menuButton,False,True,0)
        self.add(outerbox)

        # Creating menu items Using Menu model
        menuModel = Gio.Menu()
        # menmodel items have (label) and action name with win.XX or app.XX
        menuModel.append("Item 1 - label 1","win.XX")
        menuModel.append("About Your Computer","win.About_Your_Computer")
        menuModel.append("Asif Ali Rizvan","win.riz")
        
        # menu is set as the menu of the menubutton
        self.menuButton.set_menu_model(menuModel)

        
        # the set action XX from win.XX,skip the win. prefix
        
        #1st menu item
        about_action = Gio.SimpleAction.new("XX",None)
        about_action.connect("activate",self.item1_XX_method)
        self.add_action(about_action)

        # 2nd menu item
        about_action = Gio.SimpleAction.new("About_Your_Computer",self.about_your_computer_function)
        self.add_action(about_action)
        
        # 3rd menu item
        riz_action = Gio.SimpleAction.new("riz",None)
        riz_action.connect("activate",self.riz_callback)
        self.add_action(riz_action)

               
    def item1_XX_method(self,action,parameter):
        print("Menu Item 1 Selected")
        
    def about_your_computer_function(self,parameter):
        print("Your Computer is an Electronic Device.")

    def riz_callback(self,parameter):
        print("You clicked \"Asif Ali Rizvan\"")

win = PopoverWindow()
win.connect("destroy",Gtk.main_quit)
win.show_all()
Gtk.main()
,

在这里使用带有Menumodel的Popover,在第35行添加了36行注释,并添加了2行popover代码。

#!/usr/bin/python3
import gi

# Popover menubutton without MENU XML
# manual Menu Items without XML using menu model
# Needs Application Window for Gtk.MenuButton + menuModel 

gi.require_version("Gtk","win.riz")
        
        # menu is set as the menu of the menubutton
        #self.menuButton.set_menu_model(menuModel)

        # USE POPOVER instead
        popover = Gtk.Popover.new_from_model(self.menuButton,menuModel)
        self.menuButton.set_popover(popover)
        
        # the set action XX from win.XX,Gtk.main_quit)
win.show_all()
Gtk.main()
,

最后通过使用ModelButton的正常菜单项和框式容器内的小部件,最终获得了更好的Popover + MenuButton +手动菜单项。 MenuModel不像带有带有窗口小部件的容器的弹出框那样丰富,可以在此处看到: enter image description here

#!/usr/bin/python3
import gi

# Popover menu button without MENU XML
# popover menu with different widgets
# using vbox container inside popover
# GPL3+ (C) Asif Ali Rizvan <fast.rizwaan@gmail.com>

gi.require_version("Gtk",Gio
class PopoverWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self,title="Popover Demo")
        self.set_border_width(10)
        self.set_default_size(400,300)

        # box0 is the main box container which will hold the mb0
        box0 = Gtk.Box(spacing=6,orientation=Gtk.Orientation.VERTICAL)
        self.add(box0)

        # mb0 is Gtk.MenuButton which will include the coming popover
        mb0 = Gtk.MenuButton()
        mb0.set_label("Click Me")
        box0.pack_start(mb0,0)

        # Create popover
        popover = Gtk.Popover()
               
        # vbox container for adding items in Popover menu
        vbox = Gtk.Box(spacing=1,orientation=Gtk.Orientation.VERTICAL)
        vbox.set_border_width(5)
        
        # 1st Gtk Entry widget
        menu_item_1= Gtk.Entry()
        #menu_item_1.set_text("Hello World")
        vbox.pack_start(menu_item_1,5)
        
        # 2nd Gtk Toggle Button Widget
        menu_item_2= Gtk.ToggleButton()
        menu_item_2.set_label("Toggle Button")
        menu_item_2.connect("toggled",self.call_menu_item2_function)
        vbox.pack_start(menu_item_2,5)

        # hbox is horzitontal box container for adding items sidewise 
        # in vbox of Popover menu.
        # we are packing container with widgets inside container (hbox in vbox)
        hbox = Gtk.Box(spacing=1,orientation=Gtk.Orientation.HORIZONTAL)
        hbox.set_border_width(0)
                
        # 3rd Gtk Button
        menu_item_3=Gtk.Button()
        menu_item_3.set_label("Menu Item 3")
        menu_item_3.connect("clicked",self.call_menu_item3_function)
        hbox.pack_start(menu_item_3,5)
        
        # 4th Add quit menu item
        menu_item_4=Gtk.CheckButton()
        menu_item_4.set_label("Quit")
        menu_item_4.connect("clicked",Gtk.main_quit)
        hbox.pack_start(menu_item_4,5)
        
        # add hbox (horizontal box) in vbox (vertical box container of popover) 
        vbox.pack_start(hbox,0)
        
        # add the vbox container with hbox+widgets and other widgets
        # in popover menu
        popover.add(vbox)
        popover.set_position(Gtk.PositionType.BOTTOM)
        
        # add the popover inside mb0 Gtk.MenuButton()
        mb0.set_popover(popover)

        # show the widgets
        popover.show_all()
        
    def call_menu_item2_function(self,button):
        print("Menu Item 2 button Toggled")

    def call_menu_item3_function(self,button):
        print("Menu item 3 Button Clicked")
        

win = PopoverWindow()
win.connect("destroy",Gtk.main_quit)
win.show_all()
Gtk.main()