我正在尝试将一个labelframe放在其他几个小部件旁边,但我根本无法弄明白。目前,当我使用.pack()方法时,它会显示在所有其他小部件的下面。当我尝试使用.grid(column = x,row = y)配置位置时,程序会运行但挂起并且没有GUI出现。
以下是相关代码
def createWidgets(self):
# Create entrybox and align to grid
self.send_entry = tk.Entry(self)
self.send_entry.grid(row=0,column=0)
# Create button,allign to grid, get xml
self.change_sub = tk.Button(self,text='Change Subreddit',padx=5, pady=5, command=lambda :self.getXML(self.send_entry.get())).grid(row=0 , column=3)
# Create scrollbar on Y-Axis
self.lb_scrollY = tk.Scrollbar(self,orient=tk.VERTICAL)
# On grid next to Listbox(sticky means fill whole row
self.lb_scrollY.grid(row=1,column=4,sticky=tk.NS,rowspan=6)
# Create Listbox and get Y from scrollbar
self.thread_lb = tk.Listbox(self,yscrollcommand=self.lb_scrollY.set)
# Calls function whenever a new item is selected
self.thread_lb.bind('<<ListboxSelect>>',self.updateSelected)
# scrolly will change the view of listbox
self.lb_scrollY['command']=self.thread_lb.yview
self.thread_lb.grid(row=1,column=0,sticky=tk.NS+tk.EW,columnspan=4,rowspan=3)
self.threadFrame = tk.LabelFrame(main,text='Reddit')
self.threadLabelTitle = tk.Label(self.threadFrame,textvariable=self.threadTitle,wraplength=200).grid(row=1,column=2,sticky= tk.EW)
self.threadLabelAuth = tk.Label(self.threadFrame, textvariable=self.threadAuth,wraplength=200).grid(row=2,column=2,sticky = tk.EW)
self.threadLabelPub = tk.Label(self.threadFrame, textvariable=self.threadPub,wraplength=200).grid(row=3,column=2,sticky = tk.EW)
self.threadLabelArtLink = tk.Label(self.threadFrame, textvariable=self.threadArtLink,wraplength=200).grid(row=4,column=2,sticky = tk.EW)
self.threadLabelThreadLink = tk.Label(self.threadFrame, textvariable=self.threadLink,wraplength=200).grid(row=5,column=2,sticky = tk.EW)
self.threadImgLink = tk.Label(self.threadFrame, textvariable=self.threadImg,wraplength=200).grid(row=6,column=2,sticky = tk.EW)
# self.columnconfigure(2,minsize=200)
# self.rowconfigure(1,minsize=175)
self.threadFrame.pack()
self.QUIT = tk.Button(self, text="QUIT", fg="red", command=main.destroy,padx=5, pady=5).grid(row=7)
这是完整的程序,所以如果你愿意,你可以运行它。
import xml.etree.ElementTree as ET
import webbrowser,time,urllib.request,re
import tkinter as tk
import urllib
main = tk.Tk()
class Application(tk.Frame):
def __init__(self, master=None):
self.threadTitle = tk.StringVar()
self.threadAuth = tk.StringVar()
self.threadPub = tk.StringVar()
self.threadArtLink = tk.StringVar()
self.threadLink = tk.StringVar()
self.threadImg = tk.StringVar()
self.threadArtLink.set('Click something to display thread info')
# Intializes tkinter gui framework
tk.Frame.__init__(self, master)
# Packs widgets needed
self.pack()
# Creates the widgets functions
self.createWidgets()
# Intializes the man rss.xml
self.initial()
# self.threadLabelArtLink = None
# self.threadLabelTitle = None
# self.threadLabelThreadLink = None
# self.threadLabelArtLink = None
# self.threadImgLink = None
def createWidgets(self):
# Create entrybox and align to grid
self.send_entry = tk.Entry(self)
self.send_entry.grid(row=0,column=0)
# Create button,allign to grid, get xml
self.change_sub = tk.Button(self,text='Change Subreddit',padx=5, pady=5, command=lambda :self.getXML(self.send_entry.get())).grid(row=0 , column=3)
# Create scrollbar on Y-Axis
self.lb_scrollY = tk.Scrollbar(self,orient=tk.VERTICAL)
# On grid next to Listbox(sticky means fill whole row
self.lb_scrollY.grid(row=1,column=4,sticky=tk.NS,rowspan=6)
# Create Listbox and get Y from scrollbar
self.thread_lb = tk.Listbox(self,yscrollcommand=self.lb_scrollY.set)
# Calls function whenever a new item is selected
self.thread_lb.bind('<<ListboxSelect>>',self.updateSelected)
# scrolly will change the view of listbox
self.lb_scrollY['command']=self.thread_lb.yview
self.thread_lb.grid(row=1,column=0,sticky=tk.NS+tk.EW,columnspan=4,rowspan=3)
self.threadFrame = tk.LabelFrame(main,text='Reddit')
self.threadLabelTitle = tk.Label(self.threadFrame,textvariable=self.threadTitle,wraplength=200).grid(row=1,column=2,sticky= tk.EW)
self.threadLabelAuth = tk.Label(self.threadFrame, textvariable=self.threadAuth,wraplength=200).grid(row=2,column=2,sticky = tk.EW)
self.threadLabelPub = tk.Label(self.threadFrame, textvariable=self.threadPub,wraplength=200).grid(row=3,column=2,sticky = tk.EW)
self.threadLabelArtLink = tk.Label(self.threadFrame, textvariable=self.threadArtLink,wraplength=200).grid(row=4,column=2,sticky = tk.EW)
self.threadLabelThreadLink = tk.Label(self.threadFrame, textvariable=self.threadLink,wraplength=200).grid(row=5,column=2,sticky = tk.EW)
self.threadImgLink = tk.Label(self.threadFrame, textvariable=self.threadImg,wraplength=200).grid(row=6,column=2,sticky = tk.EW)
# self.columnconfigure(2,minsize=200)
# self.rowconfigure(1,minsize=175)
self.threadFrame.pack()
self.QUIT = tk.Button(self, text="QUIT", fg="red", command=main.destroy,padx=5, pady=5).grid(row=7)
def updateSelected(self, event):
# getting selected listbox item
i=self.thread_lb.curselection()
# Returns tuple that must be split
x,y,z = re.split("\D+",str(i))
y=int(y)
print(self.threadTitleList[y])
print(self.threadPubDateList[y])
print(self.threadLinkList[y])
print(self.threadDescList[y])
self.threadTitle.set(self.threadTitleList[y])
self.threadAuth.set('Will have poster here')
self.threadPub.set(self.threadPubDateList[y])
self.threadArtLink.set(self.threadLinkList[y])
self.threadLink.set(self.threadDescList[y])
self.threadImg.set('Will put image here')
# # threadTitle = self.threadTitleList[y]
# print(self.threadLabelTitle["text"])
# # self.threadLabelTitle['text']=threadTitle
# self.threadLabelAutPub['text']=self.threadPubDateList[y]
# self.threadImgLink['text']=self.threadLinkList[y]
# self.threadLabelThreadLink['text']=self.threadDescList[y]
# main.update()
def descStripper(self,desc):
# Intialize values
l1,l2,l2Start = 0,0,0
t1,t2,t2start = 0,0,0
link = ""
thread = ""
# Where to start looking for each in description element
l1=int(desc.find('<br/> <a href="'))
t1=int(desc.find('</a> <a href="'))
# If both of the tags are found then continue
if l1 != -1 and t1 != -1:
# Start looking for end of quotes 16 characters from beginning of tag
l2Start = l1+16
l2=int(desc.find('"',l2Start))
# Link is created from what is in the quotes
link = desc[l1+15:l2]
# Same as above but to find thread link
t2start = t1+15
t2=int(desc.find('"',t2start))
thread = desc[t1+14:t2]
return link,thread
else:
# If it can't find one it will return an error
link = "Couldn't find the stuff :("
thread = "Couldn't find the thread link :("
return link, thread
def lbPopulator(self,title,pub,link):
# Delete old entries from listbox
self.thread_lb.delete(0,tk.END)
# Iterate through all the items and append them to the listbox
for item in title:
self.thread_lb.insert(tk.END,item)
def getXmlData(self):
# Intialize lists
self.threadPubDateList = []
self.threadTitleList = []
self.threadLinkList = []
self.threadDescList = []
self.threadThumbNailList = []
# Use the downloaded rss.xml for XML parsing
tree=ET.parse('rss.xml')
# define root as the base of the XML parsing tree
root=tree.getroot()
for channel in root:
# Iterate through all the channels
for SubChannel in channel:
# Iterate through all the items in the channel
if SubChannel.tag == 'item':
# If the SubChannel is called item then search for the items below
for threadInfo in SubChannel:
# iterate through all the items in the 'item'
if threadInfo.tag == 'title':
# append the tag from the title to the list
self.threadTitleList.append(threadInfo.text)
if threadInfo.tag == 'pubDate':
# Append the pubdate info to the list but remove excess characters
self.threadPubDateList.append(threadInfo.text[:-6])
if threadInfo.tag == 'description':
# Pass all the information from the description to the stripper to get the useful
# information and links
link,thread = self.descStripper(threadInfo.text)
self.threadLinkList.append(link)
self.threadDescList.append(thread)
# Populate the listbox with the newly generated lists
self.lbPopulator(self.threadTitleList,self.threadPubDateList,self.threadLinkList)
def getXML(self,subreddit):
try:
# Try to download the xml file using the user input subreddit
url = 'http://www.reddit.com'+subreddit+'.rss'
source = urllib.request.urlretrieve(url,'rss.xml')
self.getXmlData()
except urllib.error.HTTPError as err:
# Error caused by reddit API limiting connections
print('Too many requests-Try again')
def initial(self):
try:
# Same as above but downloads the front page
source = urllib.request.urlretrieve('http://www.reddit.com/.rss','rss.xml')
self.getXmlData()
except urllib.error.HTTPError as err:
print('Too many requests-Trying again 3')
# If error occurs program waits 3 seconds and then restarts
time.sleep(3)
self.__init__()
# main.geometry("350x400")
app = Application(master=main)
# Begins the applications GUI loop
app.mainloop()
答案 0 :(得分:3)
尝试使用此代码并使用place
方法代替pack
:
from tkinter import *
root=Tk()
mylabel = Label(root,text="This is my lablel.")
mylabel.place(x=30,y=30,height=20,width=100)
答案 1 :(得分:0)
在你的问题中没有足够的信息来确切地知道你想要什么,所以我猜你想要将带有文本“Reddit”的labelframe放在所有其他小部件的右侧。是对的吗?
如果是这样,问题在于这两行:
self.pack()
...
self.threadFrame.pack()
没有任何选项,pack会将内容置于包含小部件中任何空白区域的顶部。因此,self
填充窗口的顶部,在其下方留下空白区域。 self.threadFrame
位于空白区域的顶部,这就是为什么这两个小部件显示为堆叠的原因。
如果您尝试仅将第二个语句切换为使用网格,则GUI将像您报告一样挂起,因为当两个小部件具有相同的父级时,您不能同时使用网格和包。
为了让它们并排,一个简单的解决方法是在你打包时明确:
self.pack(side="left", fill="both", expand=False)
...
self.threadFrame.pack(side="right", fill="both", expand=True)
我使用expand会导致threadFrame
在调整窗口大小时增大和缩小。我不知道这是否是你想要的行为。您可以使用展开选项来查看它们在调整窗口大小时对窗口的影响。
只要您同时使用网格,就可以轻松使用网格来获得完全相同的结果:
self.grid(row=0, column=0, sticky="nsew")
...
self.threadFrame.grid(row=0, column=1, stick="nsew")
...
main.grid_columnconfigure(1, weight=1)
main.grid_rowconfigure(0, weight=1)
正如您所看到的,对于网格,您必须做一些额外的工作才能获得相同的调整大小行为。这就是为什么在应用程序的不同部分同时使用网格和包的好处:当你想要并排放置几个小部件或在垂直堆栈中时,pack非常好。当您有一个可以在行和列中指定的更复杂的布局时,网格很棒。正如我之前所说的那样,请确保不要将两个或更多小部件的网格和包装混合在同一个父级中。