What's the difference between these two functions in Tkinter? - python-2.7

Why are these two functions different?
def other_entry1(self, selection, row, el, var):
if selection == "Other":
var = StringVar()
el = Entry(self.frame1, textvariable=var)
el.grid(row=row, column=6)
#Calling it as part of an optionMenu
self.e33 = OptionMenu(self.frame1, self.ea_tf, *fixtures, command= lambda selection:self.other_entry1(selection,15, self.e33, self.ea_tf))
The other one:
def other_entry2(self, selection):
if selection == "Other":
self.ea_tf = StringVar()
self.e33 = Entry(self.frame1, textvariable=self.ea_tf)
self.e33.grid(row=15, column=6)
#Calling it in an optionMenu
self.e33 = OptionMenu(self.frame1, self.ea_tf, *fixtures, command=self.other_entry2)
I would like to be able to call the first function several times and just tell it what entry box to create instead of making several separate functions.
Edit: Isn't the second function just skipping the step of substituting in the arguments?

self.s33 is reference to OptionMenu
Second function overwrite self.e33 by reference to Entry and you can't use self.e33 to get access to OptionMenu.
First function copy reference from self.s33 to el then overwrites el by reference to Entry but you can still use self.s33 to get access to OptionMenu
See simple example using "Visual Execution" on PythonTutor.com:
Use link to open page with example, click "Visual Execution" and then you can use "Forward" button to see step by step how example works
function 1
function 2
You can use first function to create several Entry but you don't need to send self.e33 and self.ea_tf because function will not use it.
You get the same result as
def other_entry1(self, selection, row):
if selection == "Other":
var = StringVar()
Entry(self.frame1, textvariable=var).grid(row=row, column=6)
#Calling it as part of an optionMenu
self.e33 = OptionMenu(self.frame1, self.ea_tf, *fixtures, command=lambda selection:self.other_entry1(selection,15))
problem is with access to Entry or StringVar() to get value from Entry
self.all_vars = {} # dictionary
def other_entry1(self, selection, row):
if selection == "Other":
self.all_vars[row] = StringVar()
Entry(self.frame1, textvariable=self.all_vars[row]).grid(row=row, column=6)
#Calling it as part of an optionMenu
self.e33 = OptionMenu(self.frame1, self.ea_tf, *fixtures, command=lambda selection:self.other_entry1(selection,15))
# another place
row = 15
print "row:", row
print "value in Entry:", self.all_vars[row].get()
EDIT: working example
#!/usr/bin/env python
from Tkinter import *
class App():
def __init__(self, master):
self.master = master
self.all_entries = {} # empty dictionary
self.all_entries_vars = {} # empty dictionary
self.all_optionmenus = {} # empty dictionary
self.all_optionmenus_vars = {} # empty dictionary
fixtures = ["One", "Two", "Tree", "Other"]
# create 5 options menu
for i in range(5):
self.all_optionmenus_vars[i] = StringVar()
self.all_optionmenus_vars[i].set("One")
self.all_optionmenus[i] = OptionMenu(self.master, self.all_optionmenus_vars[i], *fixtures, command=lambda selection, col=i:self.addEntry(selection, col))
self.all_optionmenus[i].grid(row=1, column=i)
Button(master, text="Print OptionMenus Vars", command=self.printOptionMenus).grid(row=2, column=0, columnspan=5)
Button(master, text="Print Entries Vars", command=self.printEntries).grid(row=3, column=0, columnspan=5)
def run(self):
self.master.mainloop()
def addEntry(self, selection, col):
if selection == "Other":
# if Entry was created before
if col in self.all_entries:
# show existing Entry
self.all_entries[col].grid(row=0, column=col)
else:
# create new Entry
self.all_entries_vars[col] = StringVar()
self.all_entries[col] = Entry(self.master, textvariable=self.all_entries_vars[col])
self.all_entries[col].grid(row=0, column=col)
# if Entry was created before
elif col in self.all_entries:
# hide Entry
self.all_entries[col].grid_forget()
def printEntries(self):
print "-"*30
for key in self.all_entries_vars:
print "Entry #%d: %s" % ( key, self.all_entries_vars[key].get() )
def printOptionMenus(self):
print "-"*30
for key in self.all_optionmenus_vars:
print "OptionMenu #%d: %s" % ( key, self.all_optionmenus_vars[key].get() )
#----------------------------------------------------------------------
if __name__ == '__main__':
App(Tk()).run()

Related

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()

How should I link specific rows to columns in a Qtablewidget

