【问题标题】:Dropdown partially visible in Kivy (Python)在 Kivy (Python) 中部分可见的下拉菜单
【发布时间】:2015-06-30 04:30:00
【问题描述】:

我正在尝试在 Kivy(Python 的 GUI)中创建一个通用菜单栏,但我遇到了下拉菜单问题。它们只是部分出现,我不知道为什么(参见子菜单 1):

如果你想检查,这是我的代码:

#!/usr/bin/env python3

from kivy.app import App
#from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.dropdown import DropDown
from kivy.properties import ListProperty, ObjectProperty
#from kivy.uix.actionbar import ActionBar, ActionView, ActionGroup, ActionButton

class MenuItem(ButtonBehavior, Label):
    '''Background color, in the format (r, g, b, a).'''
    background_color_normal = ListProperty([0.2, 0.2, 0.2, 1])
    background_color_down = ListProperty([0.3, 0.3, 0.3, 1])
    background_color = ListProperty()
    separator_color = ListProperty([0.8, 0.8, 0.8, 1])
    pass

class MenuSubmenu(MenuItem):
    # The list of submenu items in dropdown menu
    submenu = ObjectProperty(None)

    def add_widget(self, submenu, **kwargs):
        if isinstance(submenu, MenuDropDown):
            self.submenu = submenu
        super().add_widget(submenu, **kwargs)

    def on_release(self, **kwargs):
        super().on_release(**kwargs)
        self.submenu.open(self)

class MenuDropDown(DropDown):
    pass

class MenuButton(MenuItem):
    pass

class MenuBar(BoxLayout):

    '''Background color, in the format (r, g, b, a).'''
    background_color = ListProperty([0.2, 0.2, 0.2, 1])
    separator_color = ListProperty([0.8, 0.8, 0.8, 1])

    def __init__(self, **kwargs):
        self.itemsList = []
        super().__init__(**kwargs)

    def add_widget(self, item, index=0):
        if not isinstance(item, MenuItem):
            raise TypeError("MenuBar accepts only MenuItem widgets")
        super().add_widget(item, index)
        if index == 0:
            index = len(self.itemsList)
        self.itemsList.insert(index, item)

class MenuApp(App):

    def button(self, nb):
        print("Button", nb, "triggered")

if __name__ == '__main__':
    MenuApp().run()

这里是kv文件:

#:kivy 1.0.9

<MenuItem>:
    background_color: self.background_color_down if self.state=='down' else self.background_color_normal
    color: (1,1,1,1)
    canvas.before:
        Color:
            rgba: self.background_color
        Rectangle:
            pos: self.pos
            size: self.size
    canvas.after:
        Color:
            rgba: self.separator_color
        Line:
            rectangle: self.x,self.y,self.width,self.height

<MenuBar>:
    size_hint_y: None
    height: 40
    canvas.before:
        Color:
            rgba: self.background_color
        Rectangle:
            pos: self.pos
            size: self.size
    canvas.after:
        Color:
            rgba: self.separator_color
        Line:
            points: self.x, self.y, self.x + self.width, self.y

BoxLayout:
    orientation: "vertical"

    MenuBar:
        MenuSubmenu:
            text: "Submenu 1"
            MenuDropDown:
                Button:
                    text: "Button 11"
                    on_release: app.button(11)
                Button:
                    text: "Button 12"
                    on_release: app.button(12)
                Button:
                    text: "Button 13"
                    on_release: app.button(13)
        MenuButton:
            text: "Button 2"
            on_release: app.button(2)
        MenuButton:
            text: "Button 3"
            on_release: app.button(3)

    Button:
        text: "Nothing"
        background_color: 0.4, 0.4, 0.4, 1
        background_normal: ""

如果您知道发生了什么,或者您可以将我重定向到更合适的地方以找到答案,那就太好了。

【问题讨论】:

  • 你不应该像这样直接将 DropDown 添加到父级,而应该使用 open 方法。
  • 我不是,这只有在我点击子菜单时才可见(你可以看到函数open在MenuSubmenu类的on_release事件上被调用)问题是由于事实上,我没有为下拉列表的元素指定高度,因此在 open 函数中调用的 _reposition_resomething 函数遇到了问题。
  • 在您的 kv 代码中,您 将 MenuDropDown 直接添加到 MenuSubmenu。
  • 好吧,我误解了这一点,我是 kivy 的新手,由于this exemple,我认为我可以做到这一点。那么是否可以在 kv 文件中定义一个?还是应该将其定义为示例中的某个不方便的类
  • 好的,我想我可能对如何根据类ActionGroup (_build_dropdown, ...) 中的函数来做这件事有一个想法,这可以找到here 谢谢@严重警告。

标签: python user-interface drop-down-menu kivy


【解决方案1】:

正如@inclement 警告的那样,我没有正确使用下拉菜单。您不应该直接在 kv 文件中添加下拉小部件。

因此,我查看了 actionbar 在 kivy 中的工作方式(解释 here 和源代码 here),因此我更新了我的菜单栏。

这是我的python代码:

#!/usr/bin/env python3

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.dropdown import DropDown
from kivy.uix.spinner import Spinner
from kivy.properties import ListProperty, ObjectProperty,\
        StringProperty, BooleanProperty, NumericProperty
#from kivy.uix.actionbar import ActionBar, ActionView, ActionGroup, ActionButton

