我有如下代码,它会截取屏幕截图并记录击键和鼠标移动。它使用 wxpython 作为 GUI 框架。我使用 Python 线程进行截图和记录服务。但是,无论何时我关闭 GUI 应用程序。线程仍然在运行。如何在我关闭应用程序后停止这些线程?
import wx
import threading
import sys
import subprocess
import time
from pymouse import PyMouse
from pymouse import PyMouseEvent
from pykeyboard import PyKeyboard
from pykeyboard import PyKeyboardEvent
import pyscreenshot as ImageGrab
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
import gtk.gdk
import urllib2, urllib
import Cookie
MouseMovesCount = 0
MouseClicksCount = 0
KeyStrokesCount = 0
class OD_App(wx.App):
def OnInit(self):
frame = OD_MainFrame ("Login", (0, 0), (350, 200))
self.SetTopWindow(frame)
loginPanel = OD_LoginPanel (frame)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
frame.Show()
return True
def OnCloseWindow (self, event):
self.Destroy()
class OD_MainFrame(wx.Frame):
def __init__(self, title, pos, size):
wx.Frame.__init__(self, None, -1, title, pos, size)
self.CreateStatusBar()
class OD_LoginPanel(wx.Panel):
def __init__(self, frame):
self.panel = wx.Panel(frame)
self.frame = frame
self.frame.SetStatusText("Authentication required!")
self.showLoginBox()
def showLoginBox (self):
# Create the sizer
sizer = wx.FlexGridSizer(rows=3, cols=2, hgap=5, vgap=15)
# Username
self.txt_Username = wx.TextCtrl(self.panel, 1, size=(150, -1))
lbl_Username = wx.StaticText(self.panel, -1, "Username:")
sizer.Add(lbl_Username,0, wx.LEFT|wx.TOP| wx.RIGHT, 50)
sizer.Add(self.txt_Username,0, wx.TOP| wx.RIGHT, 50)
# Password
self.txt_Password = wx.TextCtrl(self.panel, 1, size=(150, -1), style=wx.TE_PASSWORD)
lbl_Password = wx.StaticText(self.panel, -1, "Password:")
sizer.Add(lbl_Password,0, wx.LEFT|wx.RIGHT, 50)
sizer.Add(self.txt_Password,0, wx.RIGHT, 50)
# Submit button
btn_Process = wx.Button(self.panel, -1, "&Login")
self.panel.Bind(wx.EVT_BUTTON, self.OnSubmit, btn_Process)
sizer.Add(btn_Process,0, wx.LEFT, 50)
self.panel.SetSizer(sizer)
def OnSubmit(self, event):
username = self.txt_Username.GetValue()
password = self.txt_Password.GetValue()
mydata = [('username',username),('password',password)]
mydata = urllib.urlencode(mydata)
path = 'http://xyz/logincheck.php' #temporary db for testing
req = urllib2.Request(path, mydata)
req.add_header("Content-type", "application/x-www-form-urlencoded")
page = urllib2.urlopen(req).read()
if page == "true":
self.frame.SetStatusText("Authentication Success!")
self.show_other(username)
else:
self.frame.SetStatusText("Authentication Failed!")
def OnCloseWindow (self, event):
self.Destroy()
def show_other(self,username):
self.frame.Destroy()
userpanel = OD_UserPanel()
return True
class OD_UserPanel(wx.App):
def OnInit(self):
userpanel = wx.Frame(None,-1)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
#user_greeting = 'Welcome ' + username + '!'
#username = wx.StaticText(userpanel, -1, user_greeting , style=wx.ALIGN_CENTRE)
userpanel.Show()
mouse_eventer = mouse_event()
mouse_eventer.start()
keyboard_eventer = key_event()
keyboard_eventer.start()
screenshot_eventer = screenshot_thread()
screenshot_eventer.start()
return True
def OnCloseWindow (self, event):
quit()
event.Skip()
raise SystemExit
class mouse_event(PyMouseEvent):
def move(self, x, y):
global MouseMovesCount
MouseMovesCount = MouseMovesCount + 1
print MouseMovesCount
def click(self, x, y, button, press):
global MouseClicksCount
if press:
MouseClicksCount = MouseClicksCount + 1
print MouseClicksCount
else:
MouseClicksCount = MouseClicksCount + 1
print MouseClicksCount
class key_event(PyKeyboardEvent):
global screenshot_eventer
def key_press(self, key):
global KeyStrokesCount
KeyStrokesCount = KeyStrokesCount + 1
print KeyStrokesCount
def key_release(self, key):
global KeyStrokesCount
KeyStrokesCount = KeyStrokesCount + 1
print KeyStrokesCount
class screenshot_thread(threading.Thread):
def __init__(self):
super(screenshot_thread, self).__init__()
self.state = True
# Attributes
def run(self):
self.take_shot()
def stop(self):
self.state = False
threading.Thread._Thread__stop()
def take_shot(self):
while self.state==True:
time.sleep(10)
subprocess.call(['scrot'])
if __name__ == '__main__':
app = OD_App()
app.MainLoop()
2、解决方案
一种解决方法是在创建线程时将它们设置为守护线程。这将导致它们在主应用程序退出时自动退出。可以这样做:
class screenshot_thread(threading.Thread):
def __init__(self):
super(screenshot_thread, self).__init__()
self.daemon = True # Set thread as daemon
另一种解决方法是在关闭应用程序时显式地停止线程。可以这样做:
import threading
class screenshot_thread(threading.Thread):
def __init__(self):
super(screenshot_thread, self).__init__()
self.state = True
def run(self):
while self.state:
time.sleep(10)
subprocess.call(['scrot'])
def stop(self):
self.state = False
threading.Thread._Thread__stop()
if __name__ == '__main__':
app = OD_App()
screenshot_thread = screenshot_thread()
screenshot_thread.start()
app.MainLoop()
screenshot_thread.stop()