Kodi Community Forum
Help with List Control - Printable Version

+- Kodi Community Forum (https://forum.kodi.tv)
+-- Forum: Development (https://forum.kodi.tv/forumdisplay.php?fid=32)
+--- Forum: Add-ons (https://forum.kodi.tv/forumdisplay.php?fid=26)
+--- Thread: Help with List Control (/showthread.php?tid=17320)

Pages: 1 2


- Livin - 2006-01-11

help!

when i run the code below, using a previously populated list called statlist, the error occurs on the same exact line, 173, no matter if i comment out that line or not. it seems like python (a language i'm starting to hate - only 3 days into it!Wink "sees" the entire column of constant assignments as a single line. only did the error msg change when i commented out the assignment it was erroring on.

i know this is not easy to understand so let me illistrate

line #s ... python code

173 c_stat = stat[itempos] <--- error on this line even if i physically move the statement to say line 175!
174 c_dimlev = dimlev[itempos] <--- error on this line only if i comment out the c_stat code completely.
175 c_devname = devname[itempos]


any ideas?


code that creates the initial list...
Quote: self.statlist.additem(xbmcgui.listitem(label = item[3], label2 = itemstat, thumbnailimage= iwd+imgdim))
itemtype.append(item[0])
stat.append(item[1])
dimlev.append(item[2])
devname.append(item[3])
loc.append(item[4])
hcode.append(item[5])
lastch.append(item[6])
devtype.append(item[7])
candim.append(item[8])
vals.append(item[9])

code to recall the list, within same class def; throws error...
Quote: def oncontrol_action(self, control):
if control == self.statlist:
itempos = self.statlist.getselectedposition()
c_itemtype = itemtype[itempos]
c_stat = stat[itempos]
c_dimlev = dimlev[itempos]
c_devname = devname[itempos]
c_loc = loc[itempos]
c_hcode = hcode[itempos]
c_lastch = lastch[itempos]
c_devtype = devtype[itempos]
c_candim = candim[itempos]
c_vals = vals[itempos]

error log...
Quote:traceback (most recent call last):
file "q:\scripts\homecontrol\homecontrol.py", line 162, in oncontrol
self.oncontrol_action(control)
file "q:\scripts\homecontrol\homecontrol.py", line 173, in oncontrol_action
c_stat = stat[itempos]
indexerror: list index out of range
traceback (most recent call last):
file "q:\scripts\homecontrol\homecontrol.py", line 162, in oncontrol
self.oncontrol_action(control)
file "q:\scripts\homecontrol\homecontrol.py", line 174, in oncontrol_action
c_dimlev = dimlev[itempos]
indexerror: list index out of range



- BigBellyBilly - 2006-01-11

where is item[] created ?

i'd be inclined to hold all those details together as a record in a list rather than have individual vars

ie.
[
[data1,data2,data3 ...],
[data1,data2,data3 ...],
[data1,data2,data3 ...],
[data1,data2,data3 ...]
]

i think you have to show more of the code to solve it. pm me it if you wish ?


- Livin - 2006-01-11

i'm just following an example in another script so forgive me if i'm doing it incorrectly.

here's the entire script...

homecontrol script zip file

i should note two things...

a) i have several attributes that i want associated with each item in the list, but i only want to display a few of those attributes on the screen.

b) the items in the list are different types, so some will have more attributes, some will have less, but they will all be using the same attribute names, thus the some fields may just be empty for some items.

thanks for the help!






- BigBellyBilly - 2006-01-11

could you post a copy of the webfile that it expects to download ?


- Livin - 2006-01-11

updated the zip... sorry about that!


- Asteron - 2006-01-11

maintaining many parrallel arrays is a real pain and is not good for your health, like if you have to add a property later. i recommend making a struct like object.

Quote:

class hcitem:
def --init--(self,values)
self.itemtype = values[0]
self.stat = values[1]
self.dimlev = values[2]
self.devname = values[3]
self.loc = values[4]
self.hcode = values[5]
self.lastch = values[6]
self.devtype = values[7]
self.candim = values[8]
self.vals = values[9]
....
self.statlist.additem(xbmcgui.listitem(label = item[3], label2 = itemstat, thumbnailimage= iwd+imgdim))
self.hcitems = []
self.hcitems.append(hcitem(item))

....
def oncontrol_action(self, control):
if control == self.statlist:
itempos = self.statlist.getselectedposition()
item = self.hcitems[itempos]
print item.devtype



- Livin - 2006-01-11

asteron,

so if i understand this...

you define the object

additem is what is displayed on screen

self.hcitems = [] <--- creates object
self.hcitems.append(hcitem(item)) <--- adds attributes to the object

but what is hcitem(item)... is that supposed to be how i have it today, where it is actually the current item... item[#]?

thanks for the help!


- BigBellyBilly - 2006-01-11

ok, your problem is exactly as the error msg indicates - index out of bounds when looking into the lists.

this is because you dont append onto every list when the device field is an 'event' like you do when device is a 'device'.

this means the number of elements for each list is out of step.

you need to always add an element to every list for each device type that you add to controllist.

storing data is sometimes down to personnal preference,many ways to do same job.
i quite favour using dictionaries. these have key : value approach, which provides you with a simple lookup system.
value can be anything, even a class of values as suggested.

ie.
# create and init
mydict = {
'device_name_1' : [attr1, attr2, attr3],
'device_name_2' : [attr1, attr2, attr3],
'device_name_3' : [attr1, attr2, attr3]
}

or init with:
mydict = {}
and add to as and when with:
mydict['device_name_1'] = [attr1, attr2, attr3]

# look using the key
theattribs = mydict['device_name_2']






- BigBellyBilly - 2006-01-11

in asterons example

self.hcitems = [] # init an empty list

# appends an instance of hcitem class, populated with item data, to the list
self.hcitems.append(hcitem(item))

that is fine, but i'd still argue its still a record wrapped in a class, that needs amending just the same as if the record would need to be if a new param is added..

the list/record storage structure i was alluding too initially would look like this.

each list element would refer directly to the index row of the controllist. the split list (item) would be the record

mydatalist = []
...
mydatalist.append(item)

this of course results in records of different lengths,2 fields for an event and 8 for a device.
if you put the fields at the front that are always there for both type, then in the oncontrol, you could wrap it in a 'try .. except' which would trap any short records.

i hope that makes sense.
tbh, doing it your own way throu trial n error is the best way to learn, regardless of whether your chosen technique is the most effecient or not.
i'm constantly finding parts of mytv thats terrible coding and then changing it to the 'new & better' way of how things should be done.
the important thing is that we've found your error.
bbb






- Livin - 2006-01-11

my thought, and please correct me if needed, is that creating multiple dictionaries, one for each 'type' (event, device, etc) may be the best solution since the attributes for each may be different. yes/no?

a few qs on dictonaries...

1) can i name the attributes? so i do not need to know the attribute position when trying to use or change the information?

2) how would i go about changing an single attribute?

3) how would i display in a list only the attributes i want? i'm not yet sure if i will create separate colums for each 'type' or a single scrolling list.