I have a Qtablewidget with 3 columns. The first column contain user names, the second and third are columns are check boxes. I would like these check boxes to be attributes for the row of users. For example If you look at the image below, User: bruno is marked(has attributes) delete and delete home. I would like to have an output like: User Bruno marked for delete, marked for delete home. To do that, I would need to link the users to both these columns which I haven't the slightest idea. How should I approach this problem. Below is the code that I already came up with. It populates the users column from a file.
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self, rows, columns):
QtGui.QWidget.__init__(self)
self.table = QtGui.QTableWidget(rows, columns, self)
self.table.setHorizontalHeaderItem(0, QtGui.QTableWidgetItem("Users"))
self.table.setHorizontalHeaderItem(1, QtGui.QTableWidgetItem("Delete User"))
self.table.setHorizontalHeaderItem(2, QtGui.QTableWidgetItem("Delete User and Home"))
self.table.verticalHeader().hide()
header = self.table.horizontalHeader()
header.setStretchLastSection(True)
rowf = 0
with open("/home/test1/data/users") as in_file:
if in_file is not None:
users = in_file.readlines()
for line in users:
users = QtGui.QTableWidgetItem()
self.table.setItem(rowf, 0, users)
users.setText(line)
rowf+=1
in_file.close()
for column in range(columns):
for row in range(rows):
if column % 3:
item = QtGui.QTableWidgetItem(column)
item.setFlags(QtCore.Qt.ItemIsUserCheckable |
QtCore.Qt.ItemIsEnabled)
item.setCheckState(QtCore.Qt.Unchecked)
self.table.setItem(row, column, item)
self.table.itemClicked.connect(self.cell_was_clicked)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.table)
self._list = []
def cell_was_clicked(self, item):
#row = self.table.currentItem().row()
#col = self.table.currentItem().column()
#print "item:", item
#print "row=", row
if item.checkState() == QtCore.Qt.Checked:
print('"%s" Checked' % item.text())
#self._list.append(item.row())
else:
#print "(", row , ",", col, ")"
print('%s' % item.text())
print (item.row(),item.column())
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window(200, 3)
window.resize(400, 400)
window.show()
sys.exit(app.exec_())
fixed it like this:
def cell_was_clicked(self, item):
if item.checkState() == QtCore.Qt.Checked:
user = self.table
delete = user.horizontalHeaderItem(item.column()).text()
print ('%s' % user.item(item.row(), 0).text())
print ('is marked for %s' % delete)
print('%s Checked' % item.text())
#self._list.append(item.row())
else:
print('%s' % item.text())
print (item.row(),item.column())

Object not iterable when assigning to a list

I am coding a 2048 game via pygame. below is the relevant section of my code:
class Data():
def __init__(self):
self.data = getnull()
self.score = 0
def updatesprites(self): # EXP
spritelist = [[],[],[],[]]
for count in range(4): # for row loop
for i in range(4): # per column loop
if self.data[count][i] != 0:
spritelist[count]+= newSprite(str(self.data[count] [i])+".png") # error occurs here
spritelist[count][i].move(15 + i*115, 15 + count*115)
showSprite(spritelist[count][i])
class newSprite(pygame.sprite.Sprite):
def __init__(self,filename):
pygame.sprite.Sprite.__init__(self)
self.images=[]
self.images.append(loadImage(filename))
self.image = pygame.Surface.copy(self.images[0])
self.currentImage = 0
self.rect=self.image.get_rect()
self.rect.topleft=(0,0)
self.mask = pygame.mask.from_surface(self.image)
self.angle = 0
def addImage(self, filename):
self.images.append(loadImage(filename))
def move(self,xpos,ypos,centre=False):
if centre:
self.rect.center = [xpos,ypos]
else:
self.rect.topleft = [xpos,ypos]
----------------Main-------------------
from functions import *
from config import *
from pygame_functions import *
import pygame
screenSize(475,475) # call screen init
gameboard = newSprite("game board.png") # createboard
showSprite(gameboard)
game = Data()
game.updatesprites()
while True:
pass
when game.updatesprites() is called, "newSprite object is not iterable" error is raised in function Data.updatesprites
+ concatenates lists and strings, and adds numbers.
What you are trying to do, is to add an element to a list.
This is done as follows:
li.append(element) # adds the element to the end of the list
Or in your case:
spritelist[count].append(newSprite(str(self.data[count][i]) + ".png"))
Another solution: You could create a new type, that lets you add elements the way you were trying to:
class UglyList(list):
def __iadd__(self, other):
self.append(other)
You'd need to change another line here:
spritelist = [UglyList() for i in range(4)]

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()

