Tkinter and displaying iterating list - python-2.7

I have the following code:
from Tkinter import *
import itertools
l1 = [1, 'One', [[1, '1', '2'], [2, '3', '4'], [3, '5', '6']]]
l2 = [2, 'Two', [[1, 'one', 'two'], [2, 'three', 'four'], [3, 'five', 'six']]]
def session(evt,contents):
def setup_cards():
cards = [stack[2] for stack in contents]
setup = [iter(stack) for stack in cards]
return cards, setup
def end():
window.destroy()
def start():
print setup
print cards
pair = next(setup[0])
def flip():
side2cont.set(pair[2])
flipbutton.configure(command=start)
for stack in setup:
try:
for card in cards:
try:
side1cont.set(pair[1])
flipbutton.configure(command=flip)
except StopIteration:
continue
except StopIteration:
pair = next(setup[1])
window = Toplevel()
window.grab_set()
window.title("Session")
card_frame = Frame(window)
card_frame.grid(row=0, column=0, sticky=W, padx=2, pady=2)
button_frame = Frame(window)
button_frame.grid(row=1, column=0, pady=(5,0), padx=2)
side1_frame = LabelFrame(card_frame, text="Side 1")
side1_frame.grid(row=0, column=0)
side1cont = StringVar()
side2cont = StringVar()
side1 = Label(side1_frame, textvariable=side1cont)
side1.grid(row=0, column=0, sticky=W)
side2_frame = LabelFrame(card_frame, text="Side 2")
side2_frame.grid(row=1, column=0)
side2 = Label(side2_frame, textvariable=side2cont)
side2.grid(row=0, column=0, sticky=W)
flipbutton = Button(button_frame, text="Flip", command=start)
flipbutton.grid(row=0, column=2)
finishbutton = Button(button_frame, text="End", command=end)
finishbutton.grid(row=0,column=0, sticky=E)
cards = setup_cards()[0]
setup = setup_cards()[1]
w = Tk()
wbutton = Button(text='toplevel')
wbutton.bind('<Button-1>', lambda evt, args=(l1, l2): session(evt, args))
wbutton.pack()
w.mainloop()
It is piece of my project, I remade it just to the basics so it's easy to understand. In my project, function session accepts files, these are now emulated as lists l1 and l2.
The point where I am struggling is when I hit StopIteration exception. I would like my script to do the following:
1. When iteration reaches end, switch to another iterator (next item in setup list, in this case l2 iterator).
2. If no other iterators are present in setup, reset the iterator ("start over from the beginning").
The code above is the best I was able to come up with, that's why I'm turning to you folks. Thank you (also I'm newbie so I'm still struggling with basics of Python/programming in general).

StopIteration is caught by for and not propagated further. You may want to use for…else.
But your methods of iteration are weird, why not just use regular for loops?

Related

Create a dictionary in a loop

