| | |
Trying to get card images into a GUI
Please support our Python advertiser: Programming Forums - DaniWeb Sister Site
![]() |
•
•
Join Date: Jul 2006
Posts: 608
Reputation:
Solved Threads: 150
Hi all,
I know there have been several threads about getting card images into a GUI, but I'm flustered trying to understand why some things work and some things don't. Here's the code:
[php]
import random
from Tkinter import *
import Image, ImageTk
class Card(object):
suits = ["C","D","H","S"]
values = ['A','2','3','4','5','6','7','8','9','T','J','Q','K']
down_img = PhotoImage(file="Deck1.gif")
cards = [x+y for x in suits for y in values]
pics = {}
for x in cards:
pics[x] = PhotoImage(file=x+'.gif')
def __init__(self, suit=None, value=None, up=True):
if suit in Card.suits:
self.suit = suit
else:
self.suit = random.choice(Card.suits)
if value in Card.values:
self.value = value
else:
self.value = random.choice(Card.values)
self.up = up
def __str__(self):
return self.value+self.suit
def picURL(self):
return Card.pics[self.suit+self.value]
def display(self, x,y,angle,canvas):
if self.up:
canvas.create_image(x,y,Card.pics[self.suit+self.value])
else:
canvas.create_image(x,y,Card.down_image)
class Deck(Card):
deck = Card.cards[:]
def __init__(self, suit=None, value=None, up=True):
card = str(suit)+str(value)
if card not in Deck.deck:
if Deck.deck == []:
raise ValueError, "Deck empty!"
card = random.choice(Deck.deck)
suit=card[0]
value=card[1:]
Deck.deck.remove(card)
self.suit = suit
self.value = value
self.up = up
@staticmethod
def shuffle():
Deck.deck = Card.cards
class BridgeRound(Frame):
# display_data contains display info for each hand:
#(startx, starty, dx, dy, angle of rotation)
display_data = [(30,0,10,0,0), \
(200, 30, 0, 10, 270), \
(170, 200, -10, 0, 180), \
(0, 170, 0, -10, 90)]
def __init__(self, master):
Frame.__init__(self,master)
self.canvas = Canvas(self)
self.canvas.grid()
self.grid()
self.deal()
self.display()
def deal(self):
Deck.shuffle()
self.hands = [[Deck() for i in range(13)] for j in range(4)]
def display(self):
for i in range(4):
hand = self.hands[i]
x, y, dx, dy, angle = BridgeRound.display_data[i]
for j in hand:
print j,
j.display(self.canvas,x,y,angle)
x += dx
y += dy
mainw = Tk()
mainw.f = BridgeRound(mainw)
mainw.mainloop()
[/php]
You may ask, why does he create the images in the Card class? Isn't that wasteful of memory? Well, yes. BUT...for some reason, if I don't maintain a static reference to the card images, they don't display. Thus, a line like
canvas.create_image(PhotoImage(file="H6.gif"))
results in a blank image. So if I want to display all the cards at once, then I have to maintain them all in a data structure.
Anyways, when I run the code, I get
to which I say ?!@#*^$#^?!
So when's the best time to create an image?! I'm sure I can tweak the code to make it run ... but what's the underlying theory about Tkinter images here?
Thanks,
Jeff
I know there have been several threads about getting card images into a GUI, but I'm flustered trying to understand why some things work and some things don't. Here's the code:
[php]
import random
from Tkinter import *
import Image, ImageTk
class Card(object):
suits = ["C","D","H","S"]
values = ['A','2','3','4','5','6','7','8','9','T','J','Q','K']
down_img = PhotoImage(file="Deck1.gif")
cards = [x+y for x in suits for y in values]
pics = {}
for x in cards:
pics[x] = PhotoImage(file=x+'.gif')
def __init__(self, suit=None, value=None, up=True):
if suit in Card.suits:
self.suit = suit
else:
self.suit = random.choice(Card.suits)
if value in Card.values:
self.value = value
else:
self.value = random.choice(Card.values)
self.up = up
def __str__(self):
return self.value+self.suit
def picURL(self):
return Card.pics[self.suit+self.value]
def display(self, x,y,angle,canvas):
if self.up:
canvas.create_image(x,y,Card.pics[self.suit+self.value])
else:
canvas.create_image(x,y,Card.down_image)
class Deck(Card):
deck = Card.cards[:]
def __init__(self, suit=None, value=None, up=True):
card = str(suit)+str(value)
if card not in Deck.deck:
if Deck.deck == []:
raise ValueError, "Deck empty!"
card = random.choice(Deck.deck)
suit=card[0]
value=card[1:]
Deck.deck.remove(card)
self.suit = suit
self.value = value
self.up = up
@staticmethod
def shuffle():
Deck.deck = Card.cards
class BridgeRound(Frame):
# display_data contains display info for each hand:
#(startx, starty, dx, dy, angle of rotation)
display_data = [(30,0,10,0,0), \
(200, 30, 0, 10, 270), \
(170, 200, -10, 0, 180), \
(0, 170, 0, -10, 90)]
def __init__(self, master):
Frame.__init__(self,master)
self.canvas = Canvas(self)
self.canvas.grid()
self.grid()
self.deal()
self.display()
def deal(self):
Deck.shuffle()
self.hands = [[Deck() for i in range(13)] for j in range(4)]
def display(self):
for i in range(4):
hand = self.hands[i]
x, y, dx, dy, angle = BridgeRound.display_data[i]
for j in hand:
print j,
j.display(self.canvas,x,y,angle)
x += dx
y += dy
mainw = Tk()
mainw.f = BridgeRound(mainw)
mainw.mainloop()
[/php]
You may ask, why does he create the images in the Card class? Isn't that wasteful of memory? Well, yes. BUT...for some reason, if I don't maintain a static reference to the card images, they don't display. Thus, a line like
canvas.create_image(PhotoImage(file="H6.gif"))
results in a blank image. So if I want to display all the cards at once, then I have to maintain them all in a data structure.
Anyways, when I run the code, I get
•
•
•
•
Originally Posted by Python Shell
>>>
Traceback (most recent call last):
File "C:\Python24\src\cards\cards.py", line 5, in -toplevel-
class Card(object):
File "C:\Python24\src\cards\cards.py", line 14, in Card
pics[x] = PhotoImage(file=x+'.gif')
File "C:\Python24\lib\lib-tk\Tkinter.py", line 3203, in __init__
Image.__init__(self, 'photo', name, cnf, master, **kw)
File "C:\Python24\lib\lib-tk\Tkinter.py", line 3144, in __init__
raise RuntimeError, 'Too early to create image'
RuntimeError: Too early to create image
So when's the best time to create an image?! I'm sure I can tweak the code to make it run ... but what's the underlying theory about Tkinter images here?
Thanks,
Jeff
•
•
Join Date: Jul 2006
Posts: 608
Reputation:
Solved Threads: 150
Fixed. Uff. Here's the problem: the Card class code runs first, and the images were attempting to be created before Tk() is ever initialized. Apparently, one can't create images until a Tk is created. OK.
Next problem: how does one rotate the card images so that they all display inwards?
Here's the code, with some bugs fixed:
[php]
import random
from Tkinter import *
import Image, ImageTk
class Card(object):
suits = ["C","D","H","S"]
values = ['A','2','3','4','5','6','7','8','9','T','J','Q','K']
down_img = None
cards = [x+y for x in suits for y in values]
pics = {}
def __init__(self, suit=None, value=None, up=True):
if suit in Card.suits:
self.suit = suit
else:
self.suit = random.choice(Card.suits)
if value in Card.values:
self.value = value
else:
self.value = random.choice(Card.values)
self.up = up
def __str__(self):
return self.value+self.suit
def picURL(self):
return Card.pics[self.suit+self.value]
def display(self, canvas, x,y,angle):
if self.up:
image=Card.pics[self.suit+self.value]
else:
image=Card.down_image
#image.rotate(angle)
canvas.create_image(x,y,image=image)
@staticmethod
def create_images():
for x in Card.cards:
Card.pics[x] = PhotoImage(file=x+'.gif')
Card.down_img = PhotoImage(file="Deck1.gif")
class Deck(Card):
deck = Card.cards[:]
def __init__(self, suit=None, value=None, up=True):
card = str(suit)+str(value)
if card not in Deck.deck:
if Deck.deck == []:
raise ValueError, "Deck empty!"
card = random.choice(Deck.deck)
suit=card[0]
value=card[1:]
Deck.deck.remove(card)
self.suit = suit
self.value = value
self.up = up
@staticmethod
def shuffle():
Deck.deck = Card.cards[:]
class BridgeRound(Frame):
# display_data contains display info for each hand:
#(startx, starty, dx, dy, angle of rotation)
display_data = [(120, 50,12,0,0), \
(340, 30, 0, 15, 270), \
(260, 220, -12, 0, 180), \
(40, 220, 0, -15, 90)]
def __init__(self, master):
Frame.__init__(self,master)
self.canvas = Canvas(self)
self.canvas.grid()
self.grid()
self.deal()
self.display()
def deal(self):
Deck.shuffle()
self.hands = [[Deck() for i in range(13)] for j in range(4)]
def display(self):
Card.create_images()
for i in range(4):
hand = self.hands[i]
x, y, dx, dy, angle = BridgeRound.display_data[i]
for j in hand:
#print j,
j.display(self.canvas,x,y,angle)
x += dx
y += dy
mainw = Tk()
mainw.f = BridgeRound(mainw)
mainw.mainloop()
[/php]
Jeff
Next problem: how does one rotate the card images so that they all display inwards?
Here's the code, with some bugs fixed:
[php]
import random
from Tkinter import *
import Image, ImageTk
class Card(object):
suits = ["C","D","H","S"]
values = ['A','2','3','4','5','6','7','8','9','T','J','Q','K']
down_img = None
cards = [x+y for x in suits for y in values]
pics = {}
def __init__(self, suit=None, value=None, up=True):
if suit in Card.suits:
self.suit = suit
else:
self.suit = random.choice(Card.suits)
if value in Card.values:
self.value = value
else:
self.value = random.choice(Card.values)
self.up = up
def __str__(self):
return self.value+self.suit
def picURL(self):
return Card.pics[self.suit+self.value]
def display(self, canvas, x,y,angle):
if self.up:
image=Card.pics[self.suit+self.value]
else:
image=Card.down_image
#image.rotate(angle)
canvas.create_image(x,y,image=image)
@staticmethod
def create_images():
for x in Card.cards:
Card.pics[x] = PhotoImage(file=x+'.gif')
Card.down_img = PhotoImage(file="Deck1.gif")
class Deck(Card):
deck = Card.cards[:]
def __init__(self, suit=None, value=None, up=True):
card = str(suit)+str(value)
if card not in Deck.deck:
if Deck.deck == []:
raise ValueError, "Deck empty!"
card = random.choice(Deck.deck)
suit=card[0]
value=card[1:]
Deck.deck.remove(card)
self.suit = suit
self.value = value
self.up = up
@staticmethod
def shuffle():
Deck.deck = Card.cards[:]
class BridgeRound(Frame):
# display_data contains display info for each hand:
#(startx, starty, dx, dy, angle of rotation)
display_data = [(120, 50,12,0,0), \
(340, 30, 0, 15, 270), \
(260, 220, -12, 0, 180), \
(40, 220, 0, -15, 90)]
def __init__(self, master):
Frame.__init__(self,master)
self.canvas = Canvas(self)
self.canvas.grid()
self.grid()
self.deal()
self.display()
def deal(self):
Deck.shuffle()
self.hands = [[Deck() for i in range(13)] for j in range(4)]
def display(self):
Card.create_images()
for i in range(4):
hand = self.hands[i]
x, y, dx, dy, angle = BridgeRound.display_data[i]
for j in hand:
#print j,
j.display(self.canvas,x,y,angle)
x += dx
y += dy
mainw = Tk()
mainw.f = BridgeRound(mainw)
mainw.mainloop()
[/php]
Jeff
Jeff, I trust you have taken a look at:
http://www.daniweb.com/techtalkforum...257347-78.html
I had a similar problem there and solved it. Other articles mention that sometimes you have to protect Tkinter stored images from garbage collection. That may be with earlier versions of Python.
To rotate an image you best use the Python Image Library (PIL), it works very well with the Tkinter GUI.
Interesting project you have there! Good luck!
http://www.daniweb.com/techtalkforum...257347-78.html
I had a similar problem there and solved it. Other articles mention that sometimes you have to protect Tkinter stored images from garbage collection. That may be with earlier versions of Python.
To rotate an image you best use the Python Image Library (PIL), it works very well with the Tkinter GUI.
Interesting project you have there! Good luck!
May 'the Google' be with you!
•
•
Join Date: Jul 2006
Posts: 608
Reputation:
Solved Threads: 150
OK, this is progressing in increments. Why doesn't the canvas resize? As it is, the cards go off the right edge, regardless of the order in which I grid the canvas and its containing frame. Tkinter is sooo weird.
python Syntax (Toggle Plain Text)
import random from Tkinter import * import Image, ImageTk class Card(object): suits = ["C","D","H","S"] values = ['A','K','Q','J','T','9','8','7','6','5','4','3','2'] down_img = None cards = [x+y for x in suits for y in values] pics = {} def __init__(self, suit=None, value=None, up=True): if suit in Card.suits: self.suit = suit else: self.suit = random.choice(Card.suits) if value in Card.values: self.value = value else: self.value = random.choice(Card.values) self.up = up def __str__(self): return self.value+self.suit def picURL(self): return Card.pics[self.suit+self.value] def display(self, canvas, x,y,angle): if self.up: image=Card.pics[self.suit+self.value] else: image=Card.down_image image=image.rotate(angle) self.image = ImageTk.PhotoImage(image) canvas.create_image(x,y,image=self.image) def key(self): # returns hash value of 20*suit + value -- guaranteed unique; sorts # by color. return 20*('SHCD'.find(self.suit))+Card.values.index(self.value) @staticmethod def create_images(): for x in Card.cards: Card.pics[x] = Image.open(x+'.gif') Card.down_img = Image.open('Deck1.gif') class Deck(Card): deck = Card.cards[:] def __init__(self, suit=None, value=None, up=True): card = str(suit)+str(value) if card not in Deck.deck: if Deck.deck == []: raise ValueError, "Deck empty!" card = random.choice(Deck.deck) suit=card[0] value=card[1:] Deck.deck.remove(card) self.suit = suit self.value = value self.up = up @staticmethod def shuffle(): Deck.deck = Card.cards[:] class BridgeRound(Frame): # display_data contains display info for each hand: #(startx, starty, dx, dy, angle of rotation) display_data = [(150, 50,12,0,0), \ (390, 40, 0, 15, 270), \ (290, 220, -12, 0, 180), \ (50, 220, 0, -15, 90)] def __init__(self, master): Frame.__init__(self,master) self.canvas = Canvas(self) #self.grid() self.deal() self.display() self.canvas.grid() self.grid() def deal(self): Deck.shuffle() self.hands = [[Deck() for i in range(13)] for j in range(4)] def display(self): Card.create_images() for i in range(4): hand = self.hands[i] hand.sort(key=lambda x:x.key()) x, y, dx, dy, angle = BridgeRound.display_data[i] for j in hand: #print j, j.display(self.canvas,x,y,angle) x += dx y += dy mainw = Tk() mainw.f = BridgeRound(mainw) mainw.mainloop()
![]() |
Similar Threads
- Starting Python (Python)
- My nic card won't work! (*nix Hardware Configuration)
- Refreshing a Tkinter Canvas Multiple Times: (Python)
- Python GUI build: Logic Complications and Mistakes (Python)
- Re: Starting Python (Python)
Other Threads in the Python Forum
- Previous Thread: Extend Class Characters to numeric Values
- Next Thread: Ext Class
Views: 1558 | Replies: 4
| Thread Tools | Search this Thread |
Tag cloud for Python
approximation array beginner book builtin change cipher clear client code color converter countpasswordentry cturtle curved def dictionary drive dynamic examples excel file float format ftp function gui homework import inches input java library line lines linux list lists loop microcontroller mouse mysqldb mysqlquery newb number numbers output parsing path plugin port prime program programming projects py2exe pygame pymailer pyqt python random recursion recursive redirect remote script scrolledtext search singleton socket sqlite ssh string strings strip subprocess sum syntax table terminal text textarea thread threading time tkinter tlapse tuple tutorial twoup ubuntu unicode urllib urllib2 variable vigenere wikipedia windows wxpython xlwt






