如何从线程更新 Kivy 元素? [英] How do I update Kivy elements from a thread?

查看:30
本文介绍了如何从线程更新 Kivy 元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a socket client that calls a View() class every time it receives a message. I've split my code in such a way such that this class can simply use print() or any other display method, as I like. However, it seems that Kivy is not fond of this method. I've extended Kivy's BoxLayout class for my view and can call the message() function. The class looks something like this:

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 函数确实被调用并打印但界面没有更新.但是,当我按下按钮时,它会更新界面和打印.

The message function is indeed called and it prints but the interface does not update. When I press the button however, it does update the interface as well as print.

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

I've looked into using a StringProperty to modify the button text but have failed that too. Just as a note, in case what I'm doing is completely infeasible, I'm trying to later draw an entire interface consisting of width * height buttons, in the form of a board.

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

Any input is very much appreciated, it's been driving me insane.


编辑 1*我关注了一些评论并尝试了一些事情.我添加了一个 Clock 类并让它从 View 安排一个 update() 方法.update 方法只是改变一些元素的文本.当我安排它时,我注意到它可以工作,如下所示:


EDIT 1* I've followed on a few comments and tried a few things out. I've added a Clock class and have it schedule an update() method from View. The update method simply changes the text of a few elements. I've noticed it works when I schedule it to, as shown below:

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() 所示.周期性触发的 update() 方法也可以工作,分配随机文本.但是现在的问题是它无法设置文本.这不起作用:

The thread now simply assigns the text property as seen in message(). The periodically triggered update() methods works too, assigning random text. Now the issue however that it cannot set the text. This does not work:

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

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

I must be doing wrong elsewhere, any suggestions?


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

推荐答案

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

Since you don't post a full working example, I can only guess at what your doing. It seems you have an event (incoming message) on a thread, and you want to display some text when this occurs. You need to 'push' UI updates to the main thread, but you don't need to do periodic updates with Clock, you can just schedule one-time calls with Clock.schedule_once.

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 装饰器:

As inclement mentioned, you can do this 'push to main thread' automatically with the @mainthread decorator:

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

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

这样,每当你调用 update 时,它都会在主线程上执行.

This way, whenever you call update it will be executed on the main thread.

这篇关于如何从线程更新 Kivy 元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