944,098 Members | Top Members by Rank

Ad:
  • Python Discussion Thread
  • Unsolved
  • Views: 2283
  • Python RSS
Dec 23rd, 2006
0

Trying to get card images into a GUI

Expand Post »
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

Quote 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
Similar Threads
Reputation Points: 92
Solved Threads: 156
Practically a Master Poster
jrcagle is offline Offline
608 posts
since Jul 2006
Dec 23rd, 2006
0

Re: Trying to get card images into a GUI

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
Reputation Points: 92
Solved Threads: 156
Practically a Master Poster
jrcagle is offline Offline
608 posts
since Jul 2006
Dec 23rd, 2006
0

Re: Trying to get card images into a GUI

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!
Moderator
Reputation Points: 1333
Solved Threads: 1403
DaniWeb's Hypocrite
vegaseat is offline Offline
5,792 posts
since Oct 2004
Dec 24th, 2006
0

Re: Trying to get card images into a GUI

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)
  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()
Reputation Points: 92
Solved Threads: 156
Practically a Master Poster
jrcagle is offline Offline
608 posts
since Jul 2006
Dec 25th, 2006
0

Re: Trying to get card images into a GUI

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 ...
Moderator
Reputation Points: 1333
Solved Threads: 1403
DaniWeb's Hypocrite
vegaseat is offline Offline
5,792 posts
since Oct 2004

This thread is more than three months old

No one has posted to this discussion for at least three months. Please let old threads die and do not reply to them unless you feel you have something new and valuable to contribute that absolutely must be added to make the discussion complete. Otherwise, please start a new thread in this forum instead.
Message:
Previous Thread in Python Forum Timeline: Extend Class Characters to numeric Values
Next Thread in Python Forum Timeline: Ext Class





About Us | Contact Us | Advertise | Acceptable Use Policy
Forum Index | Build Custom RSS Feed


Follow us on Twitter


© 2011 DaniWeb® LLC