【问题标题】:when click on row showing error IndexError: list index out of range当单击显示错误 IndexError 的行时:列表索引超出范围
【发布时间】:2017-11-13 07:51:37
【问题描述】:

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, 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    
Window.size = (900, 500)



MAX_TABLE_COLS = 3

con = lite.connect('demo.db')
con.text_factory = str
cur = con.cursor()

class EditStatePopup(Popup):
    col_data = ListProperty(["?", "?", "?"])
    index = NumericProperty(0)

    def __init__(self, obj, **kwargs):
        super(EditStatePopup, self).__init__(**kwargs)
        self.index = obj.index
        self.col_data[0] = obj.rv_data[self.index]["Id"]
        self.col_data[1] = obj.rv_data[self.index]["Name"]
        self.col_data[2] = obj.rv_data[self.index]["Code"]

    def package_changes(self, stateName, stateCode):
        self.col_data[1] = stateName
        self.col_data[2] = stateCode


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


class SelectableButton(RecycleDataViewBehavior, Button):
    ''' Add selection support to the Button '''
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)
    rv_data = ObjectProperty(None)
    start_point = NumericProperty(0)

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

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

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

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

    def on_touch_down(self, touch):
        ''' Add selection on touch down '''
        if super(SelectableButton, 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 = rv.data
        #print("selection changed to {0}".format(rv.data[1]))

class RV(BoxLayout):
    data_items = ListProperty([])
    col1 = ListProperty()
    col2 = ListProperty()
    col3 = ListProperty()

    def __init__(self, **kwargs):
        super(RV, self).__init__(**kwargs)
        self.get_states()

    def update(self):
        self.col1 = [{'Id': str(x[0]), 'Name': x[1], 'Code': x[2], 'key': 'Id'} for x in self.data_items]
        self.col2 = [{'Id': str(x[0]), 'Name': x[1], 'Code': x[2], 'key': 'Name'} for x in self.data_items]
        self.col3 = [{'Id': str(x[0]), 'Name': x[1], 'Code': x[2], 'key': 'Code'} for x in self.data_items]

    def get_states(self):

        rows = [(1, 'Yash', 'Chopra'), (2, 'amit', 'Kumar')]
        # create data_items

        i = 0
        for row in rows:
            self.data_items.append([row[0], row[1], row[2], i])
            i += 1
        self.update()

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

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

    def display_states(self):
        self.dropdown.dismiss()
        self.remove_widgets()
        self.rv = RV()
        self.states.add_widget(self.rv)

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

    def update_states(self, obj):
        # update data_items
        # obj.start_point + 1 --- skip State_ID
        self.rv.data_items[obj.index] = [ obj.col_data[0], obj.col_data[1], obj.col_data[2], obj.index]
        self.rv.update()
        # update Database Table
        cur.execute("UPDATE m_state SET state_name=?, state_code=? WHERE state_id=?",
                (obj.col_data[1], obj.col_data[2], obj.col_data[0]))
        con.commit()

class TestApp(App):
    title = "test"

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



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

test.kv

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

<EditStatePopup>:
    title: "Update State"
    size_hint: None, None
    size: 300, 300
    auto_dismiss: False

    BoxLayout:
        orientation: "vertical"
        GridLayout:
            cols: 2
            Label:
                text: "Id"
            Label:
                id: Id
                text: root.col_data[0]
            Label:
                text: "Name"
            TextInput:
                id: Name
                text: root.col_data[1]
            Label:
                text: "Code"
            TextInput:
                id: stateCode
                text: root.col_data[2]

            Button:
                size_hint: 1, 0.4
                text: "Cancel"
                on_release: root.dismiss()

            Button:
                size_hint: 1, 0.4
                text: "Ok"
                on_release:
                    root.package_changes(Name.text, Code.text)
                    #root.obj.update_states(root.start_point, root.max_table_cols, root.new_data)
                    app.root.update_states(root)
                    root.dismiss()



<SelectableButton>:
    # Draw a background to indicate selection
    canvas.before:
        Color:
            rgba: (0, 0.517, 0.705, 1) if self.selected else (0, 0.517, 0.705, 1)
        Rectangle:
            pos: self.pos
            size: self.size


<MyRV@RecycleView>:
    viewclass: 'SelectableButton'
    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

<RV>:
    BoxLayout:
        orientation: "vertical"

        GridLayout:
            size_hint: 1, None
            size_hint_y: None
            height: 25
            cols: 3

            Label:
                size_hint_x: .1
                text: "Id"
            Label:
                size_hint_x: .5
                text: "Name"
            Label:
                size_hint_x: .4
                text: "Code"

        BoxLayout:
            MyRV:
                size_hint_x: .1
                data: root.col1
            MyRV:
                size_hint_x: .5
                data: root.col2
            MyRV:
                size_hint_x: .4
                data: root.col3


<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


#<CustDrop>:
    #id: dropdown
    #auto_width: False
    #width: 150
    #DropdownButton:
        #text: 'Add State'
        #on_release: os.system("python m_State.py")

    #DropdownButton:
        #text: 'List State'
        #on_release: root.display_users()

<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>:
    states: states
    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: 'Menu'
                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_states()

        BoxLayout:
            id: states
            size_hint_y: 9

        Label:
            size_hint_y: 9
  1. 当我单击菜单然后显示子菜单用户。当单击用户时,当我单击任何用户行时显示用户列表然后显示错误 IndexError: list index out of range。
  2. update_states() 函数未在数据库中更新

【问题讨论】:

  • 你忘记导入Clock:from kivy.clock import Clock

标签: python python-2.7 kivy kivy-language


【解决方案1】:

1.当我点击菜单然后显示子菜单用户。当点击用户时,当我点击任何一行用户时显示用户列表,然后显示错误,如附加图像。

您正在遍历行,您只有两行但有 3 列

  1. update_states() 函数未在数据库中更新

我不认为编译器会终止该函数,因为它几乎没有错误

为了让您的代码正常工作,我必须进行许多更改

首先准备好python文件中rvs的数据

...

class RV(BoxLayout):
    data_items = ListProperty([])
    col1 = ListProperty()
    col2 = ListProperty()
    col3 = ListProperty()

    def __init__(self, **kwargs):
        super(RV, self).__init__(**kwargs)
        self.get_states()

    def update(self):
        self.col1 = [{'Id': str(x[0]), 'Name': x[1], 'Code': x[2], 'key': 'Id'} for x in self.data_items]
        self.col2 = [{'Id': str(x[0]), 'Name': x[1], 'Code': x[2], 'key': 'Name'} for x in self.data_items]
        self.col3 = [{'Id': str(x[0]), 'Name': x[1], 'Code': x[2], 'key': 'Code'} for x in self.data_items]

    def get_states(self):

        #cur.execute("SELECT * FROM `m_state` order by state_id asc")
        #rows = cur.fetchall()
        rows = [(1, 'Yash', 'Chopra'), (2, 'amit', 'Kumar')]
        # create data_items
        '''for row in rows:
            for col in row:
                self.data_items.append(col)'''
        i = 0
        for row in rows:
            self.data_items.append([row[0], row[1], row[2], i])
            i += 1
        self.update()

...

然后在kv中将rvs的数据分别替换为col1、col2、col3

...

<RV>:
    BoxLayout:
        orientation: "vertical"

        GridLayout:
            size_hint: 1, None
            size_hint_y: None
            height: 25
            cols: 3

            Label:
                size_hint_x: .1
                text: "Id"
            Label:
                size_hint_x: .5
                text: "Name"
            Label:
                size_hint_x: .4
                text: "Code"

        BoxLayout:
            MyRV:
                size_hint_x: .1
                data: root.col1
            MyRV:
                size_hint_x: .5
                data: root.col2
            MyRV:
                size_hint_x: .4
                data: root.col3

...

要在编辑时自动更改 rvs 按钮的文本,我必须安排一个功能

...

class SelectableButton(RecycleDataViewBehavior, Button):
    ''' Add selection support to the Button '''
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)
    rv_data = ObjectProperty(None)
    start_point = NumericProperty(0)

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

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

