This is a rather simple question;
I know that you can do:
foo = 1,
self.card1 = "This is card number %s." % (foo)
But I'm trying to assign that variable given by function to the name itself:
def card(foo):
self.foo = foo
self.usrCrdImg%self.foo = Image.open(self.crdStk[randint(1, 50)])
self.usrCrdBg%self.foo = ImageTk.PhotoImage(usrCrdImg%self.foo)
self.usrCrd%self.foo = tkinter.Label(root, image=usrCrdBg%self.foo)
self.usrCrd%self.foo.image = self.usrCrdBg%self.foo
card(1)
#Should Execute like this
def card(1):
self.usrCrdImg1 = Image.open(self.crdStk[randint(1, 50)])
self.usrCrdBg1 = ImageTk.PhotoImage(usrCrdImg1)
self.usrCrd1 = tkinter.Label(root, image=usrCrdBg1)
self.usrCrd1.image = self.usrCrdBg1
Once I get the answer to this question, I'll have another question to ask.
Here's my Code
import tkinter
import winsound
from tkinter import *
from PIL import Image, ImageTk
from random import randint, randrange
class CardGame(tkinter.Frame):
def __init__(self, root):
tkinter.Frame.__init__(self, root)
#define variables for cards
self.crdImg = []
usrStk = None
cpuStk = None
#define card images
i = 1
while i < 57:
i = i + 1
self.crdImg.append('img/cards/%s.png' % (i - 1))
usrStk = self.crdImg[54]
cpuStk = self.crdImg[55]
def debug(card):
self.card = card
self.usrCrdImg%self.card = Image.open(self.crdStk[randint(1, 50)])
self.usrCrdBg%self.card = ImageTk.PhotoImage(self.usrCrdImg%self.card)
self.usrCrd%self.card = tkinter.Label(root, image=self.usrCrdBg%self.card)
self.usrCrd%self.card.image = self.usrCrdBg%i
def card(self):
###
self.usrStk1 = self.crdImg[54]
self.cpuStk1 = self.crdImg[55]
##
self.usrCrdImg1 = Image.open(self.usrStk1)
self.usrCrdBg1 = ImageTk.PhotoImage(self.usrCrdImg1)
self.usrCrd1 = tkinter.Label(root, image=self.usrCrdBg1)
self.usrCrd1.image = self.usrCrdBg1
##
self.cpuCrdImg1 = Image.open(self.cpuStk1)
self.cpuCrdBg1 = ImageTk.PhotoImage(self.cpuCrdImg1)
self.cpuCrd1 = tkinter.Label(root, image=self.cpuCrdBg1)
self.cpuCrd1.image = self.cpuCrdBg1
What you are trying to do is just about the worst way to solve your problem. Generally speaking, you shouldn't ever try to generate variable names on the fly.
The simplest solution is to use a dictionary. Something like this:
def debug(card):
self.card = card
self.usrCrd[self.card]["Img"] = ...
self.usrCrd[self.card]["Bg"] = ...
Though, a better solution is to make a "card" be an instance of a class. Then, you can store these properties as attributes of the class:
class Card(object):
def __init__(self, background, image):
self.bg = background
self.img = image
...
...
self.usrCrd = Card(...)
self.cpuCrd = Card(...)
If you Absolutely Must Create a variable, Eg. a Tkinter button, use something like:
vars = []
founditems = ['item', 'otheritem']
for i in founditems:
vars.append(i)
for n in range(len(founditems)-1):
exec('tkbutton' + vars[i] + '=' + 'Button(textvariable=tv' + vars[i] + ', command=lambda: buttoncommand(' + vars[i] + '))')
The basic format:
exec(var + '=' + varvalue)
If you only need to define the variables name, just do exec('varname = ' + varvalue)
Related
Ok so I think the best way for me to show what I'm trying to accomplish is visually, so I created a reproducible example of what I'm trying to do and strangely enough... it worked perfectly fine. Here it is
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
big_ar = ["1","2","3"]
class MyMainWindow(QWidget):
def __init__(self):
super(MyMainWindow,self).__init__()
self.setGeometry(300,300,300,300)
self.initUI()
def initUI(self):
self.lay = QVBoxLayout()
self.window_opener = WindowOpenerButton("open window",self)
self.group_box = UpdatingGroupBox(self)
self.lay.addWidget(self.window_opener)
self.lay.addWidget(self.group_box)
self.setLayout(self.lay)
def cust_update(self):
self.group_box.addButton()
self.group_box.update()
class WindowOpenerButton(QPushButton):
def __init__(self,txt,par):
super(WindowOpenerButton,self).__init__(txt,par)
self.clicked.connect(self.openWin)
def openWin(self):
self.smallWindow = MySmallWindow(psp=self.parentWidget())
self.smallWindow.show()
class MySmallWindow(QWidget):
def __init__(self,psp=None,parent=None):
super(MySmallWindow,self).__init__(parent)
self.setGeometry(100,100,100,100)
self.pseudo_parent = psp
self.populate()
def populate(self):
self.layout = QVBoxLayout()
self.line_edit = QLineEdit(self)
self.done = DoneButton("done",self,self.line_edit)
self.layout.addWidget(self.line_edit)
self.layout.addWidget(self.done)
self.setLayout(self.layout)
def closeEvent(self,event):
if self.pseudo_parent != None:
self.pseudo_parent.cust_update()
class UpdatingGroupBox(QGroupBox):
def __init__(self,par):
super(UpdatingGroupBox,self).__init__(par)
self.layout = QVBoxLayout()
self.addPreexisting()
self.setLayout(self.layout)
def addPreexisting(self):
global big_ar
for i in range(len(big_ar)):
self.layout.addWidget(QPushButton(big_ar[i],self))
def addButton(self):
global big_ar
self.layout.addWidget(QPushButton(big_ar[ len(big_ar) - 1],self))
class DoneButton(QPushButton):
def __init__(self,txt,par,src):
super(DoneButton,self).__init__(txt,par)
self.txt_source = src
self.clicked.connect(self.addToArr)
def addToArr(self):
global big_ar
big_ar.append(self.txt_source.text())
self.parentWidget().close()
print(big_ar)
def main():
app = QApplication(sys.argv)
app.setStyle("Fusion")
x = MyMainWindow()
x.show()
app.exec()
if __name__ == "__main__":
main()
Now this example outlines what I'm trying to do quite accurately and simply where it gets the string from the line edit on the smaller window and makes it into a pushbutton in the larger window's qgroupbox which is then updated immediately afterwards. The only difference between this example and my code is that instead of using a global array to add onto the qgroupbox, I use an instance variable, take a look.
def cust_update(self):
mem_f = open(self.file,"r")
raw_file_ml = mem_f.read().split("{")[1]
file_ml = raw_file_ml.split(";")
self.list.append(Member(file_ml[len(file_ml) - 2]))
mem_f.close()
self.mb_gb.addButton()
self.mb_gb.update()
This is the cust_update method for my actual program (you can disregard the first couple lines) and mb_gb is a MemberList which is this:
class MemberList(comps.MyButtonList): #list of memButtons derived from members.txt
def __init__(self,ttl,labl_ls,par,**kwargs):
super(MemberList,self).__init__(ttl,labl_ls,par,**kwargs)
self.layout = QVBoxLayout()
self.addPrexisting()
self.setLayout(self.layout)
def addPrexisting(self):
for i in range(len(self.list)):
self.layout.addWidget(QPushButton(self.list[i].fullName()))
def addButton(self):
nb = QPushButton(self.list[len(self.list) - 1])
self.layout.addWidget(nb)
the self.list represents a list of members which, as you can see in the cust_update method, is updated. The MemberList then takes the last element of the list and makes it into a button which is then added to its layout.
It's very similar to the first example's ugb but for some reason when the cust_event is called, even though it adds the button to the layout, it isn't being drawn (discovered through print debugging) and I have already tried using repaint()
EDIT:
I now see the confusion with what a Member and MyButtonList is, the reason I didn't explain them in the first place is because I didn't find it necessary as those parts of the code are working (my bad!). Here's the member class :
class Member:
def __init__(self,info_str):
info_ar = info_str.split(",")
self.first_name = info_ar[0]
self.last_name = info_ar[1]
self.idnum = info_ar[2]
self.grade_when_joined = info_ar[3]
self.gender = info_ar[4]
self.position = info_ar[5]
self.date_joined = info_ar[6][0:len(info_ar[6])]
def fullName(self):
return self.first_name.capitalize() + " " + self.last_name.capitalize()
def __str__(self):
return (self.fullName() + ": " + self.id() + " " + self.gender + " " + self.getPosition() + " " + str(self.date_joined))
def id(self):
lln = self.last_name.lower()
return lln + str(self.idnum)
def dateJoined(self):
y = int(self.date_joined[0:4])
m = int(self.date_joined[5:7])
d = int(self.date_joined[8:10])
return dt.date(y,m,d)
def sex(self):
s = "Other"
if self.gender == 'm':
s = "Male"
elif self.gender == 'f':
s = "Female"
return s
def getPosition(self):
pos = "Member"
if self.position == "o":
pos = "Officer"
elif self.position == "v":
pos = "Vice President"
elif self.position == "p":
pos = "President"
return pos
def idInt(self):
return int(self.idnum)
Prior to the closeEvent, a line is added to a txt file based on user input which follows the format
First_Name,Last_Name,ID#,Grade,Gender,Position,Date_When_Joined
when the close event happens, the cust_update method reads the file, splits it into individual members by ";" and takes the last one (the member that was just added) and makes it into a qpushbutton with its first name.
The MyButtonList class is nearly identical to the MemberList class, the only difference is in what goes on the buttons so it looks like this:
class MyButtonList(MyGroupBox):
def __init__(self,ttl,lab_ls,par,**kwargs):
super(MyButtonList,self).__init__(title=ttl,pare=par,**kwargs)
self.setUpdatesEnabled(True)
self.label_ls = lab_ls
self.list = self.parentWidget().list
self.layout = QVBoxLayout()
self.addPrexisting()
self.setLayout(self.layout)
def addPrexisting(self):
for i in range(len(self.list)):
self.layout.addWidget(QPushButton(str(i),self))
def addButton(self):
self.layout.addWidget(QPushButton("added",self))
Please let me know if there's anything I missed or I didn't communicate properly, sorry I didn't put everything here in the first place!
I've built a class for item selection with Tkinter Spinbox. I'd like to return the index of the selected item. Is that possible?
from Tkinter import *
class TestSpin():
def __init__(self, i_root, i_friendlist):
self.root = i_root
self.root.friend = Spinbox(self.root, values = i_friendlist)
self.root.friend.pack()
self.root.okbutton = Button(self.root, text='Ok', command = lambda: self.ack())
self.root.okbutton.pack()
def ack(self):
# here I'd like to have the index of selected item in friendlist
print "Index of "+self.root.friend.get()+" is [0 or 1 or 2]:", self.root.friend
# here I'd like to have the index of selected item in friendlist
self.root.destroy()
root = Tk()
list = ['Emma','Sarah','James']
app = TestSpin(root, list)
root.mainloop()
Thanks a lot for your advice. I tried self.root.friend.index(), but that method wants an argument which I do not understand.
There's no way to directly get the value from the widget, but it's just one line of python code:
index = i_fiendlist.index(self.root.friend.get())
Using your code, you need to save the value of the list:
class TestSpin():
def __init__(self, i_root,i_friendlist):
self._list = i_list
...
def ack(self):
value = self.root.friend.get()
index = self._list.index(value)
print "Index of " + value + " is " + str(index)
self.root.destroy()
I can't get my "doLogicForColumn5" function to affect my program. Column 5 of the CSV output should be filled with various values, but instead it's all the same number (12.12).
Lines 14-27 to be specific--they're simply not working!
Any help greatly appreciated!
# -*- coding: utf-8 -*-
import csv
import string # for capwords
date = "7/5/2015"
monthlybudget = 100000
dailybudget = monthlybudget/30
#campaign variables
levels = [["1"], ["2"], ["3"], ["4"], ["5"], ["6"]]
language = [["english"], ["spanish"]]
variables = [["1"], ["2"]]
nouns = [["wordA1"], ["+wordA2"]]
adjectives1 = [["wordB1"], ["wordB2"]]
adjectives2 = [["wordC1"], ["wordC2"]]
def doLogicForColumn5(self): # budget
self.column5 = dailybudget/36
if self.language == ["spanish"]:
self.column5 = self.column5 * .6
if self.level == ["1"]:
self.column5 = self.column5*.8
else:
self.column5 = self.column5*.1
else: #if spanish
self.column5 = self.column5*.4
if self.level == ["1"]:
self.column5 = self.column5*.2
else:
self.column5 = self.column5*.3
class Row(object):
column1 = "column1"
column2 = "column2"
column3 = "column3"
column4 = "column4"
column5 = "budget"
def __init__(self, level, language, noun, adjective1, adjective2, variable):
self.level = level
self.level = str(self.level)
self.language = language
self.language = str(self.language)
self.noun = noun
self.noun = str(self.noun)
self.adjective1 = adjective1
self.adjective1 = str(self.adjective1)
self.adjective2 = adjective2
self.adjective2 = str(self.adjective2)
self.variable = variable
self.variable = str(self.variable)
def rowEntry(self, level, language, noun, adjective1, adjective2, variable):
doLogicForColumn5(self)
lol = [[self.column1], [self.column2], [self.column3], [self.column4], [self.column5]]
lol[0] = self.column1
lol[1] = self.column2
lol[2] = self.column3
lol[3] = self.column4
lol[4] = self.column5
file_writer.writerow([o for o in lol])
with open("test.csv", "wb") as test_file:
file_writer = csv.writer(test_file)
for a in range(0, len(levels)):
for e in range(0, len(language)):
for y in range (0, len(nouns)):
for x in range (0, len(adjectives1)):
for w in range (0, len(adjectives2)):
for n in range(0, len(variables)):
city = "n/a"
stateVersion = "n/a"
food = Row(levels[a], language[e], nouns[y], adjectives1[x], adjectives2[w], variables[n])
food.rowEntry(levels[a], language[e], nouns[y], adjectives1[x], adjectives2[w], variables[n])
First:
for a in range(0, len(levels)):
so a is a number. Then:
food = Row(levels[a],
and so levels[a] is a list such as ["1"]. Then, when you __init__() a Row:
self.level = level
self.level = str(self.level)
So now self.level is a string. Then, in doLogicForColumn5():
if self.level == ["1"]
Recall that self.level was cast as a string earlier. So self.level will never be equal to a list of ["1"]. It may, however, be equal to a string of "['1']", so it would make more sense to compare to that. Better yet, turn the global levels into a flat list like ["1", "2", "3", "4", "5", "6"]. The best option would be for levels to simply be '123456' and refactor your program to use that simpler structure.
Same goes for self.language and any other variables which have been set to a single-element list within a larger list.
Check your code for other instances of unnecessary complexity, as that sort of thing will eventually bite you (as another example, the doLogicForColumn5() function should really just be a method in Row, as commenters are suggesting).
I am trying to add a value to a instance list in python but want to access it dynamically from within a method.
I cannot use dictionaries as I am trying to speed up the sorting of separate lists (boxes) rather than one large list.
Can anybody show me the correct way to do the following?
class Boxes:
def __init__(self):
self.box1 = []
self.box2 = []
#....
self.box10 = []
def addToBox(self, value):
box = self.determineBoxToUse(value)
## box = 2
varname = "box", box ## box2
self.varname.insert(0, value)
def determineBoxToUse(self, value):
## for this example returns 2
return 2
def dumpBox(self):
print self.box2
Boxes = Boxes();
Boxes.addToBox("123.001234")
Boxes.dumpBox()
Error: AttributeError: Boxes instance has no attribute 'varname'
Thanks
You can use hasattr and getattr, although many might suggest you should pursue a different solution.
def addToBox(self, value):
box = self.determineBoxToUse(value)
## box = 2
varname = "box{}".format(box) ## box2
if hasattr(self, varname):
getattr(self, varname).insert(0,value)
Demo:
>>> class Boxes:
def __init__(self):
self.box1 = []
self.box2 = []
#....
self.box10 = []
def addToBox(self, value):
box = self.determineBoxToUse(value)
## box = 2
varname = "box{}".format(box) ## box2
if hasattr(self, varname):
getattr(self, varname).insert(0,value)
def determineBoxToUse(self, value):
## for this example returns 2
return 2
def dumpBox(self):
print self.box2
>>> Boxes = Boxes()
>>> Boxes.addToBox("123.001234")
>>> Boxes.dumpBox()
['123.001234']
>>>
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I created a Hangman class and a HangmanGUI class for a final project I am doing for a introductory python class. I'm sorry if I am making amateur mistakes but I do not have a very strong background in coding. Every time my partner and I run the GUI class, we get this error:
self.__letterVar.set(self.__ans.getAnswer())
TypeError: set() missing 1 required positional argument: 'value'
Here is the hangman class:
from random import *
FOUR = 4
class Hangman:
# --------------------------------------------------------------------------
# Constructor
def __init__(self):
self.__theWord = ''
self.__indexList = []
self.__answer = '_ _ _ _ _ _'
# ---------------------------------------------------------------------------
# Accessors
def getTheWord(self):
return self.__theWord
def getIndexList(self):
return self.__indexList
def getAnswer(self):
return self.__answer
def startFruit(self):
randNumber = randint(0,FOUR)
fruit = open("fruits.txt", 'r')
fruitList = fruit.read().splitlines()
self.__theWord = fruitList[randNumber]
return self.__theWord
def startVege(self):
randNumber = randint(0,FOUR)
vege = open("veges.txt", 'r')
vegeList = vege.read().splitlines()
self.__theWord = vegeList[randNumber]
return self.__theWord
def startName(self):
randNumber = randint(0,FOUR)
name = open("names.txt", 'r')
nameList = name.read().splitlines()
self.__theWord = nameList[randNumber]
return self.__theWord
# --------------------------------------------------------------------------
# Mutators
def find(self, answerWord, inputLetter):
if inputLetter in answerWord:
self.__indexList = [index for index, letter in enumerate(answerWord) if letter == inputLetter]
else:
self.__indexList = []
def set (self, inputLetter):
newString = ""
textList = list(self.__answer)
self.__indexList = self.getIndexList()
location = self.__indexList
for aNum in location:
textList[aNum * 2] = inputLetter
newString = ''.join(textList)
self.__answer = newString
def reset(self):
self.__answer = '_ _ _ _ _ _'
# --------------------------------------------------------------------------
# toString()
def__str__(self):
return "Current answer is: %s" % self.__answer
'''
def main():
game = Hangman()
keyWord = game.startFruit()
letter = input("enter letter")
while letter:
game.find(keyWord, letter)
game.set(letter)
print(game)
letter = input("enter letter")
main()
'''
In the same folder there are several files named Fruits, Veges and Names and each file has about 5-6 six letter words in their respective category. I wanted to have the program open and read the file and extract one word randomly in a list.
We tested out our hangman class and we think it works fine but I think our problem stems from our HangmanGUI class.
from tkinter import *
from random import *
from hangman import *
FOUR = 4
class HangmanUI(Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("Hangman")
self.grid()
self.__label = Label(self, text = "Let's play Hangman!")
self.__label2 = Label(self, text = "Please choose a category!")
self.__label2.grid(row = 1, column = 0)
self.__buttonPane = Frame(self)
self.__buttonPane.grid(row = 2, column = 0)
# created a model of the hangman class
self.__ans = Hangman()
self.__fruitButton= Button(self.__buttonPane, text = 'Fruits', command = self.startFruit)
self.__nameButton = Button(self.__buttonPane, text = 'Names' , command = self.startName)
self.__vegeButton = Button(self.__buttonPane, text = 'Veges', command = self.startVege)
self.__fruitButton.grid(row = 2, column = 0)
self.__vegeButton.grid(row = 2, column = 1)
self.__nameButton.grid(row = 2, column = 2)
self.__label.grid(row = 0 , column = 0)
#to change later so if shuffles images 1-10 with each error (for loop)
self.__image = PhotoImage(file = "0.gif")
self.__imageLabel = Label(self, image = self.__image)
self.__imageLabel.grid(row = 3, column = 0)
self.__letterLabel = Label(self, text = "Please submit a letter to play!")
# instead of the submit button, tried using enter instead for now
self.__letterVar= StringVar
#self.__letterEntry = Entry(self, textvariable = self.__letterVar) # commented out this line, maybe i shouldn't have?
self.__letterEntry = Entry(self, width = 10)
self.__letterEntry.bind('<Return>', self.set)
self.__letterLabel.grid(row = 4, column = 0)
self.__letterEntry.grid(row = 5, column = 0)
self.__value = Label(self, textvariable = self.__letterVar)
self.__value.grid(row= 6, column = 0)
#creates nested frame
self.__letterPane = Frame(self)
self.__letterPane.grid(row = 7, column = 0)
self.__letter1 = Label(self.__letterPane, text = '_ _ _ _ _ _')
self.__letter1.grid(row = 7, column = 0)
def startFruit(self):
self.__ans.startFruit()
def startVege(self):
self.__ans.startVege()
def startName(self):
self.__ans.startName()
def set(self,event):
guessWord = self.__ans.getTheWord()
entryLetter = self.__letterEntry.get()
self.__ans.find(guessWord, entryLetter)
newValue = self.__letterEntry.get()
self.__ans.set(newValue)
# display new value in letterVar
# this is where the program crashes
self.__letterVar.set(self.__ans.getAnswer())
# invoke delete() to clear entry box
self.__letterEntry.delete(0,END)
def main():
HangmanUI().mainloop()
main()
Sorry for the long code, this is my first time posting here and we're both really stressed out because its finals week at our university and we've been frantically trying to put this together. We're both aren't comp sci majors so this has been a fairly difficult process.
We weren't sure how we should go about calling the Hangman class and use methods from the Hangman class in the GUI. As of right now, we're getting the error I stated above and we're not sure how we can fix it. The program crashes towards the end of the GUI class at def set(self, event):
If anyone can provide any insight and tips, that would be greatly appreciated!
You need to make __letterVar an instance of StringVar:
self.__letterVar = StringVar()
otherwise the set() method on it is unbound and won't get the automatic self first argument.
Your code assigned it as the class, not a new instance, instead.