Search code examples
pythonpython-2.7kivykivy-language

use multiple treeview widgets in kivy


test.py

import sqlite3 as lite

from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.popup import Popup
from kivy.uix.treeview import TreeView, TreeViewLabel, TreeViewNode
from kivy.uix.label import Label
from kivy.properties import ObjectProperty,StringProperty
import sys
Window.clearcolor = (.152, .149, .149, 0)
Window.size = (700, 330)


def populate_tree_view(tree_view, parent, node):
    if parent is None:
        tree_node = tree_view.add_node(TreeViewLabel(text=node['node_id'],
                                                     is_open=True))
    else:
        tree_node = tree_view.add_node(TreeViewLabel(text=node['node_id'],
                                                     is_open=True), parent)

    for child_node in node['children']:
        populate_tree_view(tree_view, tree_node, child_node)

rows = [('1','1','city1'),('2','2','city2'),('3','3','city3')]
tree = []

for r in rows:
    tree.append({'node_id': r[2], 'children': []})


class TreeViewLabel(Label, TreeViewNode):
    pass

class TreeviewGroup(Popup):
    treeview = ObjectProperty(None)
    tv = ObjectProperty(None)
    #ti = ObjectProperty()

    def __init__(self, **kwargs):
        super(TreeviewGroup, self).__init__(**kwargs)
        self.tv = TreeView(root_options=dict(text=""),
                       hide_root=False,
                       indent_level=4)
        for branch in tree:
            populate_tree_view(self.tv, None, branch)
        self.remove_widgets()
        self.treeview.add_widget(self.tv)

    def remove_widgets(self):
        for child in [child for child in self.treeview.children]:
            self.treeview.remove_widget(child)

    def filter(self, f):
        self.treeview.clear_widgets()
        self.tv = TreeView(root_options=dict(text=""),
                           hide_root=False,
                           indent_level=4)
        new_tree = []
        for n in tree:
            if f.lower() in n['node_id'].lower():
                new_tree.append(n)
        for branch in new_tree:
            populate_tree_view(self.tv, None, branch)

        self.treeview.add_widget(self.tv)

def populate_tree_view_area(tree_view, parent, node):
    if parent is None:
        tree_node = tree_view.add_node(TreeViewLabel(text=node['node_id'],
                                                     is_open=True))
    else:
        tree_node = tree_view.add_node(TreeViewLabel(text=node['node_id'],
                                                     is_open=True), parent)

    for child_node in node['children']:
        populate_tree_view(tree_view, tree_node, child_node)

rows = [('1','1','area1'),('2','2','area2'),('3','3','area3')]
treeArea = []

for r in rows:
    treeArea.append({'node_id': r[2], 'children': []})

class TreeviewArea(Popup):
    treeviewArea = ObjectProperty(None)
    tv = ObjectProperty(None)
    #ti = ObjectProperty()

    def __init__(self, **kwargs):
        super(TreeviewArea, self).__init__(**kwargs)
        self.tv = TreeView(root_options=dict(text=""),
                       hide_root=False,
                       indent_level=4)
        for branch in treeArea:
            populate_tree_view_area(self.tv, None, branch)
        self.remove_widgets()
        self.treeviewArea.add_widget(self.tv)

    def remove_widgets(self):
        for child in [child for child in self.treeviewArea.children]:
            self.treeviewArea.remove_widget(child)

class AreaScreen(Screen):
    groupName = ObjectProperty(None)
    popup = ObjectProperty(None)
    #statecode = StringProperty('')

    def display_cities(self, instance):
        if len(instance.text) > 0:
            if self.popup is None:
                self.popup = TreeviewGroup()
            #self.popup.filter(instance.text)
            self.popup.open()

    def display_areas(self, instance):
        if len(instance.text) > 0:
            if self.popup is None:
                self.popup = TreeviewGroup()
            #self.popup.filter(instance.text)
            self.popup.open()


class FactArea(App):
    def build(self):
        self.root = Builder.load_file('test.kv')
        return self.root



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

test.kv

:kivy 1.10.0

<TreeViewLabel>:
    on_touch_down:
        app.root.cityName.text = self.text
        #app.root.select_node(self)
        app.root.popup.dismiss()

