首页 > 解决方案 > 如何从活动 tcp 会话接收文本来更新 tk.label

问题描述

我正在尝试从作为服务器工作的活动 tcp 会话更新 tk.label 中的文本。所以脚本实际上是在等待(服务器)通过 tcp 连接从客户端接收一些文本。

import re
import socketserver
import socket
import subprocess
import tkinter as tk
import time

line = ""

class Info:
    def __init__(self, master):
        self.label=tk.Label(master)
        self.label.grid(row=0, column=0)
        self.label.configure(text='Ready to roll...')
        self.count = 0
        if self.count == 0: self.first_label()
        else: self.update_label()

    def first_label(self):
        self.label.configure(text=line_info)
        self.label.after(5000, self.update_label)
        self.count += 1

    def update_label(self):
        self.label.configure(text = line_info)
        self.label.after(5000, self.update_label) # call this method again in 1,000 milliseconds
        self.count += 1
        with socketserver.TCPServer((host, port), MyTCPHandler) as server:
            print("{}:{} - READY".format(host, port))
            # Activate the server; this will keep running until you
            # interrupt the program with Ctrl-C
            server.serve_forever()

class MyTCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        # self.request is the TCP socket connected to the client
        self.data = self.request.recv(1024).strip()
        data = self.data.decode('utf-8')

        # Do string manipulation to find cpu/gpu and co.

        line_info = "{} {} {} {} {} {} {}".format(timestamp, tcpu, tgpu, cpu, core, volt, gpu)
        print(line_info)
        # just send back the same data, but upper-cased
        self.request.sendall(bytes("OK", "utf-8"))
    
if __name__ == "__main__":
    host_name = socket.gethostname()
    bashCmd = "hostname -I | awk -F\" \" '{print $1}'"
    data = subprocess.check_output(["bash", "-c", bashCmd]).strip()
    server_ip = data.decode('utf-8')

    host, port = server_ip, 9999

    line_info = "Updating..."

    root = tk.Tk()
    Info(root)
    root.mainloop()

这个 server.py 脚本正在等待通过 tcp 从客户端接收一些文本,例如:

10/12/2020 10:50:01 [192.168.1.124] CPU=54.61C GPU=55.10C CPU=700GHz Core=400MHz Core=1.35V GPU=300MHz  OK
10/12/2020 10:50:12 [192.168.1.124] CPU=54.61C GPU=55.10C CPU=700GHz Core=400MHz Core=1.35V GPU=300MHz  OK
10/12/2020 10:50:23 [192.168.1.124] CPU=54.61C GPU=55.10C CPU=700GHz Core=400MHz Core=1.35V GPU=300MHz  OK

我的目标是获取通过 tcp 连接接收到的文本并将其作为将滚动的标签文本查看到 tk-window 中。尽管 tcp 连接和文本从客户端接收到服务器并且 tk 窗口已初始化,但它永远不会使用每 20 秒来自客户端的新信息(变量 line_info)进行更新。为了检查,我只是在字符串操作后将 line_info 打印到标准输出。

带有标签初始文本的 Tk 窗口

如何更新 tk.label 中的文本?

标签: python-3.xtkinter

解决方案


你最好使用线程来运行update_label(),这样它就不会阻塞应用程序:

import socketserver
import socket
import subprocess
import tkinter as tk
import threading

class Info:
    def __init__(self, master):
        self.label=tk.Label(master, textvariable=line_info)
        self.label.grid(row=0, column=0)

        threading.Thread(target=self.update_label, daemon=True).start()

    def update_label(self):
        line_info.set('Ready to roll...')
        with socketserver.TCPServer((host, port), MyTCPHandler) as server:
            print("{}:{} - READY".format(host, port))
            server.serve_forever()

class MyTCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        try:
            # self.request is the TCP socket connected to the client
            self.data = self.request.recv(1024).strip()
            data = self.data.decode('utf-8')

            # Do string manipulation to find cpu/gpu and co.

            line_info.set("{} {} {} {} {} {} {}".format(timestamp, tcpu, tgpu, cpu, core, volt, gpu))
            print(line_info.get())
            # just send back the same data, but upper-cased
            self.request.sendall(bytes("OK", "utf-8"))
        except Exception as e:
            print(e)
    
if __name__ == "__main__":
    host_name = socket.gethostname()
    bashCmd = "hostname -I | awk -F\" \" '{print $1}'"
    data = subprocess.check_output(["bash", "-c", bashCmd]).strip()
    server_ip = data.decode('utf-8')

    host, port = server_ip, 9999

    root = tk.Tk()
    line_info = tk.StringVar()
    Info(root)
    root.mainloop()

请注意,我已更改line_infoStringVar().


推荐阅读