当我单击行时,它显示错误 IndexError: list index out of range
问题描述
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
import sys
#Window.borderless = True
#Window.clearcolor = (0, 0.517, 0.705, 1)
Window.size = (900, 500)
#from easygui import msgbox
#db =lite.connect(':memory:')
con = lite.connect('test.db')
con.text_factory = str
cur = con.cursor()
class EditStatePopup(Popup):
obj = ObjectProperty(None)
start_point = NumericProperty(0)
max_table_cols = NumericProperty(0)
new_data = ListProperty([])
stateId = StringProperty("")
stateName = StringProperty("")
stateCode = StringProperty("")
def __init__(self, obj, **kwargs):
super(EditStatePopup, self).__init__(**kwargs)
self.obj = obj
self.start_point = obj.start_point
self.max_table_cols = obj.max_table_cols
self.stateId = obj.rv_data[obj.start_point]["text"]
self.stateName = obj.rv_data[obj.start_point + 1]["text"]
self.stateCode = obj.rv_data[obj.start_point + 2]["text"]
def package_changes(self, stateId, stateName, stateCode):
print(stateName)
self.new_data.append(stateId)
self.new_data.append(stateName)
self.new_data.append(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)
max_table_cols = NumericProperty(3)
data_items = ListProperty([])
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]))
def on_press(self):
end_point = self.max_table_cols
rows = len(self.rv_data) # self.max_table_cols
#print(end_point) // 3
#print(rows) // 3
for row in range(rows):
cols = list(range(end_point))
#print(cols) // [0, 1, 2]
#print(self.index) //1
#print(self.max_table_cols)//3
if self.index in cols:
break
self.start_point += self.max_table_cols
end_point += self.max_table_cols
popup = EditStatePopup(self)
popup.open()
def update_states(self, stateId, stateName, stateCode):
cur.execute("UPDATE m_state SET state_name=?, state_code=? WHERE state_id=?",(stateName, stateCode, stateId))
con.commit()
class RV(BoxLayout):
data_items = ListProperty([])
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.get_states()
def get_states(self):
cur.execute("SELECT * FROM `m_state` order by state_id asc")
rows = cur.fetchall()
#print(rows)
# create data_items
rows = [(1, 'Test', '01'), (2, 'test2', '02'), (2, 'test2', '03')]
for row in rows:
for col in row:
self.data_items.append(col)
#print(col)
class CustDrop(DropDown):
def __init__(self, **kwargs):
super(CustDrop, self).__init__(**kwargs)
self.select('')
class MainMenu(BoxLayout):
states = ObjectProperty(None)
dropdown = ObjectProperty(None)
def display_states(self):
# rv = RV()
self.dropdown.dismiss()
self.states.add_widget(RV())
#return CustDrop()
class FactApp(App):
title = "Test"
def build(self):
self.root = Builder.load_file('m_ListState.kv')
return MainMenu()
if __name__ == '__main__':
FactApp().run()
m_ListState.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: stateId
text: root.stateId
Label:
text: "Name"
TextInput:
id: stateName
text: root.stateName
Label:
text: "Code"
TextInput:
id: stateCode
text: root.stateCode
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(stateId.text, stateName.text, stateCode.text)
#root.obj.update_states(root.start_point, root.max_table_cols, root.new_data)
root.obj.update_states(stateId.text, stateName.text, stateCode.text)
root.dismiss()
<SelectableButton>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (0, 0, 0, 1)
Rectangle:
pos: self.pos
size: self.size
<RV>:
BoxLayout:
orientation: "vertical"
GridLayout:
size_hint: 1, None
size_hint_y: None
height: 25
cols: 3
Label:
text: "Id"
Label:
text: "Name"
Label:
text: "Code"
BoxLayout:
RecycleView:
viewclass: 'SelectableButton'
data: [{'text': str(x)} for x in root.data_items]
SelectableRecycleGridLayout:
cols: 3
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
<DropdownButton@Button>:
border: (0, 16, 0, 16)
text_size: self.size
valign: "middle"
padding_x: 5
size_hint_y: None
height: '30dp'
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>:
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: 'View'
size : (60,30)
on_release: dropdown.open(self)
CustDrop:
id: dropdown
auto_width: False
width: 150
DropdownButton:
text: 'State'
size_hint_y: None
height: '32dp'
#on_release: dropdown3.open(self)
on_release: root.display_states()
DropdownButton:
text: 'City'
size_hint_y: None
height: '32dp'
#on_release: dropdown3.open(self)
on_release: root.display_city()
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
Color:
rgb: (1,1,1)
AsyncImage:
source: "add.jpg"
#on_release: os.system("python m_State.py")
Label:
size_hint_x: 22
BoxLayout:
id: states
size_hint_y: 9
Label:
size_hint_y: 9
谁能帮忙解决一些问题??
1.当我一次又一次单击状态(视图子菜单)时,数据会重复.如何避免它.当我单击状态时,应显示状态列表,当我单击城市时,应显示城市列表.display_city()我还没有写这个只是为了举例.
2.当我点击取消两次然后它显示错误IndexError:列表索引超出范围.
3.当我更新状态时,它会在数据库中更新,但不会在屏幕上实时更改.如果我再次运行,则会显示更新的数据.
Can anyone help for resolve some issue??
1. when i click on state (submenu of view) again and again then data repeats.How to avoid it.When i click on state then state list should be show and when i click on city then city list should be show.display_city() i have not written yet this for only example.
2. When i click on cancel two times then it shows error IndexError: list index out of range.
3.When i update state then it updated in database but does not change real time on screen.If i again run then shows updated data.
解决方案
请参考问题,解决方案和示例来解决您的问题.
Please refer to the problems, solutions and example to solve your problems.
每次单击查看时,都会动态添加小部件.如果您单击两次查看,列会重复两次.
Each time you clicked View, widgets are dynamically added. If you clicked View twice, the columns are repeated twice.
您必须在每次动态添加小部件之前删除它们.
You have to remove the widgets each time before adding them dynamically.
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)
索引错误
问题
每当您单击每一行数据时,它都会调用 on_press 方法.self.start_point 在类 SelectableButton 实例化时初始化.
IndexError
Problem
Whenever you clicked on each row of data, it invokes the on_press method. The self.start_point is initialized at the beginning when the class SelectableButton is instantiated.
在on_press方法中初始化self.start_point.
Initialize self.start_point in the on_press method.
def on_press(self):
self.start_point = 0
end_point = MAX_TABLE_COLS
rows = len(self.rv_data) // MAX_TABLE_COLS
for row in range(rows):
if self.index in list(range(end_point)):
break
self.start_point += MAX_TABLE_COLS
end_point += MAX_TABLE_COLS
popup = EditStatePopup(self)
popup.open()
RecycleView 未更新
问题
在update_states方法中,缺少RecycleView的数据更新.
RecycleView Not Updated
Problem
In the method update_states, RecycleView's data update is missing.
添加以下内容以更新 RecycleView 的数据.
Add the following to update RecycleView's data.
def update_states(self, obj):
# update data_items
# obj.start_point + 1 --- skip State_ID
for index in range(obj.start_point + 1, obj.start_point + MAX_TABLE_COLS):
self.rv.data_items[index] = obj.col_data[index - obj.start_point]
# 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()
示例
m_ListState.py
import kivy
kivy.require('1.10.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
import sys
#Window.borderless = True
#Window.clearcolor = (0, 0.517, 0.705, 1)
Window.size = (900, 500)
#from easygui import msgbox
MAX_TABLE_COLS = 3
path = "/home/iam/dev/SQLite/sampleDB/StateCodesNamesDB/"
#db =lite.connect(':memory:')
# con = lite.connect('fact.db')
con = lite.connect(path + 'country.db')
con.text_factory = str
cur = con.cursor()
class EditStatePopup(Popup):
start_point = NumericProperty(0)
col_data = ListProperty(["?", "?", "?"])
def __init__(self, obj, **kwargs):
super(EditStatePopup, self).__init__(**kwargs)
self.start_point = obj.start_point
self.col_data[0] = obj.rv_data[obj.start_point]["text"]
self.col_data[1] = obj.rv_data[obj.start_point + 1]["text"]
self.col_data[2] = obj.rv_data[obj.start_point + 2]["text"]
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 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
def on_press(self):
self.start_point = 0
end_point = MAX_TABLE_COLS
rows = len(self.rv_data) // MAX_TABLE_COLS
for row in range(rows):
if self.index in list(range(end_point)):
break
self.start_point += MAX_TABLE_COLS
end_point += MAX_TABLE_COLS
popup = EditStatePopup(self)
popup.open()
class RV(BoxLayout):
data_items = ListProperty([])
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.get_states()
def get_states(self):
cur.execute("SELECT * FROM m_state order by State_ID asc")
rows = cur.fetchall()
# create data_items
for row in rows:
for col in row:
self.data_items.append(col)
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
for index in range(obj.start_point + 1, obj.start_point + MAX_TABLE_COLS):
self.rv.data_items[index] = obj.col_data[index - obj.start_point]
# 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 FactApp(App):
title = "Test"
def build(self):
self.root = Builder.load_file('m_ListState.kv')
return MainMenu()
if __name__ == '__main__':
FactApp().run()
m_ListState.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: stateId
text: root.col_data[0]
Label:
text: "Name"
TextInput:
id: stateName
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(stateName.text, stateCode.text)
app.root.update_states(root)
root.dismiss()
<SelectableButton>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (0, 0, 0, 1)
Rectangle:
pos: self.pos
size: self.size
<RV>:
BoxLayout:
orientation: "vertical"
GridLayout:
size_hint: 1, None
size_hint_y: None
height: 25
cols: 3
Label:
text: "Id"
Label:
text: "Name"
Label:
text: "Code"
BoxLayout:
RecycleView:
viewclass: 'SelectableButton'
data: [{'text': str(x)} for x in root.data_items]
SelectableRecycleGridLayout:
cols: 3
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
<DropdownButton@Button>:
border: (0, 16, 0, 16)
text_size: self.size
valign: "middle"
padding_x: 5
size_hint_y: None
height: '30dp'
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>:
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: 'View'
size : (60,30)
on_release: dropdown.open(self)
CustDrop:
id: dropdown
auto_width: False
width: 150
DropdownButton:
text: 'State'
size_hint_y: None
height: '32dp'
#on_release: dropdown3.open(self)
on_release: root.display_states()
DropdownButton:
text: 'City'
size_hint_y: None
height: '32dp'
#on_release: dropdown3.open(self)
on_release: root.display_city()
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
Color:
rgb: (1,1,1)
AsyncImage:
source: "clipboard.jpeg" # "gst_image/add.jpg"
#on_release: os.system("python m_State.py")
Label:
size_hint_x: 22
BoxLayout:
id: states
size_hint_y: 9
Label:
size_hint_y: 9
输出
相关文章