Closing wxpython application hangs gui

I this application which has a long running task via ssh, which gets the stdout then prints this to a wx.TextCtrl, all this works fine. The problem I have is being able to quit the application, currently when I do the gui hangs. The long sunning ssh task should keep running on the remote server and I just want to close the application. How can I correctly break the while True loop and also the ssh task when pressing the Quit button?

import wx
import wx.stc as stc
from subprocess import Popen, PIPE, STDOUT
import sys
import spur
import threading
import select
import codecs
import os
import time
import io
class MainWindow(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(600, 500), style=wx.DEFAULT_FRAME_STYLE & ~ (wx.RESIZE_BORDER |
                                                wx.RESIZE_BOX |
                                                wx.MAXIMIZE_BOX))

        self.running_log = wx.TextCtrl(self, pos=(5, 5), size=(570,390))

        self.buttonGo = wx.Button(self, -1, "Go", pos=(180,420))
        self.buttonGo.Bind(wx.EVT_BUTTON, self.Go)
        self.buttonClose = wx.Button(self, -1, "Quit", pos=(285,420))
        self.buttonClose.Bind(wx.EVT_BUTTON, self.OnClose)
        self.Show()

        self.CreateStatusBar()
        menuBar = wx.MenuBar()
        menu = wx.Menu()
        self.SetMenuBar(menuBar)
        self.sshLog1 = sshLog(self)
        self.Centre()
        self.Show()

    def Go(self, event):
        threading.Thread(target=self.sshLog1.runCommand).start()
        threading.Thread(target=self.sshLog1.readlog1).start()

    def OnClose(self, e):
        sys.exit()
        CloseApp()

class sshLog(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        self.parent = parent
self.frame = self
def runCommand(self):
        self.output_file = io.BytesIO()
        shell = spur.SshShell(hostname='10.0.1.1', username='remoteUsername', password='remotePassword', missing_host_key=spur.ssh.MissingHostKey.accept)
        process = shell.spawn(['ping', 'google.com', '-t'], stdout=self.output_file)
        process.wait_for_result()

    def readlog1(self):
        while True:
            time.sleep(1)
            wx.CallAfter(self.readlog2)

    def readlog2(self):
        last_line = str(self.output_file.getvalue())
        wx.CallAfter(self.parent.running_log.AppendText, last_line)

<details class='elided'>
<summary title='Show trimmed content'>&#183;&#183;&#183;</summary>

###############################
########## CLOSE APP ##########
###############################
class CloseApp(wx.Frame):
    def __init__(e):
        sys.exit(0)

app = wx.App()
MainWindow(None, -1, 'My App')
app.MainLoop()

You can’t break a “while True” loop. You have to provide a way for the loop to exit:

while self.LoopContinue:

Then, when you want the thread to die, you set self.sshLog1.LoopContinue to false.

However, that won’t end the other thread, which is blocking in “process.wait_for_result()”. If you want that to be interruptible, you would have to change that into a loop as well. However, since you don’t really DO anything after the process exits, why do you wait for it to exit at all? Just spawn the process and return immediately.

Also, you have this:

def OnClose(self, e):

sys.exit(0)

CloseApp()

Nothing is going to run after the sys.exit. That is not a friendly way to kill a wxPython application, because it bypasses the windowing system altogether. What you need to do is just let the normal close handler do its thing, after you signal your thread to exit:

def OnClose(self, e):

self.sshLog1.LoopContinue = false

e.Skip()

···

On Jul 11, 2015, at 5:01 AM, kevjwells kevjwells@gmail.com wrote:

I this application which has a long running task via ssh, which gets the stdout then prints this to a wx.TextCtrl, all this works fine. The problem I have is being able to quit the application, currently when I do the gui hangs. The long sunning ssh task should keep running on the remote server and I just want to close the application. How can I correctly break the while True loop and also the ssh task when pressing the Quit button?


Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

It’s also worth pointing out that the second CallAfter here is silly. readlog2 is already going to be running in the main thread’s context, because it was invoked through wx.CallAfter. Just call AppendText directly.

···

On Jul 11, 2015, at 5:01 AM, kevjwells kevjwells@gmail.com wrote:

    def readlog1(self):
        while True:
            time.sleep(1)
            wx.CallAfter(self.readlog2)

    def readlog2(self):
        last_line = str(self.output_file.getvalue())
        wx.CallAfter(self.parent.running_log.AppendText, last_line)


Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Both excellent answers, many thanks, now works a treat.

Kind regards.