【问题标题】:How do I update Kivy elements from a thread?如何从线程更新 Kivy 元素?
【发布时间】:2016-02-21 21:50:25
【问题描述】:

我有一个套接字客户端,它每次收到消息时都会调用View() 类。我已经以这样一种方式拆分了我的代码,这样这个类就可以简单地使用print() 或任何其他我喜欢的显示方法。然而,Kivy 似乎并不喜欢这种方法。我已经为我的视图扩展了 Kivy 的 BoxLayout 类,并且可以调用 message() 函数。这个类看起来像这样:

class View(BoxLayout):
    def __init__(self, **kwargs):
        super(View, self).__init__(**kwargs)
        self.btn = Button(text='Default')
        # Bind button press method
        self.btn.bind(on_press=self.message)
        self.add_widget(self.btn)
    def message(self, message):
        self.btn.text = 'Meow'
        self.add_widget(Button(text='Meow'))
        print(str(message))

message 函数确实被调用并打印但界面没有更新。但是,当我按下按钮时,它会更新界面和打印。

我已经研究过使用StringProperty 来修改按钮文本,但也失败了。顺便说一句,如果我正在做的事情完全不可行,我稍后会尝试以板的形式绘制一个由width * height 按钮组成的整个界面。

非常感谢任何意见,这让我发疯了。


编辑 1* 我已经关注了一些 cmets 并尝试了一些事情。我添加了一个Clock 类并让它从View 安排一个update() 方法。 update 方法只是改变一些元素的文本。当我安排它时,我注意到它可以工作,如下所示:
def update(self, *args, **kwargs):
    self.btn.text = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for i in range(32))
def message(self, message):
    try:
        print(message)
        self.text = 'sending'
    except Exception as e:
        print(e)

线程现在只需分配 message() 中所见的 text 属性。周期性触发的update() 方法也可以工作,分配随机文本。但是现在的问题是它无法设置文本。这不起作用:

def update(self, *args, **kwargs):
    self.btn.text = self.text

我肯定在其他地方做错了,有什么建议吗?


编辑 2* 我要调试的错误是here

【问题讨论】:

  • 您不能从主线程以外的线程修改 UI 元素或属性。查看 Kivy Clock 类以调度函数在主线程上运行。
  • 对于@bj0 的回答,您可以使用@mainthread 装饰器自动将此方法应用于函数。
  • 嘿,我已经编辑了帖子并提供了进一步的发现。感谢您的帮助以及使用 Clock() 的建议,但如上所述,它仍然没有完全发挥作用。

标签: python kivy python-multithreading


【解决方案1】:

由于您没有发布完整的工作示例,我只能猜测您在做什么。似乎您在线程上有一个事件(传入消息),并且您希望在发生这种情况时显示一些文本。您需要将 UI 更新“推送”到主线程,但您不需要使用Clock 进行定期更新,您可以使用Clock.schedule_once 安排一次性调用。 p>

from functools import partial

def update(self, text, *a):
    self.btn.text = text

def message(self, message):
    Clock.schedule_once(partial(self.update, message), 0)

正如之前提到的,您可以使用 @mainthread 装饰器自动执行“推送到主线程”:

@mainthread
def update(self, text):
    self.btn.text = text

def message(self, message):
    update(message)

这样,无论何时调用update,它都会在主线程上执行。

【讨论】:

  • 我的意图是不发布完整的工作示例,因为这是作业的一部分,我不想让我的工作被抄袭。我已经在 GitHub 上公开了这个 repo,可以使用 here。我已经删除了时钟方法并重新使用@mainthread。您要查找的文件是client.py
  • 通常当您不想(或不能)发布您正在处理的代码时,只需创建一个包含您要解决的问题的最小的准系统应用程序。当人们可以重现您的问题时,它会有所帮助。
  • 好吧,看了你的代码后,它看起来不像是 Kivy 问题,而是multiprocessing 问题。单独的进程不共享内存,因此对象之间的许多引用将无法正常工作。改用线程,它应该按照您的想法工作
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-29
  • 1970-01-01
  • 1970-01-01
  • 2019-12-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多