【问题标题】:How to make Kivy app run inside a thread?如何让 Kivy 应用程序在线程内运行?
【发布时间】:2021-07-21 05:11:25
【问题描述】:

我有一个非常简单的 Kivy 应用程序,可以像这样完美地运行:

def run_form():
    rules_form().run()


if __name__ == '__main__':
    run_form()

但我希望程序在 rules_form 窗口打开时继续运行。我尝试了以下方法:

def run_form():
    rules_form().run()


if __name__ == '__main__':
    t = Thread(target=run_form)
    t.start()
    print("Hi")

当我这样做时,程序会打印“hi”,但打开的 Kivy 窗口是白色的并且没有响应。

我怎样才能让它工作?

【问题讨论】:

  • 尝试反过来,在主线程中运行 kivy 并将其他任务分派到另一个线程。我认为kivy可能正在设置一些需要主状态的opengl状态。也就是说,我确信可以在线程中运行它,之前已经完成了。

标签: python multithreading user-interface kivy kivy-language


【解决方案1】:

我最近一直在使用 Kivy 处理线程,并且按照 Inclement 的建议进行了操作。也就是说,让 Kivy 在主线程中运行,然后将其他任务分派给另一个线程。

这是我创建的使用线程的应用示例:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.textinput import TextInput
from kivy.properties import ListProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.label import Label
import webbrowser
from wiki_recommendations import WikiSearcher


class SearchBar(TextInput):
    articles = ListProperty()

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.bind(text=self.on_text)
        self.bind(articles=self.on_articles)

    def on_text(self, *args):
        WikiSearcher().get_search_results(self.text, self)

    def on_articles(self, *args):
        self.parent.ids['recommendations'].update_recommendations(self.articles)


class SearchItem(ButtonBehavior, Label):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.url = ''

    def on_release(self):
        webbrowser.open(self.url)


class Recommendations(BoxLayout):

    def update_recommendations(self, recommendations: list):
        for (search_item, recommendation) in zip(self.children, recommendations):
            search_item.text = recommendation
            search_item.url = 'https://en.wikipedia.org/wiki/' + recommendation


kv = """
<SearchItem>:
    canvas.before:
        Color: 
            rgba: [0.8, 0.8, 0.8, 1] if self.state == 'normal' else [30/255, 139/255, 195/255, 1]
        Rectangle:
            size: self.size
            pos: self.pos
        Color:
            rgba: 0, 0, 0, 1
        Line:
            rectangle: self.x, self.y, self.width, self.height
            
    color: 0, 0, 0, 1
    
BoxLayout:
    canvas.before:
        Color: 
            rgba: 1, 1, 1, 1
        Rectangle:
            size: self.size
            pos: self.pos
            
    orientation: 'vertical'
    padding: self.width * 0.1
    spacing: self.height * 0.1

    SearchBar:
        size_hint: 1, 0.2
        multiline: False
        font_size: self.height*0.8

    Recommendations:
        id: recommendations
        orientation: 'vertical'
        SearchItem
        SearchItem
        SearchItem
        SearchItem
        SearchItem
"""


class SearchApp(App):

    def build(self):
        return Builder.load_string(kv)


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

此应用程序让用户在搜索栏中键入并自动推荐维基百科页面。屏幕截图如下:

此代码使用线程来获取建议(以免打断用户输入)。另一个名为 wiki_recommendataions.py 的文件创建这些线程,然后调度 API 调用。

import wikipedia
import threading


def thread(function):
    def wrap(*args, **kwargs):
        t = threading.Thread(target=function, args=args, kwargs=kwargs, daemon=True)
        t.start()

        return t
    return wrap


class WikiSearcher:

    @thread
    def get_search_results(self, text: str, root):
        """
        Gets the top Wikipedia articles
        :param text: The text to be searched.
        :param root: The object that calls this function - useful for returning a result.
        :return:
        """
        root.articles = wikipedia.search(text)

当用户在搜索栏中键入时,WikiSearcher 对象被实例化,get_search_results() 被调用。这会更新SearchBararticles 属性,而后者又会更新Recommendations(一个BoxLayout)的子代。这些孩子本质上只是Buttons,当用户按下它们时,它们会将用户引导至推荐页面。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-12
    • 1970-01-01
    • 2019-06-27
    • 2014-03-07
    • 1970-01-01
    • 2018-09-27
    • 2019-08-03
    相关资源
    最近更新 更多