以Python 做服务器,N Robot 做客户端,小小UI,拿捏

打印 上一主题 下一主题

主题 1796|帖子 1796|积分 5388

先Show 结果~



假造开足
 







  1. import socket
  2. import threading
  3. import logging
  4. from tkinter import Tk, Canvas, BOTH, YES, NW, N, mainloop, font as tkfont
  5. from tkinter.constants import S, E, W
  6. from datetime import datetime
  7. import os
  8. # 定义文件夹路径
  9. folder_path = r'c:\Log6'
  10. # 检查文件夹是否存在,如果不存在则创建
  11. if not os.path.exists(folder_path):
  12.     os.makedirs(folder_path)
  13. class RobotServer:
  14.     def __init__(self, host, port, canvas):
  15.         self.host = host
  16.         self.port = port
  17.         self.server_socket = None
  18.         self.clients = {}
  19.         self.lock = threading.Lock()
  20.         self.canvas = canvas
  21.         self.A = 0
  22.         self.B = 4
  23.         self.R1_LS = []
  24.         self.R2_LS = []
  25.         self.R3_LS = []
  26.         self.R4_LS = []
  27.         logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
  28.         # 初始化画布内容
  29.         self.init_canvas()
  30.     def init_canvas(self):
  31.         w = self.canvas.winfo_width()
  32.         h = self.canvas.winfo_height()
  33.         L_w, M_w, R_w = w//3, w//3, w - (w//3 * 2)
  34.         L_h, M_h, R_h = h, h, h
  35.         # 显示整体、曲线、计划的文本标签,字体为60,背景为立体感
  36.         titles = ["整体"]
  37.         for i, title in enumerate(titles):
  38.             x = 130
  39.             shadow_offset = 4
  40.             #self.canvas.create_rectangle(x-100+shadow_offset, 20+shadow_offset, x+100+shadow_offset, 80+shadow_offset, fill="darkgray", outline="")
  41.             #self.canvas.create_rectangle(x-100, 20, x+100, 80, fill="lightgray", outline="gray")
  42.             self.canvas.create_text(x, 50, text=title, anchor=N, font=tkfont.Font(size=60))
  43.         titles = ["Remark:\r\n分子为在线数量,\r\n分母为Total 数量,\r\n小于55%,显示红色,\r\n50%~75%,显示黄色,\r\n大于75%,显示绿色"]
  44.         for i, title in enumerate(titles):
  45.             self.canvas.create_text(130, 400, text=title, anchor=N, font=tkfont.Font(size=16))
  46.         titles = ["曲线"]
  47.         for i, title in enumerate(titles):
  48.             x = (i+0.5) * w/3 +300
  49.             shadow_offset = 4
  50.             #self.canvas.create_rectangle(x-100+shadow_offset, 20+shadow_offset, x+100+shadow_offset, 80+shadow_offset, fill="darkgray", outline="")
  51.             #self.canvas.create_rectangle(x-100, 20, x+100, 80, fill="lightgray", outline="gray")
  52.             self.canvas.create_text(x, 50, text=title, anchor=N, font=tkfont.Font(size=60))
  53.         titles = ["计划"]
  54.         for i, title in enumerate(titles):
  55.             x = 1080
  56.             shadow_offset = 4
  57.             #self.canvas.create_rectangle(x-100+shadow_offset, 20+shadow_offset, x+100+shadow_offset, 80+shadow_offset, fill="darkgray", outline="")
  58.             #self.canvas.create_rectangle(x-100, 20, x+100, 80, fill="lightgray", outline="gray")
  59.             self.canvas.create_text(x, 50, text=title, anchor=N, font=tkfont.Font(size=60))
  60.         titles = ["R1_Data"]
  61.         for i, title in enumerate(titles):
  62.             x = 350
  63.             self.canvas.create_rectangle(x-70, 160, x+60, 160+30, fill="lightgray", outline="gray")
  64.             self.canvas.create_text(x, 160, text=title, anchor=N, font=tkfont.Font(size=20))
  65.         titles = ["R2_Data"]
  66.         for i, title in enumerate(titles):
  67.             x = 350
  68.             self.canvas.create_rectangle(x-70, 460, x+60, 460+30, fill="darkgray", outline="gray")
  69.             self.canvas.create_text(x, 460, text=title, anchor=N, font=tkfont.Font(size=20))
  70.         self.draw_ring(90, 300, 70, 40)   
  71.         self.update_connection_status()   
  72.         self.draw_table(w, h)         
  73.         # 使用 after 方法更新曲线
  74.         self.update_scatter_plots()
  75.     def draw_ring(self, x, y, outer_radius, inner_radius):
  76.         ratio = self.A / self.B if self.B != 0 else 0
  77.         color = "red" if ratio < 0.5 else "yellow" if ratio <= 0.75 else "green"
  78.         self.canvas.create_oval(x-outer_radius, y-outer_radius, x+outer_radius, y+outer_radius, fill=color)
  79.         self.canvas.create_oval(x-inner_radius, y-inner_radius, x+inner_radius, y+inner_radius, fill="white")
  80.         self.connection_text = self.canvas.create_text(x, y, text=f"{self.A}/{self.B}", fill="black")
  81.     def update_connection_status(self):
  82.         ratio = self.A / self.B if self.B != 0 else 0
  83.         color = "red" if ratio < 0.5 else "yellow" if ratio <= 0.75 else "green"
  84.         self.canvas.itemconfig(self.connection_text, text=f"{self.A}/{self.B}")
  85.         self.canvas.itemconfig(self.connection_text, fill="black")
  86.         self.canvas.itemconfig(self.connection_text, state='normal')
  87.         self.draw_ring(90, 300, 70, 40)
  88.     def draw_table(self, w, h):
  89.         # 计划区域的宽度和高度
  90.         plan_area_width = w // 3
  91.         plan_area_height = h
  92.         # 表格应该占用计划区域的大部分空间,但要留出一些边距
  93.         margin = 20
  94.         table_width = plan_area_width - 2 * margin
  95.         table_height = min(150, plan_area_height - 2 * margin)  # 确保表格不会过高
  96.         # 表格起始坐标,使得表格居中于计划区域
  97.         table_x = w - plan_area_width + margin
  98.         table_y = (h - table_height) // 2 -30
  99.         row_height = 40
  100.         col_width = table_width // 4  # 每一列的宽度等于表格宽度的四分之一
  101.         # 清除旧表格
  102.         self.canvas.delete("table")
  103.         # 使用“+”绘制表格
  104.         for j in range(6):  # 包括表头和四行数据  6
  105.             self.canvas.create_line(table_x, table_y + j * row_height, table_x + table_width, table_y + j * row_height, fill="black", tags="table")
  106.             for i in range(table_width // col_width + 1):
  107.                 self.canvas.create_text(table_x + i * col_width, table_y + j * row_height, text="+", fill="black", font=tkfont.Font(size=10), tags="table")
  108.         for i in range(6):  # 包括边界线和四个分隔线  6                                           ##       5   ##
  109.             self.canvas.create_line(table_x + i * col_width, table_y, table_x + i * col_width, table_y + 5 * row_height, fill="black", tags="table")
  110.         # 绘制表头(列标签)
  111.         for j, quarter in enumerate(['', 'Q1', 'Q2', 'Q3', 'Q4']):
  112.             self.canvas.create_text(table_x + j * col_width + col_width // 2, table_y - 10, text=quarter, font=tkfont.Font(size=30), anchor=N, tags="table")
  113.         # 绘制表格内容(行标签与X标记)
  114.         for i, row in enumerate(['R1', 'R2', 'R3', 'R4']):
  115.             self.canvas.create_text(table_x + col_width // 2, table_y + (i + 1) * row_height, text=row, font=tkfont.Font(size=30), anchor=N, tags="table")
  116.             self.canvas.create_text(table_x + (i + 1) * col_width + col_width // 2, table_y + (i + 1) * row_height, text="X", font=tkfont.Font(size=30), anchor=N, tags="table")
  117.     def update_scatter_plots(self):
  118.         self.draw_scatter_plot('R1', self.R1_LS[-30:], 270, 250, 500, 100)  
  119.         self.draw_scatter_plot('R2', self.R2_LS[-30:], 270, 350, 500, 100)
  120.         self.draw_scatter_plot('R3', self.R3_LS[-30:], 270, 550, 500, 100)  
  121.         self.draw_scatter_plot('R4', self.R4_LS[-30:], 270, 650, 500, 100)
  122.         self.canvas.after(500, self.update_scatter_plots)  
  123.     def draw_scatter_plot(self, prefix, data_list, start_x, start_y, width, height):
  124.         scale = width / max(len(data_list), 1)
  125.         self.canvas.delete(f"{prefix}_scatter")  # 删除旧的散点图元素
  126.         
  127.         # 增加圆点大小
  128.         dot_size = 6  # 圆点直径变为原来的三倍大
  129.         for i, value in enumerate(data_list):
  130.             x = start_x + i * scale
  131.             y = start_y - int(value) * (height / 100)
  132.             color = "green" if 23 <= int(value) <= 29 else "red"
  133.             self.canvas.create_oval(x - dot_size, y - dot_size, x + dot_size, y + dot_size, fill=color, tags=f"{prefix}_scatter")  
  134.         # 清除旧的文本标签
  135.         self.canvas.delete(f"{prefix}_text")
  136.         # 只显示最近进来的2个数字,蓝色显示值
  137.         for i, value in enumerate(data_list[-2:]):
  138.             text_color = "blue"
  139.             self.canvas.create_text(start_x + len(data_list) * scale - i * scale, start_y - height / 2 - 10,
  140.                                     text=value, font=tkfont.Font(size=12), anchor=S, fill=text_color, tags=f"{prefix}_text")
  141.         # 中间水平线
  142.         self.canvas.create_line(start_x, start_y, start_x + width, start_y, fill="black", tags=f"{prefix}_line")
  143.         # 中间分割线
  144.         self.canvas.create_line(start_x, start_y - height / 2, start_x + width, start_y - height / 2, fill="black", tags=f"{prefix}_line")
  145.     def start_server(self):
  146.         try:
  147.             self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  148.             self.server_socket.bind((self.host, self.port))
  149.             self.server_socket.listen(5)
  150.             logging.info(f"Server started at {self.host}:{self.port}")
  151.             while True:
  152.                 client_socket, client_address = self.server_socket.accept()
  153.                 with self.lock:
  154.                     self.clients[client_address] = client_socket
  155.                     self.A += 1
  156.                     self.update_connection_status()
  157.                 logging.info(f"Accepted connection from {client_address}")
  158.                 threading.Thread(target=self.handle_client, args=(client_socket, client_address), daemon=True).start()
  159.         except Exception as e:
  160.             logging.error(f"Failed to start server: {e}")
  161.         finally:
  162.             if self.server_socket:
  163.                 self.server_socket.close()
  164.     def handle_client(self, client_socket, client_address):
  165.         try:
  166.             while True:
  167.                 current_time = datetime.now().strftime("%H:%M:%S")
  168.                 data = client_socket.recv(1024)
  169.                 if not data:
  170.                     break
  171.                 decoded_data = data.decode('utf-8')
  172.                 logging.info(f"{current_time} -- Received from {client_address}: {decoded_data}")
  173.                 response = current_time
  174.                 client_socket.sendall(response.encode('utf-8'))
  175.                 logging.info(f"{current_time} -- response to RobotServer('192.168.0.109', 7777): {response}")
  176.                 # 解析数据并更新散点图数据
  177.                 if decoded_data.startswith('R1'):
  178.                     self.R1_LS.append(decoded_data[2:4])
  179.                 elif decoded_data.startswith('R2'):
  180.                     self.R2_LS.append(decoded_data[2:4])
  181.                 elif decoded_data.startswith('R3'):
  182.                     self.R3_LS.append(decoded_data[2:4])
  183.                 elif decoded_data.startswith('R4'):
  184.                     self.R4_LS.append(decoded_data[2:4])
  185.                 log_entry = f"[{current_time}]-Recive:{data}---Response:{response}\n"  
  186.                 with open(r"c:\Log6\log.txt", "a") as log_file:  
  187.                     log_file.write(log_entry)  
  188.         except Exception as e:
  189.             logging.error(f"Error handling client {client_address}: {e}")
  190.         finally:
  191.             client_socket.close()
  192.             with self.lock:
  193.                 del self.clients[client_address]
  194.                 self.A -= 1
  195.                 self.update_connection_status()
  196.             logging.info(f"Closed connection from {client_address}")
  197. def on_resize(event):
  198.     global server
  199.     w = event.width
  200.     h = event.height
  201.     canvas = event.widget
  202.     canvas.delete("all")
  203.     server.init_canvas()
  204. def main():
  205.     global server
  206.     root = Tk()
  207.     root.title("Design By Tim")
  208.     root.geometry("800x600")
  209.     canvas = Canvas(root, bg="white")  
  210.     canvas.pack(fill=BOTH, expand=YES)
  211.     server = RobotServer('192.168.0.109', 7788, canvas)
  212.     threading.Thread(target=server.start_server, daemon=True).start()
  213.     canvas.bind("<Configure>", on_resize)
  214.     root.mainloop()
  215. if __name__ == "__main__":
  216.     main()
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

惊雷无声

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表