class MenuItem(Widget):
    '''Background color, in the format (r, g, b, a).'''
    background_color_normal = ListProperty([0.2, 0.2, 0.2, 1])
    background_color_down = ListProperty([0.3, 0.3, 0.3, 1])
    background_color = ListProperty([])
    separator_color = ListProperty([0.8, 0.8, 0.8, 1])
    text_color = ListProperty([1,1,1,1])
    inside_group = BooleanProperty(False)
    pass

class MenuSubmenu(MenuItem, Spinner):
    triangle = ListProperty()

    def __init__(self, **kwargs):
        self.list_menu_item = []
        super().__init__(**kwargs)
        self.dropdown_cls = MenuDropDown

    def add_widget(self, item):
        self.list_menu_item.append(item)
        self.show_submenu()

    def show_submenu(self):
        self.clear_widgets()
        for item in self.list_menu_item:
            item.inside_group = True
            self._dropdown.add_widget(item)

    def _build_dropdown(self, *largs):
        if self._dropdown:
            self._dropdown.unbind(on_dismiss=self._toggle_dropdown)
            self._dropdown.dismiss()
            self._dropdown = None
        self._dropdown = self.dropdown_cls()
        self._dropdown.bind(on_dismiss=self._toggle_dropdown)

    def _update_dropdown(self, *largs):
        pass

    def _toggle_dropdown(self, *largs):
        self.is_open = not self.is_open
        ddn = self._dropdown
        ddn.size_hint_x = None
        if not ddn.container:
            return
        children = ddn.container.children
        if children:
            ddn.width = max(self.width, max(c.width for c in children))
        else:
            ddn.width = self.width
        for item in children:
            item.size_hint_y = None
            item.height = max([self.height, 48])

    def clear_widgets(self):
        self._dropdown.clear_widgets()

class MenuDropDown(DropDown):
        pass

class MenuButton(MenuItem,Button):
    icon = StringProperty(None, allownone=True)
    pass

class MenuEmptySpace(MenuItem):
    pass

class MenuBar(BoxLayout):

    '''Background color, in the format (r, g, b, a).'''
    background_color = ListProperty([0.2, 0.2, 0.2, 1])
    separator_color = ListProperty([0.8, 0.8, 0.8, 1])

    def __init__(self, **kwargs):
        self.itemsList = []
        super().__init__(**kwargs)

    def add_widget(self, item, index=0):
        if not isinstance(item, MenuItem):
            raise TypeError("MenuBar accepts only MenuItem widgets")
        super().add_widget(item, index)
        if index == 0:
            index = len(self.itemsList)
        self.itemsList.insert(index, item)

if __name__ == '__main__':

    class MenuApp(App):
        def button(self, nb):
            print("Button", nb, "triggered")

    MenuApp().run()

这里是对应的文件menu.kv

#:kivy 1.0.9

<MenuButton>:
    size_hint_x: None if not root.inside_group else 1
    width: self.texture_size[0] + 32
    Image:
        allow_stretch: True
        opacity: 1 if root.icon else 0
        source: root.icon
        pos: root.x + 4, root.y + 4
        size: root.width - 8, root.height - 8

<MenuSubmenu>:
    size_hint_x: None
    width: self.texture_size[0] + 32
    triangle: (self.right-14, self.y+7, self.right-7, self.y+7, self.right-7, self.y+14)
    canvas.after:
        Color:
            rgba: self.separator_color
        Triangle:
            points: self.triangle

<MenuButton,MenuSubmenu>:
    background_normal: ""
    background_down: ""
    background_color: self.background_color_down if self.state=='down' else self.background_color_normal
    color: self.text_color

<MenuEmptySpace>:
    size_hint_x: 1

<MenuItem>:
    background_color: self.background_color_normal
    canvas.before:
        Color:
            rgba: self.background_color
        Rectangle:
            pos: self.pos
            size: self.size
    canvas.after:
        Color:
            rgba: self.separator_color
        Line:
            rectangle: self.x,self.y,self.width,self.height

<MenuBar>:
    size_hint_y: None
    height: 48
    canvas.before:
        Color:
            rgba: self.background_color
        Rectangle:
            pos: self.pos
            size: self.size
    canvas.after:
        Color:
            rgba: self.separator_color
        Line:
            rectangle: self.x, self.y, self.width, self.height

BoxLayout:
    orientation: "vertical"

    MenuBar:
        MenuButton:
            icon: "/home/matthieu/internships/singapore/drawings/joytube_color_small.png"
            width: 100
        MenuButton:
            text: "Button 1"
            on_release: app.button(1)
        MenuSubmenu:
            text: "Submenu 2"
            MenuButton:
                text: "Button 21"
                on_release: app.button(21)
            MenuButton:
                text: "Button 22"
                on_release: app.button(22)
            MenuButton:
                text: "Button 23"
                on_release: app.button(23)
        MenuEmptySpace:
        MenuSubmenu:
            text: "Submenu 3"
            MenuButton:
                text: "Button 31"
                on_release: app.button(31)

    Button:
        text: "Nothing"
        background_color: 0.4, 0.4, 0.4, 1
        background_normal: ""

    MenuBar:
        height: 30

希望它能帮助其他想要制作菜单栏的人。

【讨论】:

    猜你喜欢
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 2018-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-24
    相关资源
    最近更新 更多