为什么赢了';在Python中使用cmd.onecmd停止t cmd.cmdloop?

为什么赢了';在Python中使用cmd.onecmd停止t cmd.cmdloop?,python,cmd,Python,Cmd,在对python使用cmd时,我有一个名为do_exit的方法,它返回True以使cmdloop退出 我尝试调用cmd.onecmd('exit'),但是当命令exit运行时,cmdloop不会退出 也没有错误。调用了do\u exit方法,因为正在退出我。会被打印出来。这让它变得更加神秘 我已经查看了cmd模块的源代码,但找不到问题所在。考虑到cmd.onecmd可能在所有命令上都会被调用,我觉得直接调用应该可以 我还尝试使用返回值为cmd.onecmd的cmd.postmd,但这也不起作用

在对python使用cmd时,我有一个名为do_exit的方法,它返回True以使cmdloop退出

我尝试调用
cmd.onecmd('exit')
,但是当命令
exit
运行时,cmdloop不会退出

也没有错误。调用了
do\u exit
方法,因为
正在退出我。
会被打印出来。这让它变得更加神秘

我已经查看了
cmd模块的源代码,但找不到问题所在。考虑到
cmd.onecmd
可能在所有命令上都会被调用,我觉得直接调用应该可以

我还尝试使用返回值为
cmd.onecmd
cmd.postmd
,但这也不起作用

quit\u all
功能中,特定行位于该代码底部附近

#!/usr/bin/python
import cmd
from gi.repository import Gtk
import threading

class WindowWidget(object):

    def __init__(self):
        win = Gtk.Window()
        win.connect("delete-event", Gtk.main_quit)
        win.show_all()
        self.window = win;
    def create_button(self):
        self.button = Gtk.Button(label="Click Here")
        self.button.connect("clicked", self.on_button_clicked)
        self.window.add(self.button)
        self.window.show_all()

    def on_button_clicked(self, widget):
        print 'something happened'
        return


class InteractiveShell(cmd.Cmd):
    #Simple command processor example.
    prompt='>'
    def __init__(self, gtk_object):
        cmd.Cmd.__init__(self)
        # or cmd.Cmd.__init__(self)
        self.gtk_object = gtk_object

    def do_greet(self, line):
        print "hello"

    def do_setbutton(self, line):
        self.gtk_object.create_button()

    def do_exit(self, line):
        """Close the gtk main loop, and return True to exit cmd."""

        print 'Exiting me.'
        return True

    def postloop(self):
        print 'Closing window.'
        if Gtk.main_level() > 0:
            Gtk.main_quit()



def worker(num, s):
    """thread worker function"""
    #print 'Worker: %s' % num
    s.cmdloop()
    return

def worker2(num):
    Gtk.main()

threads = []



if __name__ == '__main__':

    ww = WindowWidget()
    mainshell = InteractiveShell(ww)
    threads = []

    def quit_all(event, user_data):
        print 'x out of window. Trying to exit shell.'
        #offending line cmdloop won't exit
        r = mainshell.onecmd('exit')
        return False

    ww.window.connect("delete-event", quit_all)

    t = threading.Thread(target=worker, args=(1, mainshell))
    threads.append(t)
    t2 = threading.Thread(target=worker2, args=(2,))
    threads.append(t2)
    t.start()
    t2.start()

Edit在使用代码并从cmd对象本身内部运行方法
cmd.onecmd
后,我发现该方法确实有效。很明显,可能是线程问题。某些原因导致
退出
gtk事件
内部不工作,特别是
删除事件
。我仍然不知道问题出在哪里。

我想我能理解问题出在哪里。。。但我没有简单的解决办法。如果
cmdloop的noop
,则调用
onecommand('exit')
。从
cmd
模块的角度来看,它启动
cmdloop
cmdloop
重复调用命令,并查看它启动的命令的返回值。比如:

while True:
   cr = do_cmd
   if cr:
        break
如果在循环外调用
do_cmd
,没有人关心,循环仍在等待。这正是程序中发生的事情:您调用
do_exit
,它执行时没有错误,但您没有中断循环

现在进行修复(我没有安装Gtk,因此无法测试自己):

快速且肮脏:您可以将携带
cmdloop
的线程设置为守护进程线程。当您想关闭程序时,请清除所有其他内容(窗口)并退出。线程(及其循环)应突然停止

更好,但更长。不要向
cmd
提供
sys.stdin
,而只提供一个管道。使用某个窗口中的字段获取输入命令,并将其写入管道。要停止时,将“退出”写入管道。循环将读取它,执行
do_exit
方法,获取
True
作为返回并退出。但我必须承认,
cmd
模块正在失去一部分兴趣