I have 2 lists that I want to convert them into a dict with key and values. I managed to do so but there are too many steps so I would like to know if there's a simpler way of achieving this. Basically I would like to create the dict directly in the loop without having the extra steps bellow. I just started working with python and I don't quite understand all the datatypes that it provides.
The jName form can be modified if needed.
jName=["Nose", "Neck", "RShoulder", "RElbow", "RWrist", "LShoulder", "LElbow", "LWrist", "RHip",
"RKnee","RAnkle","LHip", "LKnee", "LAnkle", "REye", "LEye", "REar", "LEar"]
def get_joints(subset, candidate):
joints_per_skeleton = [[] for i in range(len(subset))]
# for each detected skeleton
for n in range(len(subset)):
# for each joint
for i in range(18):
cidx = subset[n][i]
if cidx != -1:
y = candidate[cidx.astype(int), 0]
x = candidate[cidx.astype(int), 1]
joints_per_skeleton[n].append((y, x))
else:
joints_per_skeleton[n].append(None)
return joints_per_skeleton
joints = get_joints(subset,candidate)
print joints
Here is the output of the joints list of list
[[None, (48.0, 52.0), (72.0, 50.0), None, None, (24.0, 55.0), (5.0, 105.0), None, (63.0, 159.0), (57.0, 221.0), (55.0, 281.0), (28.0, 154.0), (23.0, 219.0), (23.0, 285.0), None, (25.0, 17.0), (55.0, 18.0), (30.0, 21.0)]]
Here I defined a function to create the dictionary from the 2 lists
def create_dict(keys, values):
return dict(zip(keys, values))
my_dict = create_dict(jointsName, joints[0])
Here is the result:
{'LAnkle': (23.0, 285.0),
'LEar': (30.0, 21.0),
'LElbow': (5.0, 105.0),
'LEye': (25.0, 17.0),
'LHip': (28.0, 154.0),
'LKnee': (23.0, 219.0),
'LShoulder': (24.0, 55.0),
'LWrist': None,
'Neck': (48.0, 52.0),
'Nose': None,
'RAnkle': (55.0, 281.0),
'REar': (55.0, 18.0),
'RElbow': None,
'REye': None,
'RHip': (63.0, 159.0),
'RKnee': (57.0, 221.0),
'RShoulder': (72.0, 50.0),
'RWrist': None}
I think defaultdict could help you. I made my own example to show that you could predefine the keys and then go through a double for loop and have the values of the dict be lists of potentially different sizes. Please let me know if this answers your question:
from collections import defaultdict
import random
joint_names = ['hip','knee','wrist']
num_skeletons = 10
d = defaultdict(list)
for skeleton in range(num_skeletons):
for joint_name in joint_names:
r1 = random.randint(0,10)
r2 = random.randint(0,10)
if r1 > 4:
d[joint_name].append(r1*r2)
print d
Output:
defaultdict(<type 'list'>, {'hip': [0, 5, 30, 36, 56], 'knee': [35, 50, 10], 'wrist': [27, 5, 15, 64, 30]})
As a note I found it very difficult to read through your code since there were some variables that were defined before the snippet you posted.

Variable value changes from string to instance

