我最近一直在使用 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() 被调用。这会更新SearchBar 的articles 属性,而后者又会更新Recommendations(一个BoxLayout)的子代。这些孩子本质上只是Buttons,当用户按下它们时,它们会将用户引导至推荐页面。