Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使tkinter文本框成为标准输入接收器?_Python_Tkinter_Console_Textbox_Stdin - Fatal编程技术网

Python 如何使tkinter文本框成为标准输入接收器?

Python 如何使tkinter文本框成为标准输入接收器?,python,tkinter,console,textbox,stdin,Python,Tkinter,Console,Textbox,Stdin,我制作了两个tkinter文本框,其中一个以python脚本作为输入,另一个显示脚本的执行结果,但是当我使用input()命令时,我遇到了一个错误。下面给出了stdout重定向器的类,以及读取脚本后执行的execute函数,该函数运行良好。我没有包括Text,tkinter等,因为我使用了所有与代码一起工作的通用方法,如Text.get(),Text.mark\u set(),Text.replace()等,这里也没有包括一些函数。除了脚本和输出框之外,我还尝试将整个控制台嵌入带有Interac

我制作了两个tkinter文本框,其中一个以python脚本作为输入,另一个显示脚本的执行结果,但是当我使用
input()
命令时,我遇到了一个错误。下面给出了stdout重定向器的类,以及读取脚本后执行的execute函数,该函数运行良好。我没有包括
Text
tkinter
等,因为我使用了所有与代码一起工作的通用方法,如
Text.get()
Text.mark\u set()
Text.replace()
等,这里也没有包括一些函数。除了脚本和输出框之外,我还尝试将整个控制台嵌入带有
InteractiveConsole
的文本框中,但在接收输入或stdin的情况下问题是相同的,但在
stdout
stderr
两种情况下都可以正常工作

从代码导入InteractiveConsole、InteractiveInterpreter
类StdoutRedirector(对象):
def_uuuinit_uuu(self,text_小部件):
self.text\u space=text\u小部件
def写入(自身,字符串):
self.text\u space.insert('end',string)
self.text\u空格。请参见('end')
##类StdinRedirector(对象):
##def_uuuinit_uuu(self,text_小部件):
##self.text\u space=text\u小部件
##
##def读线(自身)->str:
##t=self.text_space.get(INSERT,f“{int(text.index(INSERT).split('.')[0])}.{int(text.index(INSERT).split('.')[1]))
##返回t
def执行(事件=无):
保存()
code=text.get('1.0',END+'-1c')
stdin=sys.stdin
stdout=sys.stdout
stderr=sys.stderr
输出.删除('1.0',结束)
##定义a():
##sys.stdin=StdinRedirector(输出)
##output.bind(“”,lambda:a)
sys.stdout=StdoutRedirector(输出)
sys.stderr=StdoutRedirector(输出)
interp=InteractiveInterpreter()
内部运行代码(代码)
sys.stdout=stdout
sys.stderr=stderr
##sys.stdin=stdin
之后,我尝试重定向stdin,这显然不起作用,相反,应用程序挂起,窗口停止响应,即使在一次又一次尝试之后。
请帮我做这个。。。我不知道这是否是不可能的,但PyCharm和其他人的内部有I/O流,因此控制台或执行窗口可以完全嵌入到文本框中。

好的,在研究了web、文档和队列、idlelib和子流程模块的代码之后,我找到了使tkinter Textbox作为stdin、stdout和stderr接收器与python控制台交互的最简单方法。代码如下:

import tkinter as tk
import subprocess
import queue
import os
from threading import Thread


