3 回答

TA貢獻1836條經驗 獲得超5個贊
正如人們指出的那樣,我需要添加card_label.image = card_image該函數并刪除card_image和card_label全局以阻止圖像被刪除。但出于某種原因,Python 不喜歡在我這樣做之前打包圖像。
該函數現在看起來像這樣。
global hand
card_image = ImageTk.PhotoImage(Image.open(cards[0]).resize((180, 245), Image.ANTIALIAS))
card_label = Label(root, image=card_image, relief="raised")
card_label.image = card_image
card_label.pack(side="left")
hand += cards[:1]
cards.pop(0)
print(hand)

TA貢獻1788條經驗 獲得超4個贊
代替
card_image = ImageTk.PhotoImage(Image.open(cards[0]).resize((180, 245), Image.ANTIALIAS))
card_label = Label(root, image=card_image, relief="raised").pack(side="left")
做:
card_label = Label(root, image=card_image, relief="raised").pack(side="left")
card_image = ImageTk.PhotoImage(Image.open(cards[0]).resize((180, 245), Image.ANTIALIAS))
card_label.image = card_image #Keeps reference to the image so it's not garbage collected
請注意,當您想使用照片時,請使用變量card_image

TA貢獻1824條經驗 獲得超5個贊
您應該使用圖像池。你很幸運,我這里有一個
import os
from glob import glob
from PIL import Image, ImageTk
from typing import List, Tuple, Union, Dict, Type
from dataclasses import dataclass
@dataclass
class Image_dc:
image :Image.Image
rotate :int = 0
photo :ImageTk.PhotoImage = None
def size(self) -> Tuple[int]:
if not self.photo is None:
return self.photo.width(), self.photo.height()
return self.image.width, self.image.height
class ImagePool(object):
##__> PRIVATE INTERFACE <__##
__PATHS = dict()
__IMAGES = dict()
@staticmethod
def __name(path) -> str:
return os.path.basename(os.path.splitext(path)[0])
@staticmethod
def __unique(path:str, prefix:str='') -> str:
name = f'{prefix}{ImagePool.__name(path)}'
if name in ImagePool.names():
sol = 'using a prefix' if not prefix else f'changing your prefix ({prefix})'
msg = ("WARNING:\n"
f"{name} was not loaded due to a same-name conflict.\n"
f"You may want to consider {sol}.\n\n")
print(msg)
return None
return name
@staticmethod
def __request(name:str) -> Image_dc:
if name in ImagePool.__PATHS:
path = ImagePool.paths(name)
if os.path.isfile(path):
if name not in ImagePool.__IMAGES:
ImagePool.__IMAGES[name] = Image_dc(Image.open(path))
return ImagePool.__IMAGES[name]
else:
raise ValueError(f'ImagePool::__request - Path Error:\n\tpath is not a valid file\n\t{path}')
raise NameError(f'ImagePool::__request - Name Error:\n\t"{name}" does not exist')
return None
@staticmethod
def __size(iw:int, ih:int, w:int=None, h:int=None, scale:float=1.0) -> Tuple[int]:
if not w is None and not h is None:
if iw>ih:
ih = ih*(w/iw)
r = h/ih if (ih/h) > 1 else 1
iw, ih = w*r, ih*r
else:
iw = iw*(h/ih)
r = w/iw if (iw/w) > 1 else 1
iw, ih = iw*r, h*r
return int(iw*scale), int(ih*scale)
##__> PUBLIC INTERFACE <__##
@staticmethod
def names(prefix:str='') -> List[str]:
names = [*ImagePool.__PATHS]
return names if not prefix else list(filter(lambda name, pre=prefix: name.startswith(pre), names))
@staticmethod
def paths(name:str=None) -> Union[Dict, str]:
if name is None:
return ImagePool.__PATHS
if name in ImagePool.__PATHS:
return ImagePool.__PATHS[name]
raise NameError(f'ImagePool::paths - Name Error:\n\tname "{name}" does not exist')
@staticmethod
def images(name:str=None, prefix:str='') -> Union[Dict, Image.Image]:
if name is None:
return {name:ImagePool.__request(name).image for name in self.names(prefix)}
return ImagePool.__request(name).image
@staticmethod
def photos(name:str=None, prefix:str='') -> Union[Dict, ImageTk.PhotoImage]:
if name is None:
return {name:ImagePool.__request(name).photo for name in self.names(prefix)}
return ImagePool.__request(name).photo
@staticmethod
def append_file(path:str, prefix:str='') -> Type:
if not os.path.isfile(path):
raise ValueError(f'ImagePool::append_file - Value Error:\n\tpath is not valid\n\t{path}')
name = ImagePool.__unique(path, prefix)
if name:
ImagePool.__PATHS[name] = path
return ImagePool
@staticmethod
def append_directory(directory:str, filters=['*.png', '*.jpg'], prefix:str='') -> Type:
if not os.path.isdir(directory):
raise ValueError(f'ImagePool::append_directory - Value Error:\n\tdirectory is not valid\n\t{directory}')
filters = filters if isinstance(filters, (List, Tuple)) else [filters]
for filter in filters:
for path in glob(f'{directory}/{filter}'):
ImagePool.append_file(path, prefix)
return ImagePool
@staticmethod
def photo(name:str, width:int=None, height:int=None, scale:float=1.00, rotate:int=None) -> ImageTk.PhotoImage:
image_t = ImagePool.__request(name)
size = ImagePool.__size(*image_t.size(), width, height, scale)
rotate = image_t.rotate if rotate is None else rotate
#only resize if the new size or rotation is different than the current photo size or rotation
#however, a small margin for error must be considered for the size
diff = tuple(map(lambda i, j: i-j, image_t.size(), size))
if (diff > (1, 1)) or (diff < (-1, -1)) or (image_t.rotate != rotate):
image_t.rotate = rotate
image_t.photo = ImageTk.PhotoImage(image_t.image.resize(size, Image.LANCZOS).rotate(rotate))
return image_t.photo
使用該文件您可以非常輕松地做很多事情。您可以將所有卡片圖像放入一個文件夾中,并通過以下方式獲取它們:
ImagePool.append_directory(path_to_folder)
然后,您可以獲取任何卡并強制其適合其父級(無論如何):
somelabel['image'] = ImagePool.photo(image_name, allotted_width, allotted_height)
要不就:
somelabel['image'] = ImagePool.photo(image_name)
你可以得到池中每個名字的列表
deck = ImagePool.names()
或者在附加目錄的同時抓取它
deck = ImagePool.append_directory(path_to_folder).names()
這對您非常有幫助,因為您可以簡單地洗牌并彈出該列表作為游戲中的官方“牌組”。像這樣:
somecard['image'] = ImagePool.photo(deck.pop(0))
假設您不僅擁有卡片圖形,但又不想在創建牌組時獲得所有圖像,那么也有一個解決方案。
首先在附加卡片圖像目錄時提供前綴,然后在調用names(). 只要卡片圖像目錄中只有卡片圖像,則只會返回卡片名稱。
deck = ImagePool.append_directory(path_to_folder, prefix='cards_').names('cards_')
筆記:
allotted區域僅被分配,絕不應被假定為代表實際圖像的最終寬度和/或高度。圖像將盡一切努力適應分配的空間,而不會丟失其原始的高度和寬度比例。如果您不提供分配的寬度和高度,圖像將是完整尺寸。
所有圖像和照片參考都會自動維護在ImagePool. 沒有理由存儲您自己的參考資料
整個類是靜態的,因此可以在任何地方訪問所有圖像和照片的引用,而無需ImagePool實例。換句話說,您永遠不需要這樣做:images = ImagePool()因此永遠不需要弄清楚如何進入images某些class或其他文檔。
在您開始請求圖像之前,不會實際加載圖像,然后它會自動發生。這是一件好事。你有 52 張卡,但如果你在第一場比賽中只使用 ex: 6 ~ 只有 6 張會完全加載。最終,所有卡牌都會被玩完并被完全加載,并且您在游戲中不會出現嘗試一次完全創建 52 張卡牌的情況。
該類ImagePool具有更多功能,但此處解釋的功能是您的游戲所需的全部功能。
添加回答
舉報