【问题标题】:Problems stopping a thread when signaled from a menu event?从菜单事件发出信号时停止线程的问题?
【发布时间】:2011-03-27 00:15:14
【问题描述】:

这个样本来自我正在从事的一个项目。如果在其视图中检测到运动,我的客户使用软件,该软件使用他的网络摄像头拍摄快照。问题是该软件无法在拍摄图像时将图像通过电子邮件发送到他的帐户。我编写了这个项目来监视保存快照的文件夹,并将其设置为通过电子邮件将任何新快照发送到定义的帐户,这样他就会在他的手机上收到警报,以及快照什么被抓住了运动。是的,我知道有许多应用程序在他们的网络摄像头软件中包含此功能,但我的客户聘请了我,这样他就可以避免更换他当前的软件,因为他使用起来很舒服。

Start() 函数有两个步骤。第 1 步是监视器启动前的延迟,第 2 步是监视器本身的启动。到目前为止,我无法让 Stop() 函数从 GUI 的状态栏中的倒计时中终止步骤 1。

Monitor.Stop() 函数在控制台中单独运行时可以正常工作,但在界面中的 self.OnConnect() 事件处理程序中运行时它不起作用?我尝试了多种线程结构的变体:threading、thread、kthread 等,但都以相同的结果结束。

理想情况下,我想单击“文件”菜单下的“连接”->“连接”标签更改为“断开连接”->“监视器”从第 1 步开始->“状态栏”显示距离第 2 步的剩余时间。

此时我希望能够通过点击“文件”菜单下的“断开连接”来停止倒计时,但是当我单击它时,倒计时继续进行?我尝试过的线程函数的每个变体在从控制台运行时都成功地停止了线程,但到目前为止我无法弄清楚为什么从我的 gui 中调用倒计时无法停止?

任何帮助将不胜感激! :D

顺便说一句,如果您选择运行脚本,请确保将脚本底部的两个“C:\Replace\With\Valid\Path”条目替换为系统上的有效路径。

import os, sys, thread, time, wx



