Trying to get card images into a GUI

Please support our Python advertiser: Programming Forums - DaniWeb Sister Site
Reply

Join Date: Jul 2006
Posts: 608
Reputation: jrcagle is on a distinguished road 
Solved Threads: 150
jrcagle jrcagle is offline Offline
Practically a Master Poster

Trying to get card images into a GUI

 
0
  #1
Dec 23rd, 2006
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

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
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
Reply With Quote Quick reply to this message  
Join Date: Jul 2006
Posts: 608
Reputation: jrcagle is on a distinguished road 
Solved Threads: 150
jrcagle jrcagle is offline Offline
Practically a Master Poster

Re: Trying to get card images into a GUI

 
0
  #2
Dec 23rd, 2006
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
Reply With Quote Quick reply to this message  
Join Date: Oct 2004
Posts: 4,145
Reputation: vegaseat is just really nice vegaseat is just really nice vegaseat is just really nice vegaseat is just really nice vegaseat is just really nice 
Solved Threads: 949
Moderator
vegaseat's Avatar
vegaseat vegaseat is offline Offline
DaniWeb's Hypocrite

Re: Trying to get card images into a GUI

 
0
  #3
Dec 23rd, 2006
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!
May 'the Google' be with you!
Reply With Quote Quick reply to this message  
Join Date: Jul 2006
Posts: 608
Reputation: jrcagle is on a distinguished road 
Solved Threads: 150
jrcagle jrcagle is offline Offline
Practically a Master Poster

Re: Trying to get card images into a GUI

 
0
  #4
Dec 24th, 2006
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.

  1. import random
  2. from Tkinter import *
  3. import Image, ImageTk
  4.  
  5. class Card(object):
  6. suits = ["C","D","H","S"]
  7. values = ['A','K','Q','J','T','9','8','7','6','5','4','3','2']
  8. down_img = None
  9.  
  10. cards = [x+y for x in suits for y in values]
  11.  
  12. pics = {}
  13.  
  14. def __init__(self, suit=None, value=None, up=True):
  15.  
  16. if suit in Card.suits:
  17. self.suit = suit
  18. else:
  19. self.suit = random.choice(Card.suits)
  20.  
  21. if value in Card.values:
  22. self.value = value
  23. else:
  24. self.value = random.choice(Card.values)
  25. self.up = up
  26.  
  27. def __str__(self):
  28. return self.value+self.suit
  29.  
  30. def picURL(self):
  31. return Card.pics[self.suit+self.value]
  32.  
  33. def display(self, canvas, x,y,angle):
  34. if self.up:
  35. image=Card.pics[self.suit+self.value]
  36. else:
  37. image=Card.down_image
  38. image=image.rotate(angle)
  39. self.image = ImageTk.PhotoImage(image)
  40. canvas.create_image(x,y,image=self.image)
  41.  
  42. def key(self):
  43. # returns hash value of 20*suit + value -- guaranteed unique; sorts
  44. # by color.
  45. return 20*('SHCD'.find(self.suit))+Card.values.index(self.value)
  46.  
  47. @staticmethod
  48. def create_images():
  49. for x in Card.cards:
  50. Card.pics[x] = Image.open(x+'.gif')
  51. Card.down_img = Image.open('Deck1.gif')
  52.  
  53.  
  54. class Deck(Card):
  55.  
  56. deck = Card.cards[:]
  57.  
  58. def __init__(self, suit=None, value=None, up=True):
  59. card = str(suit)+str(value)
  60. if card not in Deck.deck:
  61. if Deck.deck == []:
  62. raise ValueError, "Deck empty!"
  63. card = random.choice(Deck.deck)
  64. suit=card[0]
  65. value=card[1:]
  66. Deck.deck.remove(card)
  67. self.suit = suit
  68. self.value = value
  69. self.up = up
  70.  
  71. @staticmethod
  72. def shuffle():
  73. Deck.deck = Card.cards[:]
  74.  
  75. class BridgeRound(Frame):
  76.  
  77. # display_data contains display info for each hand:
  78. #(startx, starty, dx, dy, angle of rotation)
  79. display_data = [(150, 50,12,0,0), \
  80. (390, 40, 0, 15, 270), \
  81. (290, 220, -12, 0, 180), \
  82. (50, 220, 0, -15, 90)]
  83.  
  84. def __init__(self, master):
  85. Frame.__init__(self,master)
  86. self.canvas = Canvas(self)
  87.  
  88. #self.grid()
  89. self.deal()
  90. self.display()
  91. self.canvas.grid()
  92. self.grid()
  93.  
  94. def deal(self):
  95. Deck.shuffle()
  96. self.hands = [[Deck() for i in range(13)] for j in range(4)]
  97.  
  98. def display(self):
  99. Card.create_images()
  100. for i in range(4):
  101. hand = self.hands[i]
  102. hand.sort(key=lambda x:x.key())
  103. x, y, dx, dy, angle = BridgeRound.display_data[i]
  104. for j in hand:
  105. #print j,
  106. j.display(self.canvas,x,y,angle)
  107. x += dx
  108. y += dy
  109.  
  110. mainw = Tk()
  111. mainw.f = BridgeRound(mainw)
  112. mainw.mainloop()
Reply With Quote Quick reply to this message  
Join Date: Oct 2004
Posts: 4,145
Reputation: vegaseat is just really nice vegaseat is just really nice vegaseat is just really nice vegaseat is just really nice vegaseat is just really nice 
Solved Threads: 949
Moderator
vegaseat's Avatar
vegaseat vegaseat is offline Offline
DaniWeb's Hypocrite

Re: Trying to get card images into a GUI

 
0
  #5
Dec 25th, 2006
Jeff,
the display looks pretty good! On my Sony multimedia machine using Windows XP the display looks very normal, nothing hanging off the edge. All I can think off is an update() thrown in.

Well, merry Christmas and a jolly Ho, Ho , Ho ...
May 'the Google' be with you!
Reply With Quote Quick reply to this message  
Reply

This thread is more than three months old.
Perhaps start a new thread instead?
Message:



Similar Threads
Other Threads in the Python Forum


Views: 1558 | Replies: 4
Thread Tools Search this Thread



Tag cloud for Python
About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC