I am trying to create a tkinter GUI that will essentially function as an SSH connection to a remote linux computer. The GUI needs to be functional on a windows operating system. The GUI has a few buttons that allows the user to start and stop programs on the linux computer but I am having issues printing a continuous output from this remote program to tkinter. I essentially want to have a embedded window, in a tkinter GUI, that shows the command line output from the remote desktop.
In the code below I successfully call my GUI class and build the tkinter GUI. Using paramiko I can successfully establish an SSH connection but the issue is when I press "Start Script". Start script successfully starts the program over an SSH connection, but I can not print a continuous output to the GUI (to test this the main_script.py is a basic program that just prints a increasing number every 3 seconds). I believe the issue is that I stall the tkinter mainloop but I do not know how to address this issue. I can use the tkinter.after command to update the window after a delay but because of how I read stdout my script is still stalled. Is there a better way to read stdout? Do I need to call a subprocess or use multithreading (if so how do I do this when I would like to establish the SSH connection when the main_window opens). Or am I missing a much simpler way to essentially have a remote desktop command line output with a few GUI buttons? Thanks for any help.
import paramiko
import tkinter as tk
class main_window():
def __init__(self, root2, ip, user, pword):
self.root2 = root2
# Connection Label
conn_label = tk.Label(root2, text=str('CONNECTED TO: ' + user + ' ' + 'ON: ' + ip))
conn_label.grid(row=0, columnspan=6, sticky=tk.W)
# Frequency Entery
freq_label = tk.Label(root2, text='Tag Frequency:')
freq_entry = tk.Entry(root2)
self.freq_enter_button = tk.Button(root2, text='Enter')
freq_label.grid(row=1, column=1, sticky=tk.E, padx=(5, 0))
freq_entry.grid(row=1, column=2, sticky=tk.W)
self.freq_enter_button.grid(row=1, column=3, padx=5)
# Scroll Bar and Command Line Ouput
self.scrollbar = tk.Scrollbar(root2)
self.scrollbar.grid(row=3, column=5, rowspan=1, sticky=tk.N+tk.S)
self.mylist = tk.Listbox(root2, yscrollcommand=self.scrollbar.set)
self.mylist.grid(row=3, column=0, columnspan=5, sticky=tk.W+tk.E+tk.N+tk.S)
# SSH Connection
self.ssh = paramiko.SSHClient()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.ssh.connect(ip, port=22, username=user, password=pword)
# stdin, stdout, stderr = ssh.exec_command('ls')
# for line in stdout:
# mylist.insert(tk.END, str('... ' + line.strip('\n')))
# ssh.close()
# Start Script Button
self.script_btn = tk.Button(root2, text="Start Script", command=self.toggle)
self.script_btn.grid(row=2, column=1, columnspan=3, sticky=tk.W+tk.E, padx=(10, 8), pady=2)
# Customize Grid Expansion
root2.columnconfigure(0, weight=1)
root2.columnconfigure(4, weight=1)
root2.rowconfigure(3, weight=1)
# Visual Touches
root2.title("Terminal Connection")
root2.wm_iconbitmap('logo_blue.ico')
def toggle(self):
def_color = self.freq_enter_button.cget('bg')
if self.script_btn.config('text')[-1] == 'Start Script':
stdin, self.stdout, stderr = self.ssh.exec_command('python main_script.py', get_pty=True)
self.mylist.insert(tk.END, str('Starting Script\n'))
self.script_btn.config(text='End Script', bg='red')
self.update_window()
else:
stdin, self.stdout, stderr = self.ssh.exec_command(chr(3))
self.mylist.insert(tk.END, str('Ending Script\n'))
self.script_btn.config(text='Start Script', bg=def_color)
def update_window(self):
for line in iter(lambda: self.stdout.readline(), ""):
self.mylist.insert(tk.END, str(line))
self.scrollbar.config(command=self.mylist.yview)
# self.root2.after(1000, self.update_window)
def main():
root = tk.Tk()
IP = '*********'
user = '*******'
pswd = '*******'
runGUI = main_window(root, IP, user, pswd)
root.title("Connect to Drone")
root.wm_iconbitmap('logo_blue.ico')
root.mainloop()
if __name__ == "__main__":
main()