check entry inputs in tkinter using a function

I trying to create physics calculator using python tkinter but I find it quite difficult. I have done this calculator in Command line interface but I a bit different with tkinter. basically, I have 5 entry boxes and above each one of them a button. the user will insert values in three of them and should press the button on top of each unknown value to make the calculation and get the result. my main issue is how can I create a function that evaluates the inputs in my entry boxes and make the calculation then print the results inside the entry box. I made some coding but unfortunately the operation is not working due to few mistakes.
here is my coding part:
from Tkinter import *
import math
class calculator():
def is_positive_number(number): # validation function
if number <= 0:
return False
else :
return True
def value_of_time(prompt):
while True: # loop command for time
try:
valid = False
while not valid:
value = float((prompt))
if is_positive_number(value):
valid = True
return value
else :
valid = False
print ('I donot know what is happening')
except ValueError:
print("Oops, unfortunately this is a wrong input, please try again.")
#better try again... Return to the start of the loop
continue
else:
#value was successfully parsed!
#we're ready to exit the loop.
break
def input_of_box(prompt):
while True: # loop for initial velocity
try:
value = float(input(prompt))
return value
except ValueError:
print("Oops, we are you not typing a number, please try again.")
#better try again... Return to the start of the loop
continue
else:
#value was successfully parsed!
#we're ready to exit the loop.
break
# def minput(numberofinput):
if numberofinput == 1:
t = value_of_time("Enter the time that takes an object to accelerate in seconds:")
return
elif numberofinput == 2:
u = input_of_box("Enter the initial velocity in m/s:")
return
elif numberofinput == 2:
v = input_of_box("Enter the final velocity in m/s:")
return
def my_calculation(mvariables): # this function is to operate the calculation
if mvariables == 1:
a = (v-u) /(t)
mentery1 = a
return
elif mvariables == 2:
v = u + a*t
mentery2 = v
return
elif mvariables == 3:
u = a*t - v
mentery3 = t
elif mvariables == 4:
t = (v - u)/a
mentery3 = t
return
elif mvariables == 5:
s = (v**2-u**2)/2*a
mentery4 = s
else:
print ('there is an error')
cal = Tk()
cal.configure(background='sky blue')
a = StringVar()
u = StringVar()
v = StringVar()
t = StringVar()
s = StringVar()
cal.geometry('650x420+350+225')
cal.title('Main Menu')
# here we start greating buttons and entry boxes
m_label = Label(text='Calculator',fg = 'Navy', font=("Helvetica", 20,"bold italic"), bg='sky blue')
m_label.pack()
button1 = Button(cal,text='A',fg='white',bg='dark green',bd =3, width=4, command= lambda : my_calculation(1))
button1.place(x=92,y=210)
mentery1 = Entry(cal, textvariable = a ,width=10,bd =3)
mentery1.place(x=82,y=240)
button2 = Button(cal,text='U',fg='white',bg='dark green',bd =3, width=4, command= lambda : my_calculation(3))
button2.place(x=192,y=210)
mentery2 = Entry(cal, textvariable = u ,width=10,bd =3)
mentery2.place(x=182,y=240)
button3 = Button(cal,text='V',fg='white',bg='dark green',bd =3, width=4, command= lambda : my_calculation(2))
button3.place(x=292,y=210)
mentery3 = Entry(cal, textvariable = v ,width=10,bd =3)
mentery3.place(x=282,y=240)
button4 = Button(cal,text='T',fg='white',bg='dark green',bd =3, width=4,command= lambda : my_calculation(4))
button4.place(x=392,y=210)
mentery4 = Entry(cal, textvariable = t ,width=10,bd =3)
mentery4.place(x=382,y=240)
button5 = Button(cal,text='S',fg='white',bg='dark green',bd =3, width=4,command= lambda : my_calculation(5))
button5.place(x=492,y=210)
mentery5 = Entry(cal, textvariable = s , width=10,bd =3)
mentery5.place(x=482,y=240)
# end of button commands
app = calculator()
app.mainloop()
For validating the input, do the following:
def returnValidatedInput(entry):
value = entry.get() # Get the text in the 'entry' widget
evaluation = eval(value) # Evaluate 'value'
return evaluation
And for inserting the answers into the entries (it's not called printing the answers into the entries):
def insertAnswer(entry, answer):
entry.delete(0, 'end') # Be sure the entry is empty, if it is not, clear it
entry.insert(END, str(answer)) # Insert the answer into the 'entry' widget.