2013-12-16 3 views
1

Я пытаюсь поставить labelframe рядом с несколькими другими виджетами, но я не могу понять это вообще. В настоящее время он отображается под всеми другими виджетами, когда я использую метод .pack(). Когда я пытаюсь настроить позицию с помощью .grid (column = x, row = y), тогда программа запускается, но зависает, и GUI не появляется.Python 3.3 Tkinter change LabelFrame Position

Вот код Релевент

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

@iCodez Нет, это не нужно делать. Использование места вместо метода пакета достаточно! –

+0

Просто очистите его. Я использовал оба варианта, и это было нормально, когда я пытался использовать только один, который я столкнулся с проблемой – ddaniels

+0

Когда gui зависает, довольно часто это происходит из-за того, что вы используете как сетку, так и пакет внутри одного контейнера (например: frame, toplevel , или корневое окно). Не видя кода, нельзя сказать точно. –

ответ

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) 
+0

Просто обратите внимание, что здесь tk window - это мой контейнер с этикетками, вы можете поместить контейнер рамки или все, что хотите, вместо корня! –

+0

Спасибо! Совершенно другой подход, но он работает, и это просто и легко, спасибо вам снова! – ddaniels

+0

Я бы никогда не рекомендовал место по сетке или упаковке, за исключением очень редких случаев. –

0

Существует не достаточно информации в вашем вопросе, чтобы точно знать, что вы хотите, так что я предполагаю, что вы хотите labelframe с текстом «Reddit», чтобы быть справа от всех других виджетов. это правильно?

Если да, то проблема в том, что из этих двух линий:

self.pack() 
... 
self.threadFrame.pack() 

Без каких-либо опций, пакет размещает вещи в верхней части любого пустого пространства в содержащем виджете. Итак, self заполняет верхнюю часть окна, оставляя пустое пространство под ним. self.threadFrame находится в верхней части пустого пространства, поэтому эти два виджета выглядят сложными.

Если вы попытались переключить только второе утверждение на использование сетки, графический интерфейс будет висеть так же, как вы сообщаете, потому что вы не можете использовать сетку и пакет, если у двух виджетов один и тот же родитель.

Чтобы получить их бок о бок, простое исправление должно быть явным, когда вы упаковки:

self.pack(side="left", fill="both", expand=False) 
... 
self.threadFrame.pack(side="right", fill="both", expand=True) 

Мое использование расширения заставит threadFrame расти и сжиматься при изменении размеров окна. Я не знаю, это то, что вы хотите или нет. Вы можете поиграть с параметрами expand, чтобы увидеть, как они влияют на окно при изменении размера.

Вы можете так же легко использовать сетку, чтобы получить тот же результат, до тех пор, пока вы используете сетку для обоих:

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) 

Как вы можете видеть, с сеткой, вы должны сделать немного дополнительной работы получить такое же изменение размера. Вот почему хорошо использовать как сетку, так и пакет в разных частях приложения: пакет отлично подходит, если вы хотите поместить пару виджетов бок о бок или в вертикальный стек. сетка великолепна, когда у вас более сложный макет, который может быть указан в строках и столбцах. Однако, как я сказал ранее, просто убедитесь, что вы не смешиваете сетку и пакет для двух или более виджетов с одним и тем же родителем.

+0

@HamidFzM: Я предполагаю, это тот, который проголосовал за этот ответ. Если я прав, и вы думаете, что мой ответ неправильный или я думаю, что мог бы написать его лучше, не могли бы вы быть любезными, чтобы предложить, как я могу лучше ответить? Благодаря! –

Смежные вопросы