如何为on_press传递带参数的函数?ScrollView报错求助
问题修复方案
核心问题分析
- 按钮回调绑定错误:你直接调用
self.btn_press(bl)会在App初始化时就执行函数,而非点击按钮时触发。Kivy的on_press需要接收带event参数的回调函数,不能直接传参数执行。 - ScrollView使用错误:ScrollView只能包含单个子部件,你当前逻辑把原根布局
bl加到ScrollView再返回,会导致布局层级混乱,因为原根已经是bl了。 - 同步网络请求阻塞UI:在主线程执行
requests.get会让应用卡住,直到请求完成,用户体验极差。
修复后的代码
from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Button from kivy.uix.label import Label from kivy.uix.scrollview import ScrollView from kivy.clock import mainthread import requests from bs4 import BeautifulSoup import threading class MyBoxLayout(BoxLayout): pass class MyButton(Button): pass class MyScrollView(ScrollView): pass class MyApp(App): def build(self): self.bl = MyBoxLayout(orientation='vertical', padding=[5], spacing=10) # 用lambda传递参数,同时保留点击事件对象 self.bl.add_widget(MyButton(text='И. С. Тургенев. «Отцы и дети»', on_press=lambda x: self.btn_press(self.bl))) # 初始就用ScrollView包裹布局,避免后续层级混乱 self.sc = MyScrollView(size_hint=(1, 1)) self.sc.add_widget(self.bl) return self.sc def btn_press(self, bl): # 启动线程处理网络请求,避免阻塞UI threading.Thread(target=self.fetch_and_update, args=(bl,), daemon=True).start() def fetch_and_update(self, bl): x = 1 data = '' while True: if x == 1: url = "http://loveread.ec/read_book.php?id=12021&p=1" elif x < 5: url = f"http://loveread.ec/read_book.php?id=12021&p={x}" else: break request = requests.get(url) soup = BeautifulSoup(request.text, "html.parser") teme = soup.find_all("p", class_="MsoNormal") for temes in teme: data += temes.text + '\n' # 加换行让文本排版更清晰 x += 1 # 回到主线程更新UI,Kivy要求UI操作必须在主线程执行 self.update_ui(bl, data) @mainthread def update_ui(self, bl, data): bl.clear_widgets() # 设置Label的size_hint_y=None,绑定texture_size到size,让高度适配文本内容 book_label = Label(text=data, color=(0,0,0,1), font_size=17, halign='left', valign='top', size_hint_y=None) book_label.bind(texture_size=book_label.setter('size')) bl.add_widget(book_label) if __name__ == '__main__': MyApp().run()
关键修改点说明
- 按钮回调:用
lambda x: self.btn_press(self.bl)绑定,x是按钮点击事件对象,确保点击时才触发函数并传递布局参数。 - ScrollView布局:初始化时就让ScrollView作为根部件包裹BoxLayout,后续只需更新BoxLayout内的内容,避免层级错误。
- 异步网络请求:用线程处理网页抓取,再通过
@mainthread装饰器在主线程更新UI,防止应用卡顿。 - Label滚动适配:给Label设置
size_hint_y=None并绑定texture_size,让Label高度随文本长度变化,保证ScrollView正常滚动。
内容的提问来源于stack exchange,提问作者NewbieTM
相关产品推荐
相关产品推荐

