将ssh_client对象从Login类传递到MainWindow类

时间:2019-06-02 03:59:09

标签: python tkinter paramiko

我正在构建一个GUI,该GUI需要我通过ssh登录到远程计算机。我正在使用paramiko来做到这一点。

我想要实现的是启动应用程序时显示一个登录窗口。用户必须输入一些凭证。如果登录成功,则显示应用程序的主窗口。如果登录失败,请保留在登录窗口。

如果登录成功,我希望将ssh_client对象传递给MainWindow类,以便可以使用已建立的连接在远程计算机上执行任务。但是,如何将ssh_client对象传递给MainWindow?

以下代码将运行,但不会尝试使用已建立的ssh_client。要如何在MainWindow的Login中使用ssh_client?

也许我应该只在MainWindow中重新建立连接-然后我需要将凭据传递给MainWindow,这似乎是我现在遇到的同类问题。

import Tkinter as tk
import paramiko
import time


class Application(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        container = tk.Frame(self)
        container.grid(row=0, column=0, sticky="nsew")
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}
        for F in (Login, MainWindow):
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(Login)

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


class Login(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.ssh_client = paramiko.SSHClient()
        self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        self.parent = parent
        self.controller = controller
        self.grid(row=0, column=0)

        self.user = tk.StringVar()
        self.user.set("my_username")  # Default user

        self.host_options = ["host1", "host2"]
        self.host = tk.StringVar()
        self.host.set(self.host_options[0])  # Default hostname

        l_user = tk.Label(self, text="Username: ")
        l_user.grid(row=0, column=0, sticky=tk.E)

        self.entry_user = tk.Entry(self)
        self.entry_user.grid(row=0, column=1, sticky=tk.W)
        self.entry_user.insert(0, self.user.get())

        l_pwd = tk.Label(self, text="Password: ")
        l_pwd.grid(row=1, column=0, sticky=tk.E)

        self.entry_pwd = tk.Entry(self, show="*")
        self.entry_pwd.grid(row=1, column=1, sticky=tk.W)

        l_host = tk.Label(self, text="Hostname: ")
        l_host.grid(row=2, column=0, sticky=tk.E)

        optionmenu_host = tk.OptionMenu(self, self.host, *self.host_options)
        optionmenu_host.grid(row=2, column=1, sticky=tk.W)

        b_login = tk.Button(self, text="Log in", command=self.authorize)
        b_login.grid(row=3, column=0, sticky=tk.W)

        b_quit = tk.Button(self, text="Quit", command=self.parent.destroy)
        b_quit.grid(row=4, column=0, sticky=tk.W)

    def authorize(self):
        try:
            self.ssh_client.connect(hostname=self.host.get(), username=self.entry_user.get(), password=self.entry_pwd.get())
            self.controller.show_frame(MainWindow)
        except paramiko.AuthenticationException:
            l_error = tk.Label(self, text="Login failed...", fg="red")
            l_error.grid(row=4, column=1, sticky=tk.W)
            l_error.after(2000, l_error.destroy)


class MainWindow(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.grid(row=0, column=0)

        l = tk.Label(self, text="Log in was successful!")
        l.grid(row=0, column=0, sticky=tk.W)


###################################
# run application
if __name__ == "__main__":
    app = Application()
    app.mainloop()
###################################

1 个答案:

答案 0 :(得分:0)

这就是我的意思,还有其他一些改进:

  • tkinter从不使用* args;当您继承子类时,您不需要它。
  • tkinter经常使用** kwargs;当您继承子类时,请不要忽略它!
  • 没有指向容器Frame的提示……它除了增加复杂性之外什么也没做
  • 如果同时将两个框架都网格化,则窗口始终是最大尺寸。要动态调整大小,您需要重新栅格化。
  • 当您有几十个帧时,使用帧字典是不错的选择,但是对于只有2个帧,我只会使用常规方法。
  • Tkinter将您所说的“父级”称为“母版”,它会自动设置self.master = master,因此您不需要该行。

我无法对此进行测试,所以请告诉我它是如何工作的。

import Tkinter as tk
import paramiko
import time

class Application(tk.Tk):
    def __init__(self, **kwargs):
        tk.Tk.__init__(self, **kwargs)

        self.ssh_client = paramiko.SSHClient()
        self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        self.login_window = Login(self)
        self.main_window = MainWindow(self)

        self.show_login() # set starting point

    def show_login(self):
        self.main_window.pack_forget()
        self.login_window.pack()

    def show_main(self):
        self.login_window.pack_forget()
        self.main_window.pack()

class Login(tk.Frame):
    def __init__(self, parent, **kwargs):
        tk.Frame.__init__(self, parent, **kwargs)

        self.user = tk.StringVar()
        self.user.set("my_username")  # Default user

        self.host_options = ["host1", "host2"]
        self.host = tk.StringVar()
        self.host.set(self.host_options[0])  # Default hostname

        l_user = tk.Label(self, text="Username: ")
        l_user.grid(row=0, column=0, sticky=tk.E)

        self.entry_user = tk.Entry(self)
        self.entry_user.grid(row=0, column=1, sticky=tk.W)
        self.entry_user.insert(0, self.user.get())

        l_pwd = tk.Label(self, text="Password: ")
        l_pwd.grid(row=1, column=0, sticky=tk.E)

        self.entry_pwd = tk.Entry(self, show="*")
        self.entry_pwd.grid(row=1, column=1, sticky=tk.W)

        l_host = tk.Label(self, text="Hostname: ")
        l_host.grid(row=2, column=0, sticky=tk.E)

        optionmenu_host = tk.OptionMenu(self, self.host, *self.host_options)
        optionmenu_host.grid(row=2, column=1, sticky=tk.W)

        b_login = tk.Button(self, text="Log in", command=self.authorize)
        b_login.grid(row=3, column=0, sticky=tk.W)

        b_quit = tk.Button(self, text="Quit", command=self.quit)
        b_quit.grid(row=4, column=0, sticky=tk.W)

    def authorize(self):
        try:
            self.master.ssh_client.connect(hostname=self.host.get(), username=self.entry_user.get(), password=self.entry_pwd.get())
            self.master.show_main()
        except paramiko.AuthenticationException:
            l_error = tk.Label(self, text="Login failed...", fg="red")
            l_error.grid(row=4, column=1, sticky=tk.W)
            l_error.after(2000, l_error.destroy)

class MainWindow(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)

        l = tk.Label(self, text="Log in was successful!")
        l.grid(row=0, column=0, sticky=tk.W)

        # you can use the ssh client like this:
        print(self.master.ssh_client)

        # or like this:
        self.ssh_client = self.master.ssh_client
        print(self.ssh_client)

###################################
# run application
if __name__ == "__main__":
    app = Application()
    app.mainloop()
###################################