class Frame(wx.Frame):

    def __init__(self, parent, id=-1, title="A Frame", path="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE):
        wx.Frame.__init__(self, parent, id, title, pos, size, style)

        self.path = path
        self.StatusBar = wx.StatusBar(self, -1)
        self.StatusBar.SetFieldsCount(3)
        self.StatusBar.SetStatusWidths([-2, -1, -1])
        self.InitMenuBar()

    def InitMenuBar(self):
        menuBar  = wx.MenuBar()
        menuFile = wx.Menu()
        menuHelp = wx.Menu()
        self._Connect = menuFile.Append(101, "&Connect", kind=wx.ITEM_CHECK)
        menuFile.AppendSeparator()
        menuFile.Append(104, "E&xit")
        menuBar.Append(menuFile, "&File")
        menuBar.Append(menuHelp, "&Help")
        self.SetMenuBar(menuBar)
        self.Bind(wx.EVT_MENU, self.OnConnect, self._Connect)

    def OnConnect(self, event):
        #print [event.IsChecked()]
        mon = Monitor("", "", "", self.path, "60", self.StatusBar)
        if event.IsChecked():
            print "Set Menu Label Disconnected"
            self._Connect.SetItemLabel("Disconnect")
            print "Start Monitor"
            mon.Start()
            print "Start Finished"
        else:
            print "Set Menu Label Connected"
            self._Connect.SetItemLabel("Connect")
            print "Stop Monitor"
            mon.Stop()
            print "Stop Finished"


class Monitor:

    def __init__(self, email, password, recipient, path, timeout, statusBar=None):

        self.email     = email
        self.password  = password
        self.recipient = recipient
        self.path      = path
        self.timeout   = timeout
        self.statusBar = statusBar
        #self.lock      = thread.allocate_lock()

    def Start(self):
        #self.lock.acquire()
        self.running = True
        thread.start_new_thread(self.Run, ())
        #self.lock.release()

    def Stop(self):
        #self.lock.acquire()
        self.running = False
        #self.lock.release()

    def IsRunning(self):
        return self.running

    def Run(self):
        start = NewestByModTime(self.path)
        count = int(self.timeout)
        while self.running:
            #print self.running
            # Step 1 - Delay the start of the monitor for X amount of seconds, updating the
            # statusbar/console each second to relfect a countdown. remove one from count each
            # loop until the count equals 0, than continue on to Step 2.
            if count > 0:
                if self.statusBar:
                    self.statusBar.SetStatusText("Monitoring will begin in %s seconds" % (count))
                else:
                    sys.stdout.write("Monitoring will begin in %s seconds\r" % (count))
                    #sys.stdout.flush()
                count -= 1
                time.sleep(1)
            # Step 2 - Start the monitor function which monitors the selected folder for new
            #files. If a new file is detected, send notification via email with the new file
            #as an attachment. (for this project, files in the folder will always be jpg images)
            # *NOTE* I Have not tested the Stop() function during Step 2 just yet, but I would
            # assume it would fail just the same as . *NOTE*
            if count == 0:
                current = NewestByModTime(self.path)
                if current[1] > start[1]:
                    print "Activity Detected"
                    start = current
                    print "Sending Notification Email"
                    #sendMail(self.email, self.password, self.recipient, "JERK ALERT!!",
                    #         "Some jerkoff is in your place right now, wanna see who it is??", "%s\\%s" % (self.path, start[0]))
                    print "Notification Email Sent!"
        print 
        self.running = False


def NewestByModTime(path):
    stat = ["", 0]
    for a in os.listdir(path):
        new = os.path.getmtime("%s\\%s" %(path, a))
        if new > stat[1]:
            stat = [a, new]
    return stat

if __name__ == "__main__":
    # Run GUI
    app   = wx.PySimpleApp()
    frame = Frame(None, -1, "Test Frame", "C:\\Replace\\With\\Valid\\Path", size=(800, 600))
    frame.Show()
    app.MainLoop()
    del app

    ## Run Console
    #mon = Monitor("", "", "", "C:\\Replace\\With\\Valid\\Path", "60", None)
    #mon.Start()
    #time.sleep(10)
    #mon.Stop()

【问题讨论】:

  • 任何人想要破解它?我仍然坚持这个问题,我完全没有想法:(

标签: python multithreading events wxpython


【解决方案1】:

刚刚想通了.. 为什么我最大的问题总是一条线解决? :P

显然我忽略了一个事实,即每次调用 self.OnConnect 时我都在重新创建变量 mon ,当我沮丧到疯狂地单击连接/断开连接十亿次并观察计数器在不同倒计时 59、43、58、42 等之间交换时,我有点意识到了这个错误。哈哈

我将 mon 更改为 self.mon 并添加了 if not hasattr(self, "mon") 以停止 self.mon em> 每次都重新创建自己。至此问题解决,倒计时完美停止。

def OnConnect(self, event):
    #print [event.IsChecked()]
    mon = Monitor("", "", "", self.path, "60", self.StatusBar)
    if event.IsChecked():
        print "Set Menu Label Disconnected"
        self._Connect.SetItemLabel("Disconnect")
        print "Start Monitor"
        mon.Start()
        print "Start Finished"
    else:
        print "Set Menu Label Connected"
        self._Connect.SetItemLabel("Connect")
        print "Stop Monitor"
        mon.Stop()
        print "Stop Finished"

收件人:

def OnConnect(self, event):
    #print [event.IsChecked()]
    if not hasattr(self, "mon"):
        self.mon = Monitor("", "", "", self.path, "60", self.StatusBar)
    if event.IsChecked():
        print "Set Menu Label Disconnected"
        self._Connect.SetItemLabel("Disconnect")
        print "Start Monitor"
        self.mon.Start()
        print "Start Finished"
    else:
        print "Set Menu Label Connected"
        self._Connect.SetItemLabel("Connect")
        print "Stop Monitor"
        self.mon.Stop()
        print "Stop Finished"

【讨论】:

    猜你喜欢
    • 2018-09-02
    • 2018-04-29
    • 1970-01-01
    • 2018-01-15
    • 2015-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多