Kivy / Python:根据类别列表更改TreeView中的子类别列表

时间:2017-11-24 12:30:50

标签: python python-2.7 kivy kivy-language

我已经用Python(test.py)和kivy(test.kv)编写了一些代码。当我运行test.py.then show test Menu和user子菜单时。当我点击用户然后+添加按钮show.When点击+添加然后显示两个TextBox类型

我在两个(类别和名称)中使用TreeView当我从catgory TextBox中选择Male时,显示男性名称rows1 = [(' Andrew'),(' Daniel'), ('心光&#39)。]
如果我从类别textBox中选择任何类别,则相同的列表显示。我希望它根据类别进行更改。

如果我从类别中选择女性,则应显示rows1 = [(' Atarah'),(' Abigail'),(' Adriel')]
如果我从类别中选择Dog,则应显示rows1 = [(' Abby'),(' Flash'),(' Penny')]

test.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.dropdown import DropDown

from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.button import Button
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.popup import Popup
from kivy.core.window import Window
from kivy.uix.label import Label
Window.maximize()
from kivy.clock import Clock
from kivy.uix.treeview import TreeView, TreeViewLabel, TreeViewNode
from kivy.uix.image import AsyncImage
import os
import sys


#root.attributes("-toolwindow", 1)


class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior,
                                  RecycleGridLayout):
    ''' Adds selection and focus behaviour to the view. '''




def populate_tree_view_account_group(tree_view_account_group, parent, node):

    if parent is None:
        tree_node = tree_view_account_group.add_node(TreeViewLabelAccountGroup(text=node['node_id'],
                                                     is_open=True))
    else:
        tree_node = tree_view_account_group.add_node(TreeViewLabelAccountGroup(text=node['node_id'],
                                                     is_open=True), parent)

    for child_node in node['children']:
        populate_tree_view_account_group(tree_view_account_group, tree_node, child_node)

#this is retrieve from database
rows = [(1, 'Male'), (2, 'Female'), (3, 'Dog')]
treeAccountGroup = []

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


class TreeviewAccountGroup(Popup):
    treeviewAccount = ObjectProperty(None)
    tv = ObjectProperty(None)
    h = NumericProperty(0)
    #ti = ObjectProperty()
    popup = ObjectProperty()

    def __init__(self, **kwargs):
        super(TreeviewAccountGroup, self).__init__(**kwargs)
        self.tv = TreeView(root_options=dict(text=""),
                       hide_root=False,
                       indent_level=4)
        for branch in treeAccountGroup:
            populate_tree_view_account_group(self.tv, None, branch)
        #self.remove_widgets()
        self.treeviewAccount.add_widget(self.tv)
        Clock.schedule_once(self.update, 1)

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

    def update(self, *args):
        self.h = len([child for child in self.tv.children]) * 24

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

        self.treeviewAccount.add_widget(self.tv)

def populate_tree_view_effect_type(tree_view_effect_type, parent, node):

    if parent is None:
        tree_node = tree_view_effect_type.add_node(TreeViewLabelEffectType(text=node['node_id'],
                                                     is_open=True))
    else:
        tree_node = tree_view_effect_type.add_node(TreeViewLabelEffectType(text=node['node_id'],
                                                     is_open=True), parent)

    for child_node in node['children']:
        populate_tree_view_effect_type(tree_view_effect_type, tree_node, child_node)

# male name list fetch from database
rows_male = [('Andrew'),('Daniel'),('Ebenezer')]

#girl name list fetch from database
rows_girl = [('Atarah'),('Abigail'),('Adriel')]

#Dog name list fetch from database
rows_dog = [('Abby'),('Flash'),('Penny')]

treeEffectType = {'Male': [], 'Female': [], 'Dog': []}
for r in rows_male:
    treeEffectType['Male'].append({'node_id': r, 'children': []})
for r in rows_girl:
    treeEffectType['Female'].append({'node_id': r, 'children': []})
for r in rows_dog:
    treeEffectType['Dog'].append({'node_id': r, 'children': []})

class TreeviewEffectType(Popup):
    treeviewEffectType = ObjectProperty(None)
    tv = ObjectProperty(None)
    h = NumericProperty(0)
    #ti = ObjectProperty()
    #popupEffect = ObjectProperty()

    def __init__(self, type, **kwargs):
        super(TreeviewEffectType, self).__init__(**kwargs)
        self.type = type
        self.tv = TreeView(root_options=dict(text=""),
                           hide_root=False,
                           indent_level=4)

        for branch in treeEffectType[self.type]:
            populate_tree_view_effect_type(self.tv, None, branch)
            # self.remove_widgets()
            self.treeviewEffectType.add_widget(self.tv)
            Clock.schedule_once(self.update, 1)

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

    def update(self, *args):
        self.h = len([child for child in self.tv.children]) * 24

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

        self.treeviewEffectType.add_widget(self.tv)


class TreeViewLabelAccountGroup(Label, TreeViewNode):
    pass

class TreeViewLabelEffectType(Label, TreeViewNode):
    pass

class AccountGroupPopup(Popup):
    category_label = ObjectProperty(None)
    category_text = ObjectProperty(None)
    name_label = ObjectProperty(None)
    name_txt = ObjectProperty(None)
    popupGroupAccount = ObjectProperty(None)
    popupEffect = {}

    groupType = ObjectProperty(None)

    mode = StringProperty("")
    col_data = ListProperty(["?", "?", "?", "?","?"])
    index = NumericProperty(0)
    popup4 = ObjectProperty(None)
    popup5 = ObjectProperty(None)

    primary_check_button = BooleanProperty(False)
    secondary_check_button = BooleanProperty(False)

    def __init__(self, obj, **kwargs):
        super(AccountGroupPopup, self).__init__(**kwargs)
        self.mode = obj.mode
        if obj.mode == "Add":
            self.col_data[0] = ''
            self.col_data[1] = ''
            self.col_data[2] = ''
            self.col_data[3] = 'Select Category'
            self.col_data[4] = 'Select Name'
        self.popupEffect['Male'] = TreeviewEffectType('Male')
        self.popupEffect['Male'].popup5 = self
        self.popupEffect['Female'] = TreeviewEffectType('Female')
        self.popupEffect['Female'].popup5 = self
        self.popupEffect['Dog'] = TreeviewEffectType('Dog')
        self.popupEffect['Dog'].popup5 = self

    def display_primary_treeview(self, instance):
        if len(instance.text) > 0:
            if self.popupGroupAccount is None:
                self.popupGroupAccount = TreeviewAccountGroup()
                self.popupGroupAccount.popup4 = self
                self.popupGroupAccount.filter(instance.text)
            self.popupGroupAccount.open()

    def display_effect_type(self, instance):
        if len(self.category_text.text) > 0:
            if self.popupEffect[self.category_text.text] is None:
                self.popupEffect[self.category_text.text] = TreeviewEffectType(self.category_text.text)
                self.popupEffect[self.category_text.text].popup5 = self
                self.popupEffect[self.category_text.text].filter(self.category_text.text)
            self.popupEffect[self.category_text.text].open()

class SelectableButtonGroupAccount(RecycleDataViewBehavior, Button):
    ''' Add selection support to the Button '''
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)
    rv_data_account_group = ObjectProperty(None)
    start_point = NumericProperty(0)
    mode = StringProperty("Update")

    def __init__(self, **kwargs):
        super(SelectableButtonGroupAccount, self).__init__(**kwargs)
        Clock.schedule_interval(self.update, .0005)


    def update(self, *args):
        self.text = self.rv_data_account_group[self.index][self.key]

    def refresh_view_attrs(self, rv, index, data):
        ''' Catch and handle the view changes '''
        self.index = index
        return super(SelectableButtonGroupAccount, self).refresh_view_attrs(rv, index, data)

    def on_touch_down(self, touch):
        ''' Add selection on touch down '''
        if super(SelectableButtonGroupAccount, self).on_touch_down(touch):
            return True
        if self.collide_point(*touch.pos) and self.selectable:
            return self.parent.select_with_touch(self.index, touch)

    def apply_selection(self, rv, index, is_selected):
        ''' Respond to the selection of items in the view. '''
        self.selected = is_selected
        self.rv_data_account_group = rv.data
        #print("selection changed to {0}".format(rv.data[1]))

    def on_press(self):
        popup = AccountGroupPopup(self)
        popup.open()

