微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在另一个类中使用 Window.bind 时,Kivy Config.read 无法正常工作

如何解决在另一个类中使用 Window.bind 时,Kivy Config.read 无法正常工作

我刚刚发现了一个错误,正在努力寻找解决方案。这是我的文件夹结构:

|- root
  |- GUI.py
  |- GUI.ini
  |- layouts
    |- root.kv
    |- style.kv
  |- lib
    |- kivy_utils.py
  |- static
    |- icon.ico
    |- Barlow-Regular.ttf
    |- Barlow-Bold.ttf

GUI.py 是我启动 GUI 的起点,如下所示:

# %% standard python library imports
import os

# %% kivy imports
# import kivy
from kivy.app import App
from kivy.core.window import Window
from kivy.config import Config
from kivy.lang import Builder
from kivy.uix.Boxlayout import BoxLayout

# %% lib imports
from lib.kivy_utils import TTLabel

# read & overrule config
Config.read(os.path.join(os.path.dirname(os.path.abspath(__file__)),"GUI.ini"))
Window.size = Config.getint("graphics","width"),Config.getint("graphics","height")

# read kv language files
for kv in ["root.kv","style.kv"]:
    Builder.load_file("layouts" + os.sep + kv)

class Root(BoxLayout):
    """ Main Root class for callbacks,UI building etc."""
    def __init__(self):
        super().__init__()

    def test_function(self):
        print("K TEST")


class Launcher(App):
    """Supplementary Launcher class"""

    def build(self):
        return Root()

    def on_pause(self):
        return True


if __name__ == "__main__":
    Launcher().run()

我想将 kivy_utils.py 用于自定义类,例如可扩展的小部件、工具提示等:

from kivy.properties import BooleanProperty,ObjectProperty,NumericProperty
from kivy.core.window import Window
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.slider import Slider
from kivy.uix.switch import Switch
from kivy.clock import Clock

class Tooltip(Label):
    pass


class HoverBehavior(object):
    """Hover behavior.
    :Events:
        `on_enter`
            Fired when mouse enter the bBox of the widget.
        `on_leave`
            Fired when the mouse exit the widget
    """

    hovered = BooleanProperty(False)
    border_point = ObjectProperty(None)

    def __init__(self,**kwargs):
        self.register_event_type('on_enter')
        self.register_event_type('on_leave')
        Window.bind(mouse_pos=self.on_mouse_pos)  # for recognizing tooltips
        super(HoverBehavior,self).__init__(**kwargs)

    def on_mouse_pos(self,*args):
        if not self.get_root_window():
            return
        pos = args[1]
        inside = self.collide_point(*self.to_widget(*pos))  # compensate for relative layout
        if self.hovered == inside:
            return
        self.border_point = pos
        self.hovered = inside
        if inside:
            self.dispatch('on_enter')
        else:
            self.dispatch('on_leave')

    def on_enter(self):
        pass

    def on_leave(self):
        pass


class TTLabel(HoverBehavior,Label):
    """Resizable Label with Tooltip on top of Label and HoverBehavIoUr class"""

    def __init__(self,**kwargs):
        super().__init__()
        self.tooltip = None  # Attribute set in kv file
        self.header = None  # Attribute set in kv file
        self.tooltip_wdg = Tooltip()
        Window.bind(on_resize=self.on_window_resize)  # binds font_size rescaling function to on_resize event
        Clock.schedule_once(self.on_window_resize,1.5)  # called once at init cuz widget hasnt final size yet

    def on_enter(self):
        """Event fires when entering widget"""
        if self.tooltip:  # only binds event if tooltip variable is set
            Window.bind(mouse_pos=lambda w,p: setattr(self.tooltip_wdg,'pos',p))  # binds position to cursor
            self.tooltip_wdg.text = self.tooltip  # sets text to tooltip variable
            Window.add_widget(self.tooltip_wdg)

    def on_leave(self):
        """Event fires when leaving widget"""
        if self.tooltip:
            Window.remove_widget(self.tooltip_wdg)

    def on_window_resize(self,*args):
        """Event fires when window is rescaled"""
        fire_refresh = True

        # # Fires when horizontal size is too small
        if self.size[0] < self._label.size[0]:
            fire_refresh = False
            self.texture_size[0] = self.size[0]  # reduce texture size to widget size
            if self.size[1] < self._label.size[1]:  # additionally,if vertical size is too small,reduce aswell
                self.texture_size[1] = self.size[1]
                return

        # Fires when vertical size is too small
        if self.size[1] < self._label.size[1]:
            fire_refresh = False
            self.texture_size[1] = self.size[1]
            if self.size[0] < self._label.size[0]:
                self.texture_size[0] = self.size[0]
                return

        # Fires when widget size > texture size  # Todo: is there another way not to fire all the time?
        if fire_refresh:
            self.texture_update()

最后,我的 root.kv 看起来像这样:

<Root>:
    BoxLayout:
        orientation: 'horizontal'
        Button:
            text: "Test button"
            on_release: root.test_function()
        TTLabel:
            text: "Test label with tooltip"
            tooltip: "Also WOW!"

现在我的实际问题是:代码有效,但是(!)我的 Config.read 文件中的 GUI.py 命令没有“刷新”当前配置 - 加载有效,我可以访问通过 Config.get 使用属性,使用 Config.write 等 - .ini 文件已更新,但未实现更改。现在我想手动刷新配置中的参数(例如Window.size = Config.getint("graphics","height")),但我想使用选项菜单(F1),我确信肯定有另一种方式。一旦我在 Window.bind 中使用 kivy_utils.py,问题就会出现。我尝试在那里加载配置,使用 self.get_root_window 而不是 Window,将 Config.read 命令放在 kivy_utils.py 等的不同位置。我错过了什么?

解决方法

我想通了 - 我只需要在 Window 导入之前导入并阅读配置:

from kivy.config import Config
Config.read("GUI.ini")
from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout

像这样,您可以使用配置器 (F1) 并正确识别受影响的更改(但是,在重新启动 UI 之后)。我还发现了环境变量的奇怪行为:kivy documentation 状态:

如果不想映射任何环境变量,可以禁用 行为::

os.environ["KIVY_NO_ENV_CONFIG"] = "1"

他们可能在那里翻转了一个布尔值,因为 0 实际上禁用了环境变量,而 1 启用了它们。将报告给 kivy 存储库。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。