Kivy动态添加TextInput后,如何将TreeView选中值填入当前输入框?
解决动态添加TextInput与TreeView的交互问题
嘿,我看你遇到的问题是动态添加的TextInput没办法把TreeView选中的节点值填进去对吧?其实核心就是要记住当前激活的那个TextInput实例,然后在TreeView弹窗里把选中的值传递给它就行。我来帮你一步步修改代码:
关键修改点
- 在Row类中保存当前激活的TextInput:当TextInput获得焦点打开弹窗时,把这个输入框实例存起来,方便后续赋值。
- 给TreeView添加选中事件监听:记录用户选中的节点文本。
- 修改弹窗Ok按钮的逻辑:把选中的节点值填入之前保存的激活输入框中。
修改后的完整代码
test1.py
import kivy kivy.require('1.9.0') # replace with your current kivy version ! import sqlite3 as lite from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.properties import BooleanProperty, ListProperty, StringProperty, ObjectProperty, NumericProperty from kivy.lang import Builder from kivy.uix.popup import Popup from kivy.core.window import Window from kivy.uix.label import Label from kivy.clock import Clock from kivy.uix.treeview import TreeView, TreeViewLabel, TreeViewNode from kivy.uix.screenmanager import Screen Window.size = (450, 525) class TreeviewNumber(Popup): treeview = ObjectProperty(None) tv = ObjectProperty(None) h = NumericProperty(0) selected_text = StringProperty("") # 新增:保存选中的节点文本 target_input = ObjectProperty(None) # 新增:保存要赋值的目标TextInput def __init__(self, **kwargs): super(TreeviewNumber, self).__init__(**kwargs) self.tv = TreeView(root_options=dict(text=""), hide_root=False, indent_level=4) # 新增:绑定TreeView的节点选中事件 self.tv.bind(on_node_select=self.on_node_selected) rows = [('One'), ('Two'), ('Three')] tree = [] for r in rows: tree.append({'node_id': r, 'children': []}) for branch in tree: populate_tree_view(self.tv, None, branch) self.treeview.add_widget(self.tv) Clock.schedule_once(self.update, 1) def remove_widgets(self): for child in [child for child in self.treeview.children]: self.treeview.remove_widget(child) def update(self, *args): self.h = len([child for child in self.tv.children]) * 24 # 新增:处理节点选中事件 def on_node_selected(self, tv, node): self.selected_text = node.text # 新增:点击Ok时把选中值填入目标输入框 def confirm_selection(self): if self.target_input and self.selected_text: self.target_input.text = self.selected_text self.dismiss() def populate_tree_view(tree_view_city, parent, node): if parent is None: tree_node = tree_view_city.add_node(TreeViewLabel(text=node['node_id'], is_open=True)) else: tree_node = tree_view_city.add_node(TreeViewLabel(text=node['node_id'], is_open=True), parent) for child_node in node['children']: populate_tree_view(tree_view_city, tree_node, child_node) class TreeViewLabel(Label, TreeViewNode): pass class display(Screen): def add_more(self): self.ids.rows.add_row() def insert_value(self): # 这里可以遍历所有Row获取输入值,示例: for row in self.ids.rows.children: if isinstance(row, Row): print(f"Row {row.button_text}: {row.ids.state.text}") class Row(BoxLayout): button_text = StringProperty("") state = ObjectProperty('') popupNumber = ObjectProperty(None) popup_number = ObjectProperty(None) def display_number(self, instance): if self.popupNumber is None: self.popupNumber = TreeviewNumber() # 新增:把当前激活的TextInput传给弹窗 self.popupNumber.target_input = instance self.popupNumber.open() class Rows(BoxLayout): orientation = "vertical" row_count = 0 button_text = StringProperty("") def __init__(self, **kwargs): super(Rows, self).__init__(**kwargs) self.add_row() def add_row(self): self.row_count += 1 self.add_widget(Row(button_text=str(self.row_count),id=str("test"+str(self.row_count)))) class test(App): def build(self): self.root = Builder.load_file('test1.kv') return self.root if __name__ == '__main__': test().run()
test1.kv
<Row>: state : state orientation: "horizontal" spacing: 0, 5 Button: text: root.button_text size_hint_x: .2 TextInput: size_hint_x: .8 id : state on_focus: root.display_number(self) if self.focus else None # 优化:只有获得焦点时才打开弹窗 display: BoxLayout: orientation: "vertical" padding : 20, 20 BoxLayout: orientation: "horizontal" Button: size_hint_x: .2 text: "+Add More" valign: 'bottom' on_press: root.add_more() BoxLayout: orientation: "horizontal" Label: size_hint_x: .2 text: "SN" valign: 'bottom' Label: size_hint_x: .8 text: "Value" valign: 'bottom' Rows: id: rows BoxLayout: orientation: "horizontal" padding : 10, 0 spacing: 10, 10 size_hint: .5, .7 pos_hint: {'x': .25, 'y':.25} Button: text: 'Ok' on_release: root.insert_value() Button: text: 'Cancel' on_release: app.stop() # 优化:直接退出程序,原root.dismiss()无效因为display是Screen <TreeviewNumber>: treeview: treeview title: "Select Number" title_size: 17 title_font: "Verdana" size_hint: .5, .5 auto_dismiss: False BoxLayout orientation: "vertical" ScrollView: size_hint: 1, .9 BoxLayout: size_hint_y: None id: treeview height: root.h # 修复:设置高度让ScrollView正常工作 GridLayout: cols : 2 row_default_height: '20dp' size_hint: .5, 0.2 pos_hint: {'x': .25, 'y': 0} Button: text: 'Ok' on_release: root.confirm_selection() # 修改:调用确认选中的方法 Button: text: 'Cancel' on_release: root.dismiss() <TreeViewLabel>: text_size: self.size height: 24
代码说明
- TreeviewNumber类:新增了
selected_text保存选中的节点文本,target_input保存要赋值的TextInput;绑定了TreeView的on_node_selected事件来更新选中文本;新增confirm_selection方法把值填入目标输入框。 - Row类:在打开弹窗时,把当前激活的TextInput实例传给弹窗的
target_input属性。 - KV文件:修改了TextInput的
on_focus逻辑,只有获得焦点时才打开弹窗;修改了弹窗Ok按钮的事件,调用confirm_selection;修复了TreeView的高度设置,让ScrollView正常滚动;修改了Cancel按钮的逻辑,因为原root.dismiss()对Screen无效,改为退出程序。
现在你运行代码,点击任意动态添加的TextInput,打开TreeView弹窗选中一个节点,点击Ok,就能把节点文本填入当前激活的输入框啦!
内容的提问来源于stack exchange,提问作者Nirdesh Kumawat
相关产品推荐
相关产品推荐

