获取一个函数来“等待”多帧Tkinder应用程序中的值

时间:2017-05-03 19:37:55

标签: python tkinter

我有一个在TeamCity中创建构建的脚本。我正在尝试创建一个使用Tkinder完成此操作的gui。有多个步骤(即获取凭据 - >输入buildname - >添加模板 - >等),因此我使用多个框架使用show_frame()命令创建步骤。我的问题如下:我进行了多次REST调用,因此第一步是获取用户的用户名和密码。但是,由于所有页面在程序启动时都已初始化,因此所有使REST调用的方法都会出错,因为它们还没有凭据。

如何让后续步骤(及其方法)等待用户输入用户名和密码?

从下面的代码中,(在PageOne类中)我试图通过REST调用从BitBcuket获取项目列表,这样我就可以动态地将菜单项添加到菜单中,但我无法弄清楚如何等待获取用户名和密码。

import json
import requests
import Tkinter as tk
import tkMessageBox

TITLE_FONT = ("Arial", 18, "bold")


class CreateBuild(tk.Tk):
    def __init__(self, *args, **kwargs):
        self.username = None
        self.password = None
        self.bit_projects = None
        tk.Tk.__init__(self, *args, **kwargs)
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}
        for F in (StartPage, PageOne, PageTwo):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("StartPage")

    def show_frame(self, page_name):
        frame = self.frames[page_name]
        frame.tkraise()

    def authenticate(self, username, password):
        r = requests.head('https://source.amirsys-int.com/projects', auth=(username, password))
        if r.status_code == 405:
            self.username = username
            self.password = password
            self.show_frame("PageOne")
        else:
            tkMessageBox.showinfo("Error", "Incorrect username and/or password.\nPlease enter your Crowd username and "
                                           "password.")

    def get_bitbucket_projects(self):
        r = requests.get('https://source.amirsys-int.com/rest/api/1.0/projects', auth=(self.username,
                                                                                       self.password))
        j = json.loads(r.text)
        size = j['size']
        repo_dic = {}
        for i in range(0, size):
            name = j['values'][i]['name']
            repo_id = j['values'][i]['key']
            repo_dic[name] = repo_id

        self.bit_project = repo_dic


class StartPage(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        instructions = tk.Label(self, text="Please enter your Crowd credentials", font=TITLE_FONT)
        instructions.grid(column=1, row=1, columnspan=3, padx=30, pady=30)
        username = tk.Label(self, text="Crowd Username: ")
        username.grid(column=1, row=2, columnspan=2)
        password = tk.Label(self, text="Crowd Password: ")
        password.grid(column=1, row=3, columnspan=2)
        username_entry = tk.Entry(self)
        username_entry.grid(column=3, row=2)
        password_entry = tk.Entry(self, show="*")
        password_entry.grid(column=3, row=3)
        button = tk.Button(self, text="Next", command=lambda: controller.authenticate(username_entry.get(),
                                                                                      password_entry.get()))
        button.grid(column=4, row=4, padx=10, pady=10)
        self.grid_rowconfigure(5, weight=1)
        self.grid_columnconfigure(5, weight=1)


class PageOne(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        instructions = tk.Label(self, text="Enter build information", font=TITLE_FONT)
        instructions.grid(column=1, row=1, columnspan=3, padx=30, pady=30)
        build_name = tk.Label(self, text="Build Name: ")
        build_name.grid(column=1, row=2, columnspan=2)
        build_name_entry = tk.Entry(self)
        build_name_entry.grid(column=3, row=2)

        project_key = tk.Label(self, text="BitBucket Project: ", anchor="w")
        project_key.grid(column=1, row=3, columnspan=2)
        project_menu = tk.Menubutton(self, text="Project", anchor="w")
        project_menu.grid(column=3, row=3, columnspan=2)
        project_menu.menu = tk.Menu(project_menu)

        for key, value in controller.bit_projects:
            project_menu.menu.add_checkbutton(label=key, variable=value)

        self.grid_rowconfigure(4, weight=1)
        self.grid_columnconfigure(4, weight=1)


class PageTwo(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller


if __name__ == "__main__":
    app = CreateBuild()
    app.geometry("800x600")
    app.title("Create TeamCity Build")
    app.mainloop()

1 个答案:

答案 0 :(得分:1)

您需要将该代码移出__init__方法(在程序启动时运行),并移动到显示框架时调用的方法:tkraise()。

class PageOne(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        instructions = tk.Label(self, text="Enter build information", font=TITLE_FONT)
        instructions.grid(column=1, row=1, columnspan=3, padx=30, pady=30)
        build_name = tk.Label(self, text="Build Name: ")
        build_name.grid(column=1, row=2, columnspan=2)
        build_name_entry = tk.Entry(self)
        build_name_entry.grid(column=3, row=2)

        project_key = tk.Label(self, text="BitBucket Project: ", anchor="w")
        project_key.grid(column=1, row=3, columnspan=2)
        self.project_menu = tk.Menubutton(self, text="Project", anchor="w")
        self.project_menu.grid(column=3, row=3, columnspan=2)
        self.project_menu.menu = tk.Menu(self.project_menu)

        self.grid_rowconfigure(4, weight=1)
        self.grid_columnconfigure(4, weight=1)

    def tkraise(self):
        for key, value in self.controller.bit_projects:
            self.project_menu.menu.add_checkbutton(label=key, variable=value)
        tk.Frame.tkraise(self) # call the superclass to actually raise the frame