class RVACCOUNTGROUP(BoxLayout):

    def add_account_group(self):
        self.mode = "Add"
        popup = AccountGroupPopup(self)
        popup.open()

class CustDrop(DropDown):
    def __init__(self, **kwargs):
        super(CustDrop, self).__init__(**kwargs)
        self.select('')

class MainMenu(BoxLayout):
    content_area = ObjectProperty()
    rv = ObjectProperty(None)
    dropdown = ObjectProperty(None)

    def display_account_group(self):
        self.dropdown.dismiss()
        self.remove_widgets()
        self.rvarea = RVACCOUNTGROUP()
        self.content_area.add_widget(self.rvarea)

    def remove_widgets(self):
        self.content_area.clear_widgets()


    def insert_update(self, obj):
        print('Test')


class TacApp(App):
    title = "FactEx"

    def build(self):
        self.root = Builder.load_file('test.kv')
        return MainMenu()



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

test.kv

#:kivy 1.10.0
#:import CoreImage kivy.core.image.Image
#:import os os

<TreeviewAccountGroup>:
    id: treeviewAccount
    treeviewAccount: treeviewAccount
    title: ""
    pos_hint: {'x': .65, 'y': .3}
    size_hint: .2,.4
    #size: 800, 800
    auto_dismiss: False

    BoxLayout
        orientation: "vertical"
        ScrollView:
            size_hint: 1, .9
            BoxLayout:
                size_hint_y: None
                id: treeviewAccount
                height: root.h
                rooot: root
        TextInput:
            id: treeview
            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()


