python - 如何在 Tkinter 应用程序上收听终端?

标签 python python-3.x tkinter tkinter-canvas

我有一个简单的图形程序,可以在远程树莓派的触摸屏上显示一些指令和触摸按钮。

我没有直接执行,而是通过 SSH 连接运行它,所以我的桌面应用程序日志中有。

我想在运行脚本时从控制台进行一些简短的交互,比如执行一些函数或更改一些变量的值。

这可能吗?

我不想在 TKinter 窗口内创建控制台,正如 alessandro 所问: How to embed a terminal in a Tkinter application?

不确定我是否应该使用一个简短的子流程,如 user1941008,但 htis 似乎太复杂了 Write to terminal in Tkinter GUI

而且我不想为这个东西创建客户端/服务器设置或中间缓冲区,太复杂了,我将不得不重写一些东西以将日志发送到新程序。

我添加了我的代码的一个小版本:

#!/usr/bin/env python3
import tkinter as tk

class _tkapp(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.pack()
        self.create_widgets()

    def create_widgets(self):

        self.redButton = tk.Button(self, text='Make me red', command=self.paintMeRed)
        self.redButton.pack(side='top')

        self.blueButton = tk.Button(self, text='Make me blue', command=self.paintMeBlue)
        self.blueButton.pack(side='top')

        self.quit = tk.Button(self, text='QUIT', fg='red', command=self.master.destroy)
        self.quit.pack(side='bottom')

    def paintMeRed(self):
        tk_root.configure(background='red')
        print('user click on RED')

    def paintMeBlue(self):
        tk_root.configure(background='blue')
        print('user click on BLUE')


tk_root = tk.Tk()
tk_root.geometry("200x120") 
tk_app = _tkapp(master=tk_root)
tk_app.mainloop()

这让我可以在控制台上看到用户喜欢什么, 我的目标,也从控制台更改颜色

最佳答案

这是您问题的答案。我的其他(已删除)答案不适合您的问题。

不幸的是,如果没有套接字,您将无法做到这一点,但我添加了一些易于适应的方法(init_remote_executionlistenerdo_remite_callcleanup) 到您的示例,您可以将其复制并粘贴到您的实际应用程序中。你只需要适配do_remote_call方法:

#!/usr/bin/env python3
import socket
import tkinter as tk
from queue import Queue
from threading import Thread
from uuid import uuid1

UDP_HOST = ""
UDP_PORT = 5005
RECV_BUFFER = 1020


class _tkapp(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.pack()
        self.create_widgets()
        self.init_remote_execution()
        self.master.protocol("WM_DELETE_WINDOW", self.cleanup)  # call cleanup on exit

    def init_remote_execution(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind((UDP_HOST, UDP_PORT))
        self.endmsg = str(uuid1())  # Random string to stop threads
        self.queue = Queue()
        self.treads_running = True
        self.listener_thread = Thread(target=self.listener)
        self.worker_thread = Thread(target=self.do_remote_call)
        self.listener_thread.start()
        self.worker_thread.start()

    def listener(self):
        print("listen")
        while self.treads_running:
            data, addr = self.sock.recvfrom(RECV_BUFFER)
            data = data.decode().strip()
            print("from {addr}: {data}".format(addr=addr, data=data))
            if data == self.endmsg:
                self.treads_running = False
            self.queue.put(data)
        self.sock.close()

    def do_remote_call(self):
        while self.treads_running:
            data = self.queue.get()
            if data == self.endmsg:
                print("Bye")
            elif data == "click RED":
                self.paintMeRed()
            elif data == "click BLUE":
                self.paintMeBlue()
            else:
                print(">>> unknown command")

    def cleanup(self):
        print("cleanup")
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.sendto(self.endmsg.encode(), ("127.0.0.1", UDP_PORT))
        self.listener_thread.join()
        self.worker_thread.join()
        self.master.destroy()

    def create_widgets(self):
        self.redButton = tk.Button(self, text="Make me red", command=self.paintMeRed)
        self.redButton.pack(side="top")

        self.blueButton = tk.Button(self, text="Make me blue", command=self.paintMeBlue)
        self.blueButton.pack(side="top")

        self.quit = tk.Button(
            self, text="QUIT", fg="red", command=self.cleanup
        )  # call cleanup!!!
        self.quit.pack(side="bottom")

    def paintMeRed(self):
        tk_root.configure(background="red")
        print("user click on RED")

    def paintMeBlue(self):
        tk_root.configure(background="blue")
        print("user click on BLUE")


if __name__ == "__main__":
    tk_root = tk.Tk()
    tk_root.geometry("200x120")
    tk_app = _tkapp(master=tk_root)
    tk_app.mainloop()

请务必在退出按钮上调用cleanup 方法(否则线程不会停止,应用程序会挂起)!

现在您可以通过向树莓派上的端口 5005 发送 udp 消息(单击蓝色)来“单击”“让我变蓝”按钮。

使用树莓派上的工具 netcat(您可能需要使用 apt 安装它),您可以像这样发送命令以单击蓝色:

echo "click BLUE" | nc -uw0 127.0.0.1 5005

用 python :

#!/usr/bin/env python3
import socket


sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto('click BLUE'.encode(), ('127.0.0.1', 5005)
sock.close()

在您的桌面上,您必须将“127.0.0.1”切换为您的树莓派的 IP 地址。

关于python - 如何在 Tkinter 应用程序上收听终端?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63789455/

相关文章:

Python:pyflakes 不解释 noqa 评论

python - pyparsing ParseException : Expected end of line -- general questions 问题

python - 获取词向量矩阵中最相似的词

python - _tkinter.Tcl错误: unknown option "-image"

python - 这个错误TypeError : 'Button' object is not callable mean?是什么意思

python-3.x - 如何获取运算符类型并将公式应用到 pandas 数据框中

python - 如何在屏幕上显示和更新分数?

python-3.x - 如何在 Wxpython PseudoDC 中返回 wx.Rect 中的 ID

python - Python 3.9.1(或 3.9.2)中 "subprocess"模块的问题 - "subprocess.Popen"不起作用

python - 如何使 OptionMenu 保持相同的宽度?