You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kivy动态添加TextInput后,如何将TreeView选中值填入当前输入框?

解决动态添加TextInput与TreeView的交互问题

嘿,我看你遇到的问题是动态添加的TextInput没办法把TreeView选中的节点值填进去对吧?其实核心就是要记住当前激活的那个TextInput实例,然后在TreeView弹窗里把选中的值传递给它就行。我来帮你一步步修改代码:

关键修改点

  1. 在Row类中保存当前激活的TextInput:当TextInput获得焦点打开弹窗时,把这个输入框实例存起来,方便后续赋值。
  2. 给TreeView添加选中事件监听:记录用户选中的节点文本。
  3. 修改弹窗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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:57:55