<TreeviewEffectType>:
    #id: treeviewAccount
    treeviewEffectType: treeviewEffectType
    title: ""
    pos_hint: {'x': .65, 'y': .3}
    size_hint: .2,.4
    #size: 800, 800
    auto_dismiss: False

    BoxLayout
        orientation: "vertical"
        ScrollView:
            size_hint: 1, .9
            BoxLayout:
                size_hint_y: None
                id: treeviewEffectType
                height: root.h
                rooot: root
        TextInput:
            id: treeview
            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()

<TreeViewLabelEffectType>:
    height: 24
    on_touch_down:
        root.parent.parent.rooot.popup5.col_data[4] = self.text
        #app.root.effect_type_txt.text = self.text
        #root.parent.parent.rooot.popup5.popup.dismiss()

<TreeViewLabelAccountGroup>:
    height: 24
    on_touch_down:
        root.parent.parent.rooot.popup4.col_data[3] = self.text
        #app.root.effect_type_txt.text = self.text
        #app.root.popupEffect.dismiss()


<AccountGroupPopup>:
    title: ""
    size_hint: None, None
    size: 500, 350
    auto_dismiss: False
    name_label: name_label
    name_txt: name_txt
    category_text: category_text



    BoxLayout:
        orientation: "vertical"

        GridLayout:
            cols: 2
            padding : 30, 0
            row_default_height: '30dp'
            size_hint: 1, .1
            pos_hint: {'x': .1, 'y': .06}

        GridLayout:
            cols: 2
            padding: 10, 10
            spacing: 20, 20
            #row_default_height: '30dp'
            size_hint: 1, .7
            pos_hint: {'x': 0, 'y':.65}

            Label:
                id:category_label
                text: 'Category'
                text_size: self.size
                valign: 'middle'

            TextInput:
                id: category_text
                text: root.col_data[3]
                on_focus: root.display_primary_treeview(self)

            Label:
                id:name_label
                text: 'Name'
                text_size: self.size
                valign: 'middle'

            TextInput:
                id: name_txt
                text: root.col_data[4]
                on_focus: root.display_effect_type(self)
            Button:
                text: 'Ok'
                on_release:
                    #root.package_changes(name_txt.text,primary_group_txt.text,effect_type_txt.text)
                    app.root.insert_update(root)
                    root.dismiss()


            Button:
                text: 'Cancel'
                on_release: root.dismiss()

<AccountGroup@RecycleView>:
    viewclass: 'SelectableButtonGroupAccount'
    SelectableRecycleGridLayout:
        cols: 1
        default_size: None, dp(26)
        default_size_hint: 1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: 'vertical'
        multiselect: True
        touch_multiselect: True

<RVACCOUNTGROUP>:
    BoxLayout:
        orientation: "vertical"
        Button:
            size_hint: .05, .03
            text: "+Add"
            on_press: root.add_account_group()


<DropdownButton@Button>:
    border: (0, 16, 0, 16)
    text_size: self.size
    valign: "middle"
    padding_x: 5
    size_hint_y: None
    height: '30dp'
    #on_release: dropdown.select('')
    #on_release: app.root.test
    background_color: 90 , 90, 90, 90
    color: 0, 0.517, 0.705, 1



