我正在编写纸牌游戏 Dominion 的数字版本,以便与一些朋友一起玩。这只是我第二次使用 tkinter 进行窗口管理,总体来说我对 python 不是很熟练。无论如何:
程序目前如下所示:
我最困惑的是,为什么画布内滚动框架中的卡片是(可能)导致框架的可见部分根据需要拉伸到屏幕的两端,但不是使整个整体拉伸得足够高,以使卡片文本可见。我也很困惑为什么标签框和它们应该包装的边框之间存在间隙(例如手部区域下方的绿色线令人困惑),但我不知道这个问题是否相关。
我的代码变得越来越混乱,因为我尝试了在线教程中的各种方法来修复它,对此我深表歉意。现在是这样:
from tkinter import *
from PIL import Image, ImageTk
from pathlib import Path
filedirectory = Path.cwd() #sets filedirectory to the current program's location
##Image handling
def ResizeImage(image,new_size=(300,500)):
tempImage=Image.open(image)
card=tempImage.resize(new_size) #Don't re-use variable for somereason, and do in extra lines? Test later.
return card #should probably do PhotoImage conversion here
##Window Management
root=Tk() #create a window
root.title("Frederick's Custom Dominion Game") #set the title of the window, which is displayed on window bar among other places.
icon = filedirectory.joinpath('img/icon.ico') #uses relative pathing to get the icon file
root.iconbitmap(icon) #sets the icon to the desired image I made
root.geometry("1800x1000") #set window size
root.configure(background="green") #like windows solitaire
frame = Frame(root,bg="green") #Creates a frame, which is a graphic that's generally designed to be identical to the background of the window and the same size as it for some reason.
frame.pack(side=BOTTOM, fill=BOTH,expand=1)
midframe=Frame(frame,bg="green") #use so we can pack the other way with the play and discard
player_hand=LabelFrame(frame,text='Hand',height=520,width=1520) #set up three labelFrames (which just draw a square and put a text label in the corner, but look nice)
play_area=LabelFrame(midframe,text='Play',height=520,width=1520) #height and width don't do anything without pack_propagate(0), but that's okay because we shouldn't be using them
discard=LabelFrame(midframe,text='discard',height=520,width=320)
player_hand.pack(side=BOTTOM,fill=X,expand=1) #This should be putting the hand across the entire bottom of the screen, but it's not
player_hand.update() #didn't work, didn't hurt
midframe.pack(side=BOTTOM,fill=BOTH,expand=1)
play_area.pack(side=LEFT,fill=X,expand=1)
discard.pack(side=RIGHT,expand=1)
scroll_bar = Scrollbar(player_hand,orient=HORIZONTAL) #place next to, not in, canvas. Linking is via configure *on both*
scroll_field=Canvas(player_hand,xscrollcommand=scroll_bar.set,highlightthickness=0)
scroll_field.config(scrollregion=scroll_field.bbox('all')) #bbox=bounding box, target self not inset Frame
scroll_bar.configure(orient=HORIZONTAL, command=scroll_field.xview) #target Canvas, not Frame
inside_frame=Frame(scroll_field, bg='blue') #this should grow to fit its contents, but it doesn't. Can't pack it, because that breaks scrolling.
###scroll code?
def updateScrollRegion():
scroll_field.update_idletasks()
scroll_field.config(scrollregion=scroll_field.bbox('all'))
root.update()
scroll_bar.pack( side = BOTTOM, fill = X,expand=1 )
scroll_field.create_window(0, 0, window=inside_frame, anchor=NW)
scroll_field.pack(fill=BOTH,side=LEFT,expand=TRUE) #Fill set to BOTH but still not growing vertically
root.after(1000,updateScrollRegion)
###
#deck logic
FuckGarbageCollection=[] #Why the heck are graphics garbage collected while still used in a Label?
flist = []
for f in Path(filedirectory.joinpath('img/Cards')).iterdir():
if f.is_file():
print(f)
flist.append(f)
class Card:
def __init__(self,file):
self.image=file
print(file)
FuckGarbageCollection.append(ImageTk.PhotoImage(ResizeImage(file))) #should move image processing from here to top of file
self.label=Label(inside_frame,image=FuckGarbageCollection[-1])
print("image complete")
AllCards=[]
for i in flist:
AllCards.append(Card(i))
for i in AllCards[:15]:
i.label.pack(side=LEFT,expand=1,fill=Y) #Does put cards in the box. Doesn't make the box fit.
root.update()
scroll_field.configure(scrollregion = scroll_field.bbox("all"))
updateScrollRegion()
def logic():
root.update()
player_hand.update()
scroll_field.update()
inside_frame.update()
updateScrollRegion()
root.after(1000,logic)
for i in inside_frame.children.values(): #no dice
i.update()
root.after(1000,logic)
root.mainloop()# spin forever?
我知道当我将整个卡牌列表(AllCards 而不是 AllCards[:15])放入手中时,我已经达到了坐标限制,但即使没有这个问题仍然存在。
我尝试过在 root.mainloop() 之前或通过 after() 在 root.mainloop() 中更新各种内容。我尝试过明确地告诉不同的事情来填充各个方向或两个方向的空间。我尝试通过禁用包传播来明确强制 Labelframes 具有正确的大小,其工作原理是它会更改它们的大小以填充我想要的任何内容,但仍然在奇怪的位置和带有它们的内容(例如卡片图像和滚动条)卡片图像被切断并显示额外的灰色背景。强制大小似乎也是一种不好的学习习惯,所以我宁愿避免它,尽管我可以暂时使我的计算机/显示器上的一切正常工作,专门通过 place() (或者可能只是传播禁用,但在这一点上我只使用 place())。
我尝试阅读 github 上的一些 tkinter 文件,但它基本上超出了我的技能水平,所以我非常确定没有明显的答案/语法错误/缺少参数,但我不会感到惊讶学习其他方式。
我期望的是小部件会扩展以适合其内容,因此卡片应该全部显示,以达到屏幕/窗口大小和坐标限制的限制。
您没有指定画布的高度,因此默认高度小于这些卡片的高度。
请注意,使用
.create_window()
将小部件放入画布不会影响画布的大小。
因此将画布的高度指定为 500 将解决该问题:
scroll_field=Canvas(player_hand,xscrollcommand=scroll_bar.set,highlightthickness=0,height=500)