I am trying to put together my first little program, but I keep having some difficulties. I am using data from an SQLite DB, but I changed the code below a bit so it's usable without the DB itself. The list_base and List_sold_at_base functions usually would pull data from a DB (base and commodities info from the Freelancer game, so I can list what commodities are sold on what base).
What the program should do is build up a list of all bases when the 'bases' button is pressed and put this in the Combobox.
When selecting an option from the Combobox this selection should be stored in the variable v, and update when another base is selected. This works. the variable v is a str type so far.
The Goods sold at base button calls a function that takes v and uses it to check in de DB what goods are sold at this base, and prints this out in a list.
However, now the variable v isn't a string type anymore (which it should be for the function to work properly), but an instance. Somehow this gets changed but I can't figure out where and why. I put in a couple of print statements to see how and where, but they don't really show it all that well.
from Tkinter import *
import csv, sqlite3, sys
from ttk import Combobox
root = Tk()
v = StringVar()
def on_field_change(index, value, op):
print "combobox updated to ", boxBases.get()
v = boxBases.get()
print 'v is', v
print type(v)
def List_bases():
dropdownBases = []
for i in ['base1', 'base2', 'base3', 'base4',]:
dropdownBases.append(i)
return dropdownBases
def List_sold_at_base(selbase):
goodsSoldAtBase = []
sb=selbase
print "selbase value (v) is", selbase
print "selbase type is ", type(selbase)
dataFromDB = [['base1', 'Cobalt 275', 'Copper 180'],['base2', 'High Temp Alloy 280', 'Mining Machinery 130'], ['base3', 'H-Fuel 240', 'Oxygen 6', 'Water 18'], ['base4', 'Hydrocarbons 40', 'Polymers 107']]
for i in dataFromDB:
if i[0] == sb:
goodsSoldAtBase.append(i)
print "goods sold at base list: ", goodsSoldAtBase
print " "
print v
print type(v)
def base():
dropdownBases = List_bases()
boxBases.config(values=dropdownBases)
print "bases!"
def goods():
List_sold_at_base(v)
print '=========='
dropdownBases = []
v.trace('w',on_field_change)
boxBases = Combobox(root, textvar=v, values=dropdownBases)
boxBases.grid(row=4, column=3, sticky='w', padx=5, pady=5)
baseButton=Button(root, text="bases", command=base)
baseButton.grid(row=3, column=0, sticky='w', padx=5, pady=5)
goodsButton = Button(root, text="Goods sold at base", command=goods)
goodsButton.grid(row=3, column=2, sticky='w', padx=5, pady=5)
root.mainloop()
Thanks for the input. I got it to work by trying around with the .get() a bit more and taking out 1 function that basically just called another function. I cut out the middle man (goods() ).
from Tkinter import *
import csv, sqlite3, sys
from ttk import Combobox
root = Tk()
v = StringVar()
def on_field_change(index, value, op):
v = boxBases.get()
print 'v is', v
def List_bases():
dropdownBases = []
for i in ['base1', 'base2', 'base3', 'base4',]:
dropdownBases.append(i)
return dropdownBases
def List_sold_at_base():
goodsSoldAtBase = []
sb=v.get()
dataFromDB = [['base1', 'Cobalt 275', 'Copper 180'],['base2', 'High Temp Alloy 280', 'Mining Machinery 130'], ['base3', 'H-Fuel 240', 'Oxygen 6', 'Water 18'], ['base4', 'Hydrocarbons 40', 'Polymers 107']]
for i in dataFromDB:
if i[0] == sb:
goodsSoldAtBase.append(i)
print "goods sold at base list: ", goodsSoldAtBase
def base():
dropdownBases = List_bases()
boxBases.config(values=dropdownBases)
print "bases!"
dropdownBases = []
v.trace('w',on_field_change)
boxBases = Combobox(root, textvar=v, values=dropdownBases)
boxBases.grid(row=4, column=3, sticky='w', padx=5, pady=5)
baseButton=Button(root, text="bases", command=base)
baseButton.grid(row=3, column=0, sticky='w', padx=5, pady=5)
goodsButton = Button(root, text="Goods sold at base", command=List_sold_at_base)
goodsButton.grid(row=3, column=2, sticky='w', padx=5, pady=5)
root.mainloop()

Generate a bunch of tkinter checkbuttons and read the status of all those radio buttons at once

I have a tkinter class which reads some data into a couple of lists. From this now i have created a dictionary for creating checkbuttons.
I'm trying to create those checkbuttons in a new window() with a button to submit and read the stutus of those. I want this data to process.
def get_data(self):
self.flags = ["one","two","three", "four"]
self.tests = ["Jack","Queen","King","Ace"]
self.value = [11,12,13,1]
self.dict1 = {k:v for k,v in enumerate(self.flags,1)}
def get_status(self):
self.selectWindow = Toplevel(root)
self.selectWindow.title("Select Test Cases")
Submit_btn = Button(selectWindow, text="Submit", command=read_status )
for testcase in self.dict1:
self.dict1[testcase] = Variable()
l = Checkbutton(self.selectWindow,text=self.dict1[testcase], variable=self.dict1[testcase])
l.pack()
def read_status(self):
pass
From here I'm not able go ahead and read the status of checkbuttons and get those are checked. I need this data for further processing on tests(not actual lists given here I have few more). How to solve? Please let me know.
Checkbutton has a built in command function that can solve this problem. Every time you press a button that function is called, and you can print out the values of the buttons (0,1)
def get_data(self):
self.flags = ["one","two","three", "four"]
self.tests = ["Jack","Queen","King","Ace"]
self.value = [11,12,13,1]
self.dict1 = {k:v for k,v in enumerate(self.flags,1)}
def get_status(self):
self.selectWindow = Toplevel(self)
self.selectWindow.title("Select Test Cases")
self.get_data()
Submit_btn = Button(self.selectWindow, text="Submit", command=read_status ) # This button should be packed
Submit_btn.pack()
for testcase in self.dict1:
self.dict1[testcase] = Variable()
l = Checkbutton(self.selectWindow,text=self.dict1[testcase], variable=self.dict1[testcase], command=self.read_status) # Note the command
l.pack()
self.selectWindow.mainloop()
# Here comes the interesting part
def read_status(self):
for i,j in self.dict1.iteritems():
print j.get()
You forgot to use self and pack method:
Submit_btn = Button(self.selectWindow, text="Submit", command=self.read_status )
Submit_btn.pack()
Checkbutton's states are (0, 1) so use IntVar() to inspect the state:
...
self.dict1[testcase] = IntVar()
...
Then use IntVar get method:
def read_status(self):
for v in self.dict1:
print self.dict1[v].get()