<TreeviewGroup>:
    id: treeview
    treeview: treeview
    title: "Select City"
    size_hint: None, None
    size: 400, 350
    auto_dismiss: False

    BoxLayout
        orientation: "vertical"
        #TextInput:
            #id: ti
            #size_hint_y: .1
            #on_text: root.filter(self.text)
        BoxLayout:
            id: treeview
            #on_press: root.select_node(self.text)
        Button:
            size_hint: 1, 0.1
            text: "Close"
            on_release: root.dismiss()

<TreeviewGroupArea>:
    id: treeviewArea
    treeviewArea: treeviewArea
    title: "Select City"
    size_hint: None, None
    size: 400, 350
    auto_dismiss: False

    BoxLayout
        orientation: "vertical"
        #TextInput:
            #id: ti
            #size_hint_y: .1
            #on_text: root.filter(self.text)
        BoxLayout:
            id: treeviewArea
            #on_press: root.select_node(self.text)
        Button:
            size_hint: 1, 0.1
            text: "Close"
            on_release: root.dismiss()

<CustomLabel@Label>:
    text_size: self.size
    valign: "middle"
    padding_x: 5

<SingleLineTextInput@TextInput>:
    multiline: False


<GreenButton@Button>:
    background_color: 1, 1, 1, 1
    size_hint_y: None
    height: self.parent.height * 0.200

AreaScreen:
    cityName: cityName

    GridLayout:
        cols: 2
        padding : 30,30
        spacing: 10, 10
        row_default_height: '30dp'

        Label:
            text: 'City'
            text_size: self.size
            valign: 'middle'
            padding_x: 50


        SingleLineTextInput:
            id: cityName
            font_size_valign:self.height*0.4
            on_text: root.display_cities(self)

        Label:
            text: 'Area'
            text_size: self.size
            valign: 'middle'
            padding_x: 50


        SingleLineTextInput:
            id: areaName
            on_text: root.display_areas(self)


        GreenButton:
            text: 'Ok'
            on_press: root.insert_data(cityName.text, areaName.text)



        GreenButton:
            text: 'Cancel'
            on_press: app.stop()

If i type anything in city then city shows in treeview.But i type anything in area then also shows city.I have written separate function for area but i don't know what is wrong?If it is possible use same function with if else condition for city treeview and area treeview.Code won't be repeat so it will be very better.

I select city then value put in city TextBox but i select area then value also set in city TextBox.How to put value in separate TextBox?City treeView value put in city TextBox and Area TreeView value put in area TextBox.


Solution

  • I know you tried to modify but it's not enough, you must redefine the TreeView class and the TreeViewLabel for each popup

    I will only post the necessary for the Area popup

    ...
    def populate_tree_view_area(tree_view, parent, node):
        if parent is None:
            tree_node = tree_view.add_node(TreeViewLabelArea(text=node['node_id'],
                                                     is_open=True))
        else:
            tree_node = tree_view.add_node(TreeViewLabelArea(text=node['node_id'],
                                                     is_open=True), parent)
    
        for child_node in node['children']:
            populate_tree_view(tree_view, tree_node, child_node)
    
    rowsa = [('1','1','area1'),('2','2','area2'),('3','3','area3')]
    treeArea = []
    
    for r in rowsa:
        treeArea.append({'node_id': r[2], 'children': []}) 
    
    class TreeViewLabelArea(Label, TreeViewNode):
        pass
    
    class TreeviewArea(Popup):
    #You can let it as it is
    
    ...
    
    class AreaScreen(Screen):
        groupName = ObjectProperty(None)
        popupcity = ObjectProperty(None)
        popuparea = ObjectProperty(None)
        #statecode = StringProperty('')
    
        ...
    
        def display_areas(self, instance):
            if len(instance.text) > 0:
                if self.popuparea is None:
                    self.popuparea = TreeviewArea()
                #self.popup.filter(instance.text)
                self.popuparea.open()
    

    then in your kv replace TreaviewGroupArea by TreeViewArea as defined in the main and add the TreeViewLabelArea rule

    ...
    <TreeViewLabelArea>:
        height: 24
        on_touch_down:
            app.root.areaName.text = self.text
            #app.root.select_node(self)
            app.root.popuparea.dismiss()
    

    Finally add the areaName property in the AreaScreen rule

    ...
    AreaScreen:
        cityName: cityName
        areaName: areaName
    ...
    

    I hope this helps