<MenuButton@Button>:
    text_size: self.size
    valign: "middle"
    padding_x: 5
    size : (80,30)
    size_hint : (None, None)
    background_color: 90 , 90, 90, 90
    background_normal: ''
    color: 0, 0.517, 0.705, 1
    border: (0, 10, 0, 0)


<MainMenu>:
    content_area: content_area
    dropdown: dropdown

    BoxLayout:
        orientation: 'vertical'
        #spacing : 10

        BoxLayout:
            canvas.before:
                Rectangle:
                    pos: self.pos
                    size: self.size

            size_hint_y: 1

            MenuButton:
                id: btn
                text: 'Test'
                size : (60,30)
                on_release: dropdown.open(self)

            CustDrop:
                id: dropdown
                auto_width: False
                width: 150

                DropdownButton:
                    text: 'User'
                    size_hint_y: None
                    height: '32dp'
                    # on_release: dropdown3.open(self)
                    on_release: root.display_account_group()


        BoxLayout:
            id: content_area
            size_hint_y: 30


        Label:
            size_hint_y: 1

有人可以帮助我吗?

1 个答案:

答案 0 :(得分:1)

第一件事。您必须为不同的类别制作不同的列表

# male name list fetch from database
rows_male = [('Andrew'),('Daniel'),('Ebenezer')]

#girl name list fetch from database
rows_girl = [('Atarah'),('Abigail'),('Adriel')]

#Dog name list fetch from database
rows_dog = [('Abby'),('Flash'),('Penny')]

然后制作一个包含每棵树的词典

treeEffectType = {'Male': [], 'Female': [], 'Dog': []}
for r in rows_male:
    treeEffectType['Male'].append({'node_id': r, 'children': []})
for r in rows_girl:
    treeEffectType['Female'].append({'node_id': r, 'children': []})
for r in rows_dog:
    treeEffectType['Dog'].append({'node_id': r, 'children': []})

然后编辑一下TreeViewEffectType类:

class TreeviewEffectType(Popup):
...
        def __init__(self, type, **kwargs):
            super(TreeviewEffectType, self).__init__(**kwargs)
            self.type = type
            self.tv = TreeView(root_options=dict(text=""),
                               hide_root=False,
                               indent_level=4)

            for branch in treeEffectType[self.type]:
                populate_tree_view_effect_type(self.tv, None, branch)
                #self.remove_widgets()
            self.treeviewEffectType.add_widget(self.tv)
            Clock.schedule_once(self.update, 1)

            ...

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

                self.treeviewEffectType.add_widget(self.tv)

我们需要第一个文本输入的值,因此您必须将该属性保存在kv:

...
<AccountGroupPopup>:
    title: ""
    size_hint: None, None
    size: 500, 350
    auto_dismiss: False
    name_label: name_label
    name_txt: name_txt
    category_text: category_text
...

最后编辑您的AccountGroupPopup:

...

class AccountGroupPopup(Popup):
    category_label = ObjectProperty(None)
    category_text = ObjectProperty(None)
    name_label = ObjectProperty(None)
    name_txt = ObjectProperty(None)
    popupGroupAccount = ObjectProperty(None)
    popupEffect = {}
    ...

        def __init__(self, obj, **kwargs):
            super(AccountGroupPopup, self).__init__(**kwargs)
            self.mode = obj.mode
            if obj.mode == "Add":
                self.col_data[0] = ''
                self.col_data[1] = ''
                self.col_data[2] = ''
                self.col_data[3] = 'Select Category'
                self.col_data[4] = 'Select Name'
            self.popupEffect['Male'] = TreeviewEffectType('Male')
            self.popupEffect['Male'].popup5 = self
            self.popupEffect['Female'] = TreeviewEffectType('Female')
            self.popupEffect['Female'].popup5 = self
            self.popupEffect['Dog'] = TreeviewEffectType('Dog')
            self.popupEffect['Dog'].popup5 = self
        ...

        def display_effect_type(self, instance):
            if len(self.category_text.text) > 0:
                if self.popupEffect[self.category_text.text] is None:
                    self.popupEffect[self.category_text.text] = TreeviewEffectType(self.category_text.text)
                    self.popupEffect[self.category_text.text].popup5 = self
                    self.popupEffect[self.category_text.text].filter(instance.text)
                self.popupEffect[self.category_text.text].open()