TkInter-无法使框架正常工作并调整其大小

时间:2019-08-20 23:28:21

标签: python-3.x tkinter

TkInter的帧让我发疯。我的目标是要有一个选项框,在其中可以选择一些选项,然后按“存档”,然后TkInter窗口将更改为显示脚本其余部分的输出。

我无法正确调整其大小-窗口中似乎还有一些额外的框架占用了空间。

import string
from tkinter import *
import tkinter as tk
import threading

def main(argv):
    print("In Main")
    for arg in argv:
        print(arg)

class TextOut(tk.Text):

    def write(self, s):
        self.insert(tk.CURRENT, s)
        self.see(tk.END)

    def flush(self):
        pass

class Mainframe(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self._frame = OptionsFrame(self)
        self._frame.pack(expand=True)

    def change(self, frameClass):
        # make new frame - for archive output
        self._frame = frameClass(self)
        self._frame.pack(fill="both", expand=True)
        return self._frame

class Mainframe(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self._frame = OptionsFrame(self)
        self._frame.pack(expand=True)

    def change(self, newFrameClass):
        # make new frame - for archive output
        self._frame = newFrameClass(self)
        self._frame.pack(fill="both", expand=True)
        return self._frame

class OptionsFrame(tk.Frame):
    def __init__(self, master=None, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)

        master.title("Test")
        master.geometry("325x180")
        self.selectedProject = None
        self.initUI(master)

    def initUI(self, master):

        frame1 = Frame(master)
        frame1.pack(fill=BOTH, expand=True)

        self.label1 = Label(frame1, text="Select Project to Archive, then click Archive")

        self.projectListbox = tk.Listbox(frame1, width=60, height=100)
        self.projectListbox.bind("<<ProjectSelected>>", self.changeProject)

        # create a vertical scrollbar for the listbox to the right of the listbox
        self.yscroll = tk.Scrollbar(self.projectListbox,command=self.projectListbox.yview,orient=tk.VERTICAL)
        self.projectListbox.configure(yscrollcommand=self.yscroll.set)

        # Archive button
        self.archiveBtn=tk.Button(frame1,text="Archive",command=self.ArchiveButtonClick)

        # Do layout
        self.label1.pack()
        self.projectListbox.pack(fill="both", expand=True)
        self.yscroll.pack(side="right", fill="y")
        self.archiveBtn.pack(side="bottom", pady=10, expand=False)

        choices = ["test 1", "test 2", "test 3", "test 4", "test 5", "test 6"]
        # load listbox with sorted data
        for item in choices:
            self.projectListbox.insert(tk.END, item)

    def getSelectedProject(self):
        # get selected line index
        index = self.projectListbox.curselection()[0]
        # get the line's text
        return self.projectListbox.get(index)

    # on change dropdown value
    def changeProject(self,*args):
        self.selectedProject = self.getSelectedProject()

    def ArchiveButtonClick(self):
        # Switch to second frame - for running the archive
        self.changeProject(None)
        # Hide existing controls
        self.label1.pack_forget()
        self.projectListbox.pack_forget()
        self.yscroll.pack_forget()
        self.archiveBtn.pack_forget()

        newFrame = self.master.change(ArchivingOutputFrame)
        newFrame.args = [ "-n", self.selectedProject]
        newFrame.start()

# Frame shown while archive task is running
class ArchivingOutputFrame(tk.Frame):
    def __init__(self, master=None, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        master.title("Test Frame 2")
        master.geometry("1000x600")
        # Set up for standard output in window
        self.var = tk.StringVar(self)
        lbl = tk.Label(self, textvariable=self.var)
        #lbl.grid(row=0, column=0)
        lbl.pack(anchor="nw")

    def start(self):
        t = threading.Thread(target=self.process)
        t.start()

    def process(self):
        main(self.args)

if __name__=="__main__":
    # If command line options passed - skip the UI
    if len(sys.argv) > 1:
        main(sys.argv[1:])
    else:
        app=Mainframe()
        text = TextOut(app)
        sys.stdout = text
        sys.stderr = text
        text.pack(expand=True, fill=tk.BOTH)
        app.mainloop()

这是我在用户界面中得到的;请注意,这显示了Microsoft Spy ++的UI层次结构-在窗口的底部有一个我没有创建的框架(至少我不认为我做了),它占据了UI区域的一半;这是黄色的亮点。我的选项窗格因此被压缩到上半部分。
UI regions

调整大小也不起作用-如果我调整窗口大小,则会得到以下提示:

Resized window only growing bottom

当我单击按钮和代码以删除选项框架并将其放入从主脚本运行中捕获stdout / stderr的框架时,我得到以下信息:

UI from stdout

现在,多余的空间似乎在顶部!

感谢任何想法-我知道我可以切换到使用“网格” UI布局引擎,但这似乎很简单-我没有在这里做任何不适用于pack的复杂工作。

1 个答案:

答案 0 :(得分:1)

那是很多复杂的代码。如果提供Minimal, Complete, and Verifiable example,调试起来会更容易。

但是;底部的Frame是在Mainframe()之后打包的TextOut()小部件:

if __name__=="__main__":
    app = Mainframe()
    text = TextOut(app)  # This one
    sys.stdout = text
    sys.stderr = text
    text.pack(expand=True, fill=tk.BOTH)
    app.mainloop()

如果为每个小部件赋予bg颜色,然后为它们提供全部填充,则调试起来会更容易,这样您就可以更轻松地识别哪个小部件位于哪个小部件内。