如何使tkinter文本框成为stdin输入接收器?

如何解决如何使tkinter文本框成为stdin输入接收器?

我制作了两个tkinter文本框,其中一个将您的python脚本作为输入,另一个显示了脚本执行的结果,但是当我使用input()命令时出现错误。下面给出的是stdout重定向器的类,以及在读取脚本后执行的execute函数,效果很好。我没有包括Texttkinter等,因为我使用了与Text.get()Text.mark_set()Text.replace()等类似的所有通用方法也有些功能不在此处。除了脚本和输出框之外,我还尝试将整个控制台嵌入到带有InteractiveConsole的文本框中,但是在接收输入或标准输入的情况下,问题是相同的,但是在两种情况下,stdoutstderr正常。

from code import InteractiveConsole,InteractiveInterpreter


class StdoutRedirector(object):
    def __init__(self,text_widget):
        self.text_space = text_widget

    def write(self,string):
        self.text_space.insert('end',string)
        self.text_space.see('end')


##class StdinRedirector(object):
##    def __init__(self,text_widget):
##        self.text_space = text_widget
##
##    def readline(self) -> str:
##        t = self.text_space.get(INSERT,f"{int(text.index(INSERT).split('.')[0])}.{int(text.index(INSERT).split('.')[1])}")
##        return t


def execute(event=None):
    save()
    code = text.get('1.0',END+'-1c')
    stdin = sys.stdin
    stdout = sys.stdout 
    stderr = sys.stderr

    output.delete('1.0',END)
##    def a():
##        sys.stdin = StdinRedirector(output)
##    output.bind('<Return>',lambda: a)
    
    sys.stdout = StdoutRedirector(output)
    sys.stderr = StdoutRedirector(output)
    
    interp = InteractiveInterpreter()
    interp.runcode(code)

    sys.stdout = stdout
    sys.stderr = stderr
##    sys.stdin = stdin

此后,我尝试了重定向stdin,这显然不起作用,而是挂起了应用程序,并且即使一次又一次尝试后,窗口也停止响应。 请帮助我...我不知道它是否不可能,但是PyCharm和其他人内部都具有I / O流,因此控制台或执行窗口可以完全嵌入文本框中。

解决方法

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

# get context
$apimContext = New-AzApiManagementContext -ResourceGroupName "targetResourceGroup" -ServiceName "targetApimInstance"
$api = Get-AzApiManagementApi -Context $apimContext -ApiId "api-id"

# set subscriptionRequired to false
$api.SubscriptionRequired=$false
Set-AzApiManagementApi -InputObject $api

上面的代码使用了jupyter qtconsole(因为它非常好用),否则也可以使用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]?',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() 模块中的InteractiveShell()来使用简单的python shell。 我还没有完全为 code 键、EnterUp 箭头键制作函数。这些可以由用户根据自己的选择进行。

这也可以在 Oli 的回答 here 中找到,并且可以自定义。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-