Python - TypeError:无法在 Kivy 主线程之外创建图形指令

问题描述 投票:0回答:3

我试图在运行这个线程函数后更改屏幕。但它给了我错误

 TypeError: Cannot create graphics instruction outside the main Kivy thread

我在网上对此进行了研究,他们告诉我使用时钟属性,但我不知道如何在这里使用它。我只是希望能够通过该命令更改图形指令。但如果我不线程它,应用程序就会没有响应。

这是我的代码:

class Notice(Screen):
    def thread_notice(self):
            t1 = Thread(target= Notice.sendNotice, args =(self,))
            t1.daemon = True
            t1.start()
        
    def sendNotice(self):
        my_big_chunk_of_code()
        kv.current = 'menu'
python kivy
3个回答
0
投票

你不能在主线程之外执行任何 kivy 指令,这意味着你不能在不同的线程上运行 sendNotice,因为它有 kivy 代码...如果

my_big_chunk_of_code()
需要时间,则删除
kv.current = 'menu'
行并将其移动到,例如 thread_notice 函数。

顺便说一下,在线程中,我建议制定目标:

self.sendNotice
而不是
Notice.sendNotice
,我认为它创建了该类的另一个实例(不确定),它应该工作相同


0
投票

我迟到了,但我发布这个答案是为了将来对其他人有所帮助,所以因为你无法在主 Kivy 线程之外创建图形指令,所以你必须对此有点棘手,我面临着同样的问题不久前,这就是我解决这个问题的方法,所以你应该在启动线程之前先创建一个弹出窗口,然后启动你的线程,如果你想在线程内的函数中传递参数,你应该使用像这样的 lambda 函数。

    self.showLoadingPopUp() # showing pop up before starting thread
    try:
    # Using lambda  function for passing arguments in function inside thread
       threading.Thread(target=lambda : self.yourFunction(argument)).start() 
    except:
         print("Error: unable to start thread")

这不会阻塞您的 UI,当您创建弹出函数时,请确保为此使用类变量,这样您就可以从线程函数中关闭该弹出窗口,这是示例 -

class MyApp(App):

    def __init__(self):
        super().__init__()
        self.window = None
        self.loading = None

    # Main Build function
    def build(self):
        self.window = GridLayout()
        self.window.cols = 2
  
        return self.window

    def showLoadingPopUp(self):
        content = BoxLayout(orientation='vertical')
        self.loading = Popup(title="Loading", title_color='#FFFFFF', content=content, size=('700dp', '200dp'),
                             size_hint=(None, None),
                             auto_dismiss=False,
                             background='#FFFFFF')
        content.add_widget(Label(text="Loading...", color="#FFFFFF"))

        def _on_d(*args):
            self.loading.is_visable = False

        self.loading.bind(on_dismiss=_on_d)
        self.loading.is_visable = True

        self.loading.open()

        while not self.loading.is_visable:
            EventLoop.idle()

    def yourFunction(self, argument):
        for i in list:
            # code
        self.loading.dismiss() # dismissing old popup

所以简而言之,这个函数将首先创建一个弹出窗口,然后启动一个线程,当我们的工作完成时,线程最终将关闭带有类变量的弹出窗口。希望有帮助。


0
投票

对我来说,它可以从 kivy.core 导入主线程,然后使用此装饰器设置函数:

喜欢: `

from kivy.clock import mainthread
from kivy.app import App

class MyApp(App):

    @mainthread
    def create_something(self, *args): # this will run in mainthread, even if called  outside.
        # cool things created here 

`

© www.soinside.com 2019 - 2024. All rights reserved.