【问题标题】:Python 3.3 Tkinter change LabelFrame PositionPython 3.3 Tkinter 更改 LabelFrame 位置
【发布时间】:2013-12-16 19:24:04
【问题描述】:

我试图在其他一些小部件旁边放置一个标签框,但我根本无法弄清楚。目前,当我使用 .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()

【问题讨论】:

  • @iCodez 不,没必要这样做。使用 place 而不是 pack 方法就足够了!
  • 只是清理它。我两个都用过,而且运行良好,当我尝试只使用一个时,我遇到了问题
  • 当 gui 挂起时,通常是因为您在同一个容器中同时使用了 grid 和 pack(例如:框架、顶层或根窗口)。没有看到代码就不可能确定。

标签: python python-3.x tkinter frame


【解决方案1】:

试试这段代码并使用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)

【讨论】:

  • 请注意,这里的 tk 窗口是我的标签容器,您可以放置​​框架容器或任何您想要的东西而不是 root!
  • 谢谢!完全不同的方法,但它很有效,而且简单易行,再次感谢您!
  • 我绝不会推荐放置在网格或包装上,除非在极少数情况下。
  • @BryanOakley 但他想将标签放在某个坐标中,所以他应该使用 place 而没有其他选择。
  • @HamidFzM:“在其他几个小部件旁边放置一个标签框”与“我想在某个坐标处放置一个标签”不同。在正常情况下,如果您完全担心小部件具有适当的调整大小行为、不同字体和分辨率的适当行为等,那么使用 place 比其他方式更难使用。
【解决方案2】:

您的问题中没有足够的信息来确切地知道您想要什么,所以我猜您希望带有文本“Reddit”的标签框位于所有其他小部件的右侧。那正确吗?

如果是这样,问题出在这两行:

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)

如您所见,使用网格您必须做一些额外的工作才能获得相同的调整大小行为。这就是为什么在应用程序的不同部分同时使用 grid 和 pack 很好的原因:当您想将几个小部件并排或放在垂直堆栈中时,pack 非常有用。当您有可以在行和列中指定的更复杂的布局时,网格非常有用。但是,正如我之前所说,请确保不要将网格和打包两个或多个具有相同父级的小部件混合使用。

【讨论】:

  • @HamidFzM:我猜你是对这个答案投反对票的人。如果我是正确的,并且您认为我的答案是错误的,或者认为我可以写得更好,您是否会好心地建议我如何使我的答案更好?谢谢!
猜你喜欢
  • 2021-12-19
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 2018-04-05
  • 2013-11-05
  • 1970-01-01
  • 2012-04-03
  • 2022-12-04
相关资源
最近更新 更多