|
|
@@ -0,0 +1,219 @@
|
|
|
+import logging
|
|
|
+import tempfile
|
|
|
+import tkinter as tk
|
|
|
+from tkinter import Menu, Text, Label, Entry, Button
|
|
|
+from typing import List
|
|
|
+
|
|
|
+from PIL import Image, ImageTk # 需要安装 Pillow 库
|
|
|
+
|
|
|
+from plat.base.base_control import AbsControl
|
|
|
+
|
|
|
+keys_mapping = {
|
|
|
+ "F1": "开仓滑竿",
|
|
|
+ "F2": "买入/开多",
|
|
|
+ "F3": "平仓滑竿",
|
|
|
+ "F4": "卖出/平多",
|
|
|
+ "F5": "开仓滑竿",
|
|
|
+ "F6": "开仓/开空",
|
|
|
+ "F7": "平仓滑竿",
|
|
|
+ "F8": "卖出/平空"
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+class Application(tk.Tk):
|
|
|
+ """
|
|
|
+ 页面布局
|
|
|
+ """
|
|
|
+
|
|
|
+ def __init__(self, controls=None):
|
|
|
+ super().__init__()
|
|
|
+ if controls is None:
|
|
|
+ controls = []
|
|
|
+ self._controls: List[AbsControl] = controls # 控件
|
|
|
+ self.content_frame = None
|
|
|
+ self.navigation_buttons = None
|
|
|
+ self.navigation_frame = None
|
|
|
+ self.title("群控小助手")
|
|
|
+ self.geometry("1366x768")
|
|
|
+
|
|
|
+ self.create_menu()
|
|
|
+ self.create_navigation()
|
|
|
+ self.create_content_area()
|
|
|
+ self._event_build()
|
|
|
+ self._content_cache = {} # 缓存内容
|
|
|
+
|
|
|
+ # ===========================
|
|
|
+ # adb 连接
|
|
|
+ # self.adb_serial = tk.StringVar()
|
|
|
+
|
|
|
+ def create_menu(self):
|
|
|
+ menubar = Menu(self)
|
|
|
+ self.config(menu=menubar)
|
|
|
+
|
|
|
+ menu1 = Menu(menubar, tearoff=0)
|
|
|
+ menu1.add_command(label="配置", command=lambda: self.more_click("配置"))
|
|
|
+ menu1.add_command(label="退出", command=self.quit)
|
|
|
+ menubar.add_cascade(label="管理", menu=menu1)
|
|
|
+
|
|
|
+ menu2 = Menu(menubar, tearoff=0)
|
|
|
+
|
|
|
+ def _bind_command(key, label):
|
|
|
+ menu2.add_command(label=label, accelerator=key, command=lambda k=key, v=label: self.more_click(k, v))
|
|
|
+
|
|
|
+ # 循环 keys_mapping 字典 ,生成菜单
|
|
|
+ for key, value in keys_mapping.items():
|
|
|
+ label = f"{value}({key})"
|
|
|
+ logging.info(f"生成菜单项:{label}")
|
|
|
+ _bind_command(key, label)
|
|
|
+
|
|
|
+ # key = "F1"
|
|
|
+ # label = f"开仓滑竿({key})"
|
|
|
+ # menu2.add_command(label=label, accelerator=key, command=lambda: self.more_click(key, label))
|
|
|
+ # key = "F2"
|
|
|
+ # label = f"买入/开多({key})"
|
|
|
+ # menu2.add_command(label=label, accelerator=key, command=lambda: self.more_click(key, label))
|
|
|
+ # key = "F3"
|
|
|
+ # label = f"平仓滑竿({key})"
|
|
|
+ # menu2.add_command(label=label, accelerator=key, command=lambda: self.more_click(key, label))
|
|
|
+ # key = "F4"
|
|
|
+ # label = f"卖出/平多({key})"
|
|
|
+ # menu2.add_command(label=label, accelerator=key, command=lambda: self.more_click(key, label))
|
|
|
+ # key = "F5"
|
|
|
+ # label = f"开仓滑竿({key})"
|
|
|
+ # menu2.add_command(label=label, accelerator=key, command=lambda: self.more_click(key, label))
|
|
|
+ # key = "F6"
|
|
|
+ # label = f"开仓/开空({key})"
|
|
|
+ # menu2.add_command(label=label, accelerator=key, command=lambda: self.more_click(key, label))
|
|
|
+ # key = "F7"
|
|
|
+ # label = f"平仓滑竿({key})"
|
|
|
+ # menu2.add_command(label=label, accelerator=key, command=lambda: self.more_click(key, label))
|
|
|
+ # key = "F8"
|
|
|
+ # label = f"卖出/平空({key})"
|
|
|
+ # menu2.add_command(label=label, accelerator=key, command=lambda: self.more_click(key, label))
|
|
|
+
|
|
|
+ menubar.add_cascade(label="操作", menu=menu2)
|
|
|
+
|
|
|
+ menu1 = Menu(menubar, tearoff=0)
|
|
|
+ menu1.add_command(label="关于", command=lambda: self.more_click('', "关于"))
|
|
|
+ menubar.add_cascade(label="帮助", menu=menu1)
|
|
|
+
|
|
|
+ # 多点击事件,循环调用
|
|
|
+ def more_click(self, key, msg):
|
|
|
+ print(msg)
|
|
|
+
|
|
|
+ for item in self._controls:
|
|
|
+ item.print_log(msg)
|
|
|
+ met_name = f'event_{key.lower()}'
|
|
|
+ if hasattr(item, met_name):
|
|
|
+ evt = getattr(item, met_name)
|
|
|
+ evt()
|
|
|
+ else:
|
|
|
+ print(f"实例 {item.name}没有名为 '{key}' 的方法")
|
|
|
+
|
|
|
+ def add_control(self, control: AbsControl):
|
|
|
+ self._controls.append(control)
|
|
|
+
|
|
|
+ def _event_build(self):
|
|
|
+
|
|
|
+ def _bind_command(key, label):
|
|
|
+ self.bind_all(f"<{key}>", lambda event: self.more_click(key, label))
|
|
|
+
|
|
|
+ for key, value in keys_mapping.items():
|
|
|
+ label = f"{value}({key})"
|
|
|
+ logging.info(f'绑定事件:{label}')
|
|
|
+ _bind_command(key, label)
|
|
|
+
|
|
|
+ # self.bind_all("<F2>", lambda event: self.more_click("买入/开多(F2)"))
|
|
|
+ # self.bind_all("<F3>", lambda event: self.more_click("平仓滑竿(F3)"))
|
|
|
+ # self.bind_all("<F4>", lambda event: self.more_click("卖出/平多(F4)"))
|
|
|
+ # self.bind_all("<F5>", lambda event: self.more_click("开仓滑竿(F5)"))
|
|
|
+ # self.bind_all("<F6>", lambda event: self.more_click("开仓/开空(F6)"))
|
|
|
+ # self.bind_all("<F7>", lambda event: self.more_click("平仓滑竿(F7)"))
|
|
|
+ # self.bind_all("<F8>", lambda event: self.more_click("卖出/平空(F8)"))
|
|
|
+
|
|
|
+ def create_navigation(self):
|
|
|
+ self.navigation_frame = tk.Frame(self, width=150, bg="#f0f0f0")
|
|
|
+ self.navigation_frame.pack(side=tk.LEFT, fill=tk.Y)
|
|
|
+
|
|
|
+ for item in self._controls:
|
|
|
+ # image = Image.open(item['logo'])
|
|
|
+ # photo = ImageTk.PhotoImage(image)
|
|
|
+ button = tk.Button(self.navigation_frame, text=item.name, command=lambda i=item: self.show_content(i), compound=tk.LEFT)
|
|
|
+ button.pack(fill=tk.X, pady=5)
|
|
|
+ # self.navigation_buttons.append(button)
|
|
|
+
|
|
|
+ def test_connect(self, control: AbsControl, serial: str, img: Label = None):
|
|
|
+
|
|
|
+ logging.info(f"测试连接:{serial}")
|
|
|
+
|
|
|
+ control.connect_adb(serial)
|
|
|
+
|
|
|
+ self.flush_screenshot(control, img)
|
|
|
+
|
|
|
+ def flush_screenshot(self, control: AbsControl, image_label: Label):
|
|
|
+ """
|
|
|
+ 刷新截图
|
|
|
+ """
|
|
|
+ control.screenshot()
|
|
|
+ try:
|
|
|
+ tmp = tempfile.gettempdir()
|
|
|
+ image = Image.open(f"{tmp}/{control.name}.png")
|
|
|
+ w = 380
|
|
|
+ image = image.resize((w, w * 16 // 9))
|
|
|
+ logging.info(f"刷新截图:{image}")
|
|
|
+ photo = ImageTk.PhotoImage(image)
|
|
|
+ image_label.config(image=photo)
|
|
|
+ image_label.image = photo # 保持对图片的引用
|
|
|
+ except FileNotFoundError:
|
|
|
+ logging.error(f"图片不存在")
|
|
|
+ pass
|
|
|
+
|
|
|
+ def create_content_area(self):
|
|
|
+ self.content_frame = tk.Frame(self)
|
|
|
+ self.content_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
|
|
|
+
|
|
|
+ def show_content(self, item: AbsControl):
|
|
|
+ print(f"---> {item.name},{self._content_cache}")
|
|
|
+ for key, value in self._content_cache.items():
|
|
|
+ if key != item.name:
|
|
|
+ value.pack_forget()
|
|
|
+ if item.name in self._content_cache:
|
|
|
+ content = self._content_cache[item.name]
|
|
|
+ content.pack(fill=tk.BOTH, expand=True)
|
|
|
+ else:
|
|
|
+ content = tk.Frame(self.content_frame)
|
|
|
+ content.pack(fill=tk.BOTH, expand=True)
|
|
|
+
|
|
|
+ # 表单区域
|
|
|
+ form_frame = tk.Frame(content)
|
|
|
+ form_frame.pack(side=tk.TOP, fill=tk.X)
|
|
|
+ # 设置第二列的权重
|
|
|
+ # form_frame.columnconfigure(1, weight=1)
|
|
|
+
|
|
|
+ tk.Label(form_frame, text="连接:").grid(row=0, column=0, sticky="w")
|
|
|
+ name_entry = Entry(form_frame, width=100)
|
|
|
+ name_entry.grid(row=0, column=1)
|
|
|
+ name_entry.insert(0, '127.0.0.1:6555')
|
|
|
+ # 图片预览区域
|
|
|
+ image_label = Label(content, width=200, height=380)
|
|
|
+ Button(form_frame, text="测试连接", command=lambda n=name_entry: self.test_connect(item, name_entry.get(), image_label)).grid(row=0, column=1, sticky="e")
|
|
|
+ Button(form_frame, text="查看手机", command=lambda n=name_entry: self.flush_screenshot(item, image_label)).grid(row=0, column=2, sticky="e")
|
|
|
+
|
|
|
+ # tk.Label(form_frame, text="年龄:").grid(row=1, column=0, sticky="w")
|
|
|
+ # age_entry = Entry(form_frame)
|
|
|
+ # age_entry.grid(row=1, column=1)
|
|
|
+ #
|
|
|
+ # Button(form_frame, text="保存").grid(row=2, column=1, sticky="e")
|
|
|
+
|
|
|
+ # 日志区域
|
|
|
+ log_text = Text(content, height=10)
|
|
|
+ log_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
|
|
+ log_text.insert(tk.END, f"导航 {item} 被点击\n")
|
|
|
+
|
|
|
+ item.set_log_func(lambda msg: log_text.insert(tk.END, f"{msg}\n"))
|
|
|
+
|
|
|
+ image_label.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
|
|
|
+
|
|
|
+ # self.flush_screenshot(image_label)
|
|
|
+
|
|
|
+ self._content_cache[item.name] = content # 缓存内容
|