由于我不知道您在应用程序中真正想要做什么,我无法想象一个更有效的解决方案。也许你应该提供更多关于你想做什么的一般结构的细节

  • 根据这里的另一个答案,我尝试
    对cmd线程进行后台监控,并从程序中退出
    sys.exit。没用。窗户冻住了,我把它弄死了。我不知道为什么会这样,因为我还不知道我在做什么。我决定不
    对任何线程进行后台监控

  • 接下来,根据我发布的一个相关问题的另一个相关答案的建议,我尝试将Gtk.main放在主线程中,而不是放在自己的线程中<代码>Gtk窗口打开,但没有cmd界面。不,它不起作用,但是

  • 我将
    Gtk.main
    移动到程序的最底部。现在一切都打开了。现在我可以用sys.exit关闭所有东西,但现在还有其他东西。终端输入为空。首先,我认为它不接受输入。在对伟大的谷歌进行了一些研究之后,我发现了一些关于同样事情的其他问题,但结果表明终端正在接受输入。它只是隐形的

  • 按照建议,我尝试操作系统('reset')
  • ,现在可以正常工作了。耶!但是,在终端输入已经重置之后,窗口会被挂起几秒钟,这是一次令人敬畏的关机

  • 我上网搜索。在另一个论坛的互联网穷乡僻壤中,我找到了
    sttyecho
    ,以及
    sttysane
    终端命令。他们都努力解决这个问题。我选择操作系统('sttysane')

  • 现在一切都好了。为了保持最新,我将操作系统('stty sane')改为
    Popen('stty sane',shell=True)
    。其他人说应用程序将修改终端设置,这将使输入不回显。很可能是我干的
    sttysane
    是明确的解决方案

    下面是所有解决方案的代码。啊。这比我想象的要简单得多

    #!/usr/bin/python
    import cmd
    from gi.repository import Gtk
    import threading
    
    """
    The bottom of this file has all the goodies for this solution.
    Scroll down to see the cool stuff.
    """
    class WindowWidget(object):
    
        def __init__(self):
            win = Gtk.Window()
            win.connect("delete-event", Gtk.main_quit)
            win.show_all()
            self.window = win;
        def create_button(self):
            self.button = Gtk.Button(label="Click Here")
            self.button.connect("clicked", self.on_button_clicked)
            self.window.add(self.button)
            self.window.show_all()
    
        def on_button_clicked(self, widget):
            print 'something happened'
            return
    
    
    class InteractiveShell(cmd.Cmd):
        #Simple command processor example.
        prompt='>'
        def __init__(self, gtk_object):
            cmd.Cmd.__init__(self)
            # or cmd.Cmd.__init__(self)
            self.gtk_object = gtk_object
    
        def do_greet(self, line):
            print "hello"
    
        def do_setbutton(self, line):
            """
            Using GLib.idle_add to insert a callback into the Gtk loop.
            This makes synchronizing the main thread where gtk is at, and
            this second thread easier.
            """
            GLib.idle_add(self.idle_setbutton)
    
        def idle_setbutton(self):
            self.gtk_object.create_button()
    
        def do_exit(self, line):
            """Close the gtk main loop, and return True to exit cmd."""
    
            print 'Exiting me.'
            return True
    
        def postloop(self):
            print 'Closing window.'
            if Gtk.main_level() > 0:
                Gtk.main_quit()
    
    
    
    def worker(s):
        s.cmdloop()
        return
    
    #isn't required  
    #def worker2(num):
    #    Gtk.main()
    
    
    
    if __name__ == '__main__':
    
        ww = WindowWidget()
        mainshell = InteractiveShell(ww)
        #This list is superfluous
        #threads = []
    
        def quit_all(event, user_data):
            print 'x out of window. Trying to exit shell.'
            #I don't know if the next line is needed.
            #It's here just in case.
            Gtk.main_quit()
            #offending line cmdloop won't exit
            #but now it will because of sys.exit
            r = mainshell.onecmd('exit')
    
            #Problem found with sys.exit
            #When this program closes terminal input is working, but
            #it's blank. Here comes the fix.
            #Works, but it is messy -> os.system('reset')
            #Does not work -> Popen('reset', shell=True)
            #The command 'stty sane' is the best way to keep the
            #terminal from having blank input after closing.
            #os.system('stty sane')
            #Actually use Popen for this.
            Popen('stty sane', shell=True)
            #alternatively
            #os.system('stty echo')
            #sys.exit can only exit the whole program from the main thread.
            sys.exit(0)
            #Threads are closing, and so is the window.
            #This is a clean close.
            return False
    
        ww.window.connect("delete-event", quit_all)
    
        t = threading.Thread(target=worker, args=(mainshell))
        #No need to create a thread for Gtk.main
        #threads.append(t)
        #t2 = threading.Thread(target=worker2, args=(2,))
        #threads.append(t2)
        t.start()
        #t2.start()
        #Gtk.main needs to be called after the second thread is started.
        #This will keep Gtk from blocking the second thread.
        #Gtk.main loop in the python main thread is easier to deal with
        #to make sure that work for Gtk will get finished.
        #Can use GLib.idle_add to insert functions, and methods into
        #the Gtk loop.
        Gtk.main()
    

    我没有尝试通过管道从Gtk字段输入。也许下次吧。

    在python3中,您可以执行以下操作:

    interactor.cmdqueue.append(“exit\n”)#其中interactor是对象(Cmd)
    打印(“请按Enter继续…”)
    

    其思想是
    cmdloop()
    挂在
    input()
    上(或者如果使用
    raw\u input
    =False,则将挂在
    readline()
    )。但是,您可以简单地将其附加到用于播放的命令队列中。问题是您需要一个
    Enter
    ,以使其通过
    input()
    部分。这是有道理的,因为否则,
    Cmd
    无法提供您使用它进行的平滑直观的交互。

    您可以向我们展示更多的代码吗?@xander您知道问题出在哪里吗?我想制作一个gtk文本区域,并通过终端发送命令与之交互。按钮加法器只是一个测试。这正是正在发生的事情。没有人看到回报。这很奇怪,因为我在gtk事件之外使用了这个方法,它停止了cmd loop.lol。我差点就明白了。我删除了gtk的线程,只是将gtk.main放在ot之后