...

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

...

你还得编辑EditStatePopup,我添加了索引属性,因为和他一起在主菜单中进行更改会容易得多

...

class EditStatePopup(Popup):
    col_data = ListProperty(["?", "?", "?"])
    index = NumericProperty(0)

    def __init__(self, obj, **kwargs):
        super(EditStatePopup, self).__init__(**kwargs)
        self.index = obj.index
        self.col_data[0] = obj.rv_data[self.index]["Id"]
        self.col_data[1] = obj.rv_data[self.index]["Name"]
        self.col_data[2] = obj.rv_data[self.index]["Code"]

最后编辑MainMenu类的updtate_states

...

class MainMenu(BoxLayout):
...
    def update_states(self, obj):
        # update data_items
        # obj.start_point + 1 --- skip State_ID
        self.rv.data_items[obj.index] = [ obj.col_data[0], obj.col_data[1], obj.col_data[2], obj.index]
        self.rv.update()
        # update Database Table
        cur.execute("UPDATE m_state SET state_name=?, state_code=? WHERE state_id=?",
                (obj.col_data[1], obj.col_data[2], obj.col_data[0]))
        con.commit()

进行这些更改时请小心。我希望这会有所帮助

【讨论】:

  • 我已经编辑了代码。我不知道我在哪里犯了错误。请问可以看一下吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-02
  • 2018-04-22
  • 2020-09-04
  • 1970-01-01
  • 1970-01-01
  • 2019-09-06
相关资源
最近更新 更多