in the future, i could see that there may be many more 'types' that will/can be added.

you guys rock, thanks so much for the help!

i may just create a useful script for the community! Wink






- BigBellyBilly - 2006-01-11

dicts, they're a storage using keys as the lookup, so they have no position. it also means they cant be sorted.

you can name the 'key', it also doesnt have to be a string.

mydict = { key : name, key2 : name ...}

you get a list of all keys and values. you cant lookup by value.


so, each attrib could be a dict key.

you could also have a dict per device type

eventsdict = { attr1 : data, attr2 : data ...}

devicedict = { attr1 : data, attr2 : data ...}

datadict = {'events' : eventsdict , 'device' : devicedict}

if you try to reference a key that doesnt exist, it throws keyvalue a exception, so its easily trapped:

eg:
try:
 x = eventsdict['badkeyname']
except:
 pass
else:
# do some processing

python faq

you could have a couple of buttons on the left, 'events' and 'device status' which would display the appropiate data on selection ?






- Livin - 2006-01-11

bbb,
i have read lots of documentation on python in the past 3 days, probably about 10 hours worth. compared to what i'm used to, it is pretty sparse on examples for more complex issues and "best practices" for thing like i'm trying.


so are you saying i can have a dict of dict's?

currently i have a separate dict for each item type (devices, events); my device dict looks like this...

dicthsdevice[item[1]] = [item[2], item[3], item[4], item[5], item[6], item[7], item[8], item[9], item[10]]

it is better to have a dict for each item itself and then do a dict of dict's?

i'd like to easily reference each item by name and then grab each attribute easily... even if not by name but maybe by attribute order?


- BigBellyBilly - 2006-01-11

yes, you can store a dict as the value in a {key : value} pair. cool isnt it.
that way your always addressing using a name as the key and you dont care where its stored.


- Livin - 2006-01-11

so i'm thinking this is a good way...

dict_hsevents = {event1: attribs, event2: attribs ...}

dict_hsdevices = {device1: attribs, device2: attribs ...}

dict_device1 = {'name': data , 'location': data, 'dimlevel': data ...}


... each item is its own dict. this allows me to name each keys and use key names when extracting/changing the specific data in that key.

my thought is to dynamically create the dict names for each event and device... can i do this?

example:

dynamically build the dict name using the device/event name (is this possible? - tips on how is appreciated!Wink

device name = 'kitchen ceiling lights'

convert spaces to +
name = 'kitchen+ceiling+lights'

so dict for that specific device = dict_kitchen+ceiling+lights

i could then parse the dict_hsdevices, and grab all the device names by doing some text "cleanup".

this is my initial thought...
please shoot holes in it, give other options, etc!

i really want to only do this one time and make it best for expanding the script to many other systems/software/applications for home automation.

thanks!






- BigBellyBilly - 2006-01-12

yep, you've got it now.

to init an empty dict:

event1= {}

then to add to it, later in the code when you need to, simply assign a key and value:

event1[attrname1] = 'some data'
event1[attrname2] = 'some data'
event1[attrname3] = 'some data'

event1keyname = 'event type 1'

adding all those to the events sdict
events = {event1keyname : event1, event2keyname : event2}

you dont need to convert string spaces for the key name. it can be any object type too.

it doesnt matter that the dict is empty or that 'keyname' doesnt exist in it, it will automatically add it.

using dicts does allow you reference eveything by name, instead of a fixed index position.

that link i posted had a really good section on dicts, with an example of each operation, well worth a glance.

hope that helps