Trouble resetting / backtracking with variables

I've written a Cryptoquote Generator in Python using wxPython. I don't really have any problems with wxPython itself, but rather with resetting my variables. My program works this way: I have a button that generates an encrypted quote. Then, the user has a decode button they press to change one letter at a time. There is a button to reset the whole quote and a button to reset changes one step back at a time.
I have a base_copy variable to store the original encrypted quote. It is an empty list that is populated with the individual characters of the encrypted quote one at a time when on_generate_quote is called. It remains unchanged throughout the loop -- so that I may call on it with on_clear_all or on_clear_last to reset my encrypted quote. The problem is, if I use my decode_button to decode a letter, then use my clear_all_button, then decode_button again, my clear_all_button calls on a base_copy that has now been somehow tainted with changed letters that should only be in my split_cryptoquote copy. Why is this, since I never make an implicit call to alter base_copy? (I do, however, make a call in on_clear_all to set split_cryptoquote to base_copy, but this shouldn't change base_copy.)
#/------------------ wxPython GUI -----------------\
class MainWindow(wx.Frame):
quote = []
quote.append(quote_fetch(quotes))
split_cryptoquote = []
base_copy = []
split_buffer = []
buffer_origin = None
buffer_replace = None
quote_altered = False #Becomes true after first decoding change.
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title="Cryptogrammar", size=(1000, 200))
self.CreateStatusBar()
self.txt = wx.StaticText(self, -1, "".join(MainWindow.split_cryptoquote), (20,30), (40,40))
self.txt.SetForegroundColour("WHITE")
#Menu
filemenu = wx.Menu()
menu_about = filemenu.Append(wx.ID_ABOUT, "&About", " Information about this program")
menu_how = filemenu.Append(HOW_TO, "&How to Play", " How to play Cryptogrammar")
menu_exit = filemenu.Append(wx.ID_EXIT,"E&xit", " Close Cryptogrammar")
#menuGenerate = filemenu.Append(wx.ID_NONE, "&Generate New", "Generate a new cryptogram")
#menu_bar
menu_bar = wx.MenuBar()
menu_bar.Append(filemenu, "&File")
self.SetMenuBar(menu_bar)
#Buttons
generate_button = wx.Button(self, -1, "&Generate Cryptogram")
decode_button = wx.Button(self, -1, "&Decode Letter")
clear_all_button = wx.Button(self, -1, "&Clear All Changes")
clear_last_button = wx.Button(self, -1, "Clear &Last Change")
answer_button = wx.Button(self, -1, "Show &Answer")
but_list = [generate_button, decode_button, clear_all_button, clear_last_button, answer_button]
#Sizers
self.sizer2 = wx.BoxSizer(wx.HORIZONTAL)
for i in range(0, 5):
self.sizer2.Add(but_list[i], 1, wx.EXPAND)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.txt, 1, wx.EXPAND)
self.sizer.Add(self.sizer2, 0, wx.EXPAND)
#Events
self.Bind(wx.EVT_MENU, self.on_about, menu_about)
self.Bind(wx.EVT_MENU, self.on_exit, menu_exit)
self.Bind(wx.EVT_MENU, self.on_how, menu_how)
self.Bind(wx.EVT_BUTTON, self.on_generate_quote, generate_button)
self.Bind(wx.EVT_BUTTON, self.on_decode, decode_button)
self.Bind(wx.EVT_BUTTON, self.on_answer, answer_button)
self.Bind(wx.EVT_BUTTON, self.on_clear_all, clear_all_button)
self.Bind(wx.EVT_BUTTON, self.on_clear_last, clear_last_button)
self.SetSizer(self.sizer)
self.SetAutoLayout(1)
self.sizer.Fit(self)
self.SetTitle("Cryptogrammar")
self.Centre()
def on_about(self, e):
dialogue = wx.MessageDialog(self, "A program for generating random cryptograms.\n\n\n\nCopyright 2014 Joshua Simmons\nVersion 0.1.0", "About Cryptogrammar", wx.OK)
dialogue.ShowModal()
dialogue.Destroy()
def on_exit(self, e):
self.Close(True)
def on_how(self, e):
dialogue = wx.MessageDialog(self, "HOW TO PLAY:\n\n\n--\tPress the 'Generate Cryptogram' to spawn a cryptogram.\n\n--\tUse the 'Decode Letter' to replace an encrypted letter with a letter of your choice. 'Decoded' letters will be lowercase to distinguish them.\n\n--\tUse the 'Clear Changes' button to reset the puzzle.\n\n--\t'Show Answer' solves the puzzle!", "How to play Cryptogrammar", wx.OK)
dialogue.ShowModal()
dialogue.Destroy()
def on_decode(self, e):
dialogue = wx.TextEntryDialog(self, "Which letter do you wish to change? Use format: 'a=e'", "Decode Letter", "")
dialogue.ShowModal()
decode = dialogue.GetValue()
#Text entry filter
match = re.search(r'\w+=\w+|^\d*$', decode)
if not match:
err = wx.MessageDialog(self, "That is not a correct entry format.", "Entry Error", style=wx.ICON_HAND)
err.ShowModal()
#Letter replacement
else:
if not MainWindow.quote_altered:
MainWindow.buffer_origin = decode[0].upper()
MainWindow.buffer_replace = decode[2].upper()
else:
for n in range(0, len(MainWindow.split_buffer)):
if MainWindow.split_buffer[n] == MainWindow.buffer_origin:
MainWindow.split_buffer[n] = MainWindow.buffer_replace.lower()
MainWindow.buffer_origin = decode[0].upper()
MainWindow.buffer_replace = decode[2].upper()
origin = decode[0].upper()
replace = decode[2].upper() #For resetting changes one at a time.
for n in range(0, len(MainWindow.split_cryptoquote)):
if MainWindow.split_cryptoquote[n] == origin:
MainWindow.split_cryptoquote[n] = replace.lower()
MainWindow.quote_altered = True
origin = None
replace = None
self.txt.SetLabel("".join(MainWindow.split_cryptoquote))
self.sizer.Layout()
dialogue.Destroy()
def on_generate_quote(self, e):
MainWindow.quote.pop()
MainWindow.quote.append(quote_fetch(quotes))
cryptoquote = generate_cryptogram(MainWindow.quote[0], encrypt_key(shuffle_alphabet()))
MainWindow.split_cryptoquote = []
MainWindow.base_copy = []
for i in cryptoquote:
MainWindow.split_cryptoquote.append(i)
MainWindow.base_copy.append(i)
MainWindow.split_buffer.append(i)
self.txt.SetLabel("".join(MainWindow.split_cryptoquote))
self.txt.SetForegroundColour("BLACK")
self.sizer.Layout()
def on_answer(self, e):
if len(MainWindow.base_copy) == 0:
err = wx.MessageDialog(self, "You haven't generated a puzzle yet, doofus!", "Encryption Error", style=wx.ICON_HAND)
err.ShowModal()
else:
self.txt.SetLabel(MainWindow.quote[0])
self.txt.SetForegroundColour("BLUE")
self.sizer.Layout()
def on_clear_last(self, e):
if MainWindow.quote_altered:
self.txt.SetLabel("".join(MainWindow.split_buffer))
else:
self.txt.SetLabel("".join(MainWindow.base_copy))
self.txt.SetForegroundColour("BLACK")
self.sizer.Layout()
def on_clear_all(self, e):
print MainWindow.base_copy
MainWindow.split_cryptoquote = MainWindow.base_copy
MainWindow.split_buffer = MainWindow.base_copy
MainWindow.quote_altered = False
self.txt.SetLabel("".join(MainWindow.base_copy))
self.txt.SetForegroundColour("BLACK")
self.sizer.Layout()
app = wx.App(False)
frame = MainWindow(None, "Cryptogrammar")
frame.Show()
app.MainLoop()
(I do, however, make a call in on_clear_all to set split_cryptoquote
to base_copy, but this shouldn't change base_copy.)
You've spotted your own problem:
MainWindow.split_cryptoquote = MainWindow.base_copy binds MainWindow.split_cryptoquote to the same object as MainWindow.base_copy, so when you modify one, you modify the other.
If you change the line to
MainWindow.split_cryptoquote = MainWindow.base_copy[:]
You will force python to create a new object (a copy of MainWindow.base_copy) , and this problem should not occur.
Edit: The line below:
MainWindow.split_buffer = MainWindow.base_copy also needs the same treatment, I think.
See this example:
>>> lista = [1,2]
>>> listb = lista
>>> listb.append(3)
>>> lista
[1, 2, 3]
>>> listb
[1, 2, 3]
>>> listc = lista[:]
>>> listc.append(4)
>>> listc
[1, 2, 3, 4]
>>> lista
[1, 2, 3]

Reassigning a value to a list with a function

How would I reassign a value in a list every time i called it. For example in:
def randomfunction():
var1 = random.randint(1,10)
return var1
list1 = [None,None,None,None]
list1[1] = randomfunction()
How do I make the list[1] value equal to the randomfunction() rather than just one value returned by the function.
i.e everytime I call list[1] there is a new value from randomfunction().
To reassign the value, you just need to keep calling the function and you'll most likely receive a different number every time you call it.
For example:
import random
def randomfunction():
var1 = random.randint(1,10)
return var1
list1 = [None,None,None,None]
list1[1] = randomfunction()
print(list1)
list1[1] = randomfunction()
print(list1)
list1[1] = randomfunction()
print(list1)
I received an output of:
>>>
[None, 1, None, None]
[None, 6, None, None]
[None, 9, None, None]
So each time I called the function and assigned it to list1[1], I got a different value.
What do you think of this solution:
import random
class specli(list):
def __init__(self):
self.append(random.randint(1,10))
def __getitem__(self,i):
if i==0:
return random.randint(1,10)
elif i<len(self):
return super(specli,self).__getitem__(i)
else:
[][i]
L = specli()
print L
L.append('B')
print L
L.append('C')
print L
print '-------------'
print 'L[0] :',L[0]
print 'L[1] :',L[1]
print 'L[2] :',L[2]
print 'L[3] :',L[3]
result
[2]
[2, 'B']
[2, 'B', 'C']
-------------
L[0] : 2
L[1] : B
L[2] : C
L[3] :
Traceback (most recent call last):
File "I:\potoh\ProvPy\quichotte.py", line 24, in <module>
print 'L[3] :',L[3]
File "I:\potoh\ProvPy\quichotte.py", line 12, in __getitem__
[][i]
IndexError: list index out of range