class Console(tk.Frame):
    def __init__(self, parent=None, **kwargs):
        tk.Frame.__init__(self, parent, **kwargs)
        self.parent = parent

        # create widgets
        self.ttytext = tk.Text(self, wrap=tk.WORD)
        self.ttytext.pack(fill=tk.BOTH, expand=True)
        self.ttytext.linenumbers.pack_forget()

        self.p = subprocess.Popen(["jupyter", "qtconsole"], stdout=subprocess.PIPE, stdin=subprocess.PIPE,
                                  stderr=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW)

        # make queues for keeping stdout and stderr whilst it is transferred between threads
        self.outQueue = queue.Queue()
        self.errQueue = queue.Queue()

        # keep track of where any line that is submitted starts
        self.line_start = 0

        # a daemon to keep track of the threads so they can stop running
        self.alive = True
        
        # start the functions that get stdout and stderr in separate threads
        Thread(target=self.readfromproccessout).start()
        Thread(target=self.readfromproccesserr).start()

        # start the write loop in the main thread
        self.writeloop()

        # key bindings for events
        self.ttytext.bind("<Return>", self.enter)
        self.ttytext.bind('<BackSpace>', self.on_bkspace)
        self.ttytext.bind('<Delete>', self.on_delete)
        self.ttytext.bind('<<Copy>>', self.on_copy)
        self.ttytext.bind('<<Paste>>', self.on_paste)
        self.ttytext.bind('<Control-c>', self.on_copy)
        self.ttytext.bind('<Control-v>', self.on_paste)

    def destroy(self):
        """This is the function that is automatically called when the widget is destroyed."""
        self.alive = False
        # write exit() to the console in order to stop it running
        self.p.stdin.write("exit()\n".encode())
        self.p.stdin.flush()
        # call the destroy methods to properly destroy widgets
        self.ttytext.destroy()
        tk.Frame.destroy(self)
        
    def enter(self, event):
        """The <Return> key press handler"""
        cur_ind = str(self.ttytext.index(tk.INSERT))
        if int(cur_ind.split('.')[0]) < int(self.ttytext.search(': ', tk.END, backwards=True).split('.')[0]):
            try:
                selected = self.ttytext.get('sel.first', 'sel.last')
                if len(selected) > 0:
                    self.ttytext.insert(tk.END, selected)
                    self.ttytext.mark_set(tk.INSERT, tk.END)
                    self.ttytext.see(tk.INSERT)
                    return 'break'
            except:
                selected = self.ttytext.get(
                    self.ttytext.search(': ', tk.INSERT, backwards=True), tk.INSERT)
                self.ttytext.insert(tk.END, selected.strip(': '))
                self.ttytext.mark_set(tk.INSERT, tk.END)
                self.ttytext.see(tk.INSERT)
            return 'break'
        string = self.ttytext.get(1.0, tk.END)[self.line_start:]
        self.line_start += len(string)
        self.p.stdin.write(string.encode())
        self.p.stdin.flush()

    def on_bkspace(self, event):
        pass

    def on_delete(self, event):
        pass

    def on_key(self, event):
        """The typing control (<KeyRelease>) handler"""
        cur_ind = str(self.ttytext.index(tk.INSERT))
        try:
            if int(cur_ind.split('.')[0]) < int(self.ttytext.search(r'In [0-9]?', tk.END, backwards=True).split('.')[0]):
                return 'break'
        except:
            return

    def on_copy(self, event):
        """<Copy> event handler"""
        self.ttytext.clipboard_append(self.ttytext.get('sel.first', 'sel.last'))
        # I created this function because I was going to make a custom textbox

    def on_paste(self, event):
        """<Paste> event handler"""
        self.ttytext.insert(tk.INSERT, self.ttytext.clipboard_get())
        # I created this function because I was going to make a custom textbox

    def readfromproccessout(self):
        """To be executed in a separate thread to make read non-blocking"""
        while self.alive:
            data = self.p.stdout.raw.read(1024).decode()
            self.outQueue.put(data)

    def readfromproccesserr(self):
        """To be executed in a separate thread to make read non-blocking"""
        while self.alive:
            data = self.p.stderr.raw.read(1024).decode()
            self.errQueue.put(data)

    def writeloop(self):
        """Used to write data from stdout and stderr to the Text widget"""
        # if there is anything to write from stdout or stderr, then write it
        if not self.errQueue.empty():
            self.write(self.errQueue.get())
        if not self.outQueue.empty():
            self.write(self.outQueue.get())

        # run this method again after 10ms
        if self.alive:
            self.after(10, self.writeloop)

    def write(self, string):
        self.ttytext.insert(tk.END, string)
        self.ttytext.see(tk.END)
        self.line_start += len(string)
        self.ttytext.inst_trigger()


if __name__ == '__main__':
    root = tk.Tk()
    main_window = Console(root)
    main_window.pack(fill=tk.BOTH, expand=True)
    main_window.ttytext.focus_force()
    root.mainloop()

将tkinter作为tk导入
导入子流程
导入队列
导入操作系统
从线程导入线程
类控制台(tk.Frame):
def uuu init uuuu(self,parent=None,**kwargs):
tk.Frame.\uuuuu init\uuuuuuu(自、父、**kwargs)
self.parent=parent
#创建小部件
self.ttytext=tk.Text(self,wrap=tk.WORD)
self.ttytext.pack(fill=tk.BOTH,expand=True)
self.ttytext.linenumbers.pack_-forget()
self.p=subprocess.Popen([“jupyter”,“qtconsole”],stdout=subprocess.PIPE,stdin=subprocess.PIPE,
stderr=subprocess.PIPE,creationflags=subprocess.CREATE\u NO\u窗口)
#在线程之间传输stdout和stderr时,创建用于保存stdout和stderr的队列
self.outQueue=queue.queue()
self.errQueue=queue.queue()
#跟踪提交的任何行的起始位置
self.line_start=0
#一个守护进程来跟踪线程,以便它们可以停止运行
self.alive=True
#在单独的线程中启动获取stdout和stderr的函数
线程(target=self.readFromProcessOut).start()
线程(target=self.readfromProcesserr).start()
#在主线程中启动写循环
self.writeloop()
#事件的键绑定
self.ttytext.bind(“,self.enter)
self.ttytext.bind(“”,self.on_bkspace)
self.ttytext.bind(“”,self.on_delete)
self.ttytext.bind(“”,self.on_copy)
self.ttytext.bind(“”,self.on_粘贴)
self.ttytext.bind(“”,self.on_copy)
self.ttytext.bind(“”,self.on_粘贴)
def销毁(自我):
“”“这是当小部件被销毁时自动调用的函数。”“”
self.alive=False
#将exit()写入控制台以停止其运行
self.p.stdin.write(“exit()\n”.encode())
self.p.stdin.flush()
#调用destroy方法来正确销毁小部件
self.ttytext.destroy()
框架破坏(自我)
def enter(自我,事件):
“”“按键处理程序”“”
cur_ind=str(self.ttytext.index(tk.INSERT))
如果int(cur_ind.split('.')[0])0:
self.ttytext.insert(tk.END,选中)
self.ttytext.mark_集(tk.INSERT,tk.END)
self.ttytext.see(tk.INSERT)
返回“中断”
除:
selected=self.ttytext.get(
self.ttytext.search(“:”,tk.INSERT,backwards=True),tk.INSERT)
self.ttytext.insert(tk.END,selected.strip(':'))
self.ttytext.mark_集(tk.INSERT,tk.END)
self.ttytext.see(tk.INSERT)
返回“中断”
string=self.ttytext.get(1.0,tk.END)[self.line\u start:]
self.line_start+=len(字符串)
self.p.stdin.write(string.encode())
self.p.stdin.flush()
bku空间上的def(自身、事件):
通过
def on_删除(自身、事件):
通过
def on_键(自身,事件):
“”“类型控制()处理程序”“”
cur_ind=str(self.ttytext.index(tk.INSERT))
尝试: