| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- import logging
- import tkinter as tk
- from tkinter import ttk, messagebox
- from control.base.base_control import BaseControl, UIControl
- class LeftPanel(tk.LabelFrame):
- def __init__(self, master=None, control: UIControl = None):
- super().__init__(master, text="手机列表")
- self.scrollbar = None
- self.canvas = None
- self.list_frame = None
- self.control = control
- self.master = master
- self.phone_items_data = [] # 用于存储每个手机项的数据 (包含 CheckVar)
- self.create_widgets()
- self._check_scrollable() # 初始检查是否需要滚动条
- def create_widgets(self):
- title_label = ttk.Frame(self, relief="flat", borderwidth=1)
- title_label.grid(row=0, column=0, padx=10, pady=10, sticky="ew")
- # 添加分割线
- separator = ttk.Separator(title_label, orient="horizontal")
- separator.grid(row=1, column=0, columnspan=4, sticky="ew", padx=5, pady=5)
- name_label = ttk.Label(title_label, text='全选')
- name_label.grid(row=0, column=1, padx=5, pady=10, sticky="e")
- # 选择框
- check_all = tk.BooleanVar()
- check_button = ttk.Checkbutton(title_label, variable=check_all,
- command=lambda v=check_all: self.toggle_check(v))
- check_button.grid(row=0, column=2, padx=5, pady=10, sticky="e")
- # 添加数据按钮
- add_data_button = ttk.Button(title_label, text="刷新", command=self.flush_data)
- add_data_button.grid(row=0, column=3, padx=5, pady=10, sticky="e")
- # 创建 Canvas 和 Scrollbar
- self.canvas = tk.Canvas(self)
- self.scrollbar = ttk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
- self.canvas.configure(yscrollcommand=self.scrollbar.set)
- self.canvas.grid(row=1, column=0, columnspan=4, sticky="nsew")
- self.scrollbar.grid(row=1, column=4, sticky="ns")
- # 创建 Frame 放入 Canvas 中
- self.list_frame = ttk.Frame(self.canvas)
- self.canvas.create_window((0, 0), window=self.list_frame, anchor="nw")
- self.list_frame.bind("<Configure>", self._on_frame_configure)
- self.canvas.bind("<Enter>", self._bind_mousewheel_enter)
- self.canvas.bind("<Leave>", self._bind_mousewheel_leave)
- # 配置 Grid 的行和列的权重,使 Canvas 可以扩展
- self.grid_rowconfigure(1, weight=1)
- self.grid_columnconfigure(0, weight=1)
- self.grid_columnconfigure(1, weight=0) # 全选按钮不扩展
- self.grid_columnconfigure(2, weight=0) # 添加数据按钮不扩展
- self.grid_columnconfigure(3, weight=0) # 取消全选按钮不扩展
- self.grid_columnconfigure(4, weight=0) # 滚动条列不扩展
- self._populate_list()
- def _populate_list(self):
- """根据 self.phone_data 填充列表"""
- for widget in self.list_frame.winfo_children():
- widget.destroy()
- self.phone_items_data = []
- # for phone in self.phone_data:
- # self.create_list_item(phone["name"], phone["status"])
- logging.info(f"发现连接手机:{BaseControl.connect_dict}")
- for pkg, device in BaseControl.connect_dict.items():
- logging.info(f'==添加手机信息=>{pkg} {device}')
- self.create_list_item(device)
- self._on_frame_configure(None) # 更新滚动区域
- def create_list_item(self, device):
- item_frame = ttk.Frame(self.list_frame, padding=(5, 5))
- item_frame.pack(fill="x", expand=True)
- status = device['status']
- # 选择框
- check_var = tk.BooleanVar()
- check_var.set(True)
- check_button = ttk.Checkbutton(item_frame, variable=check_var)
- check_button.pack(side="left")
- # 手机名称
- name_label = ttk.Label(item_frame, text=f'{device["name"]}:【{device["pkg"]}】', anchor="w", width=20)
- name_label.pack(side="left", padx=5)
- # 状态指示器
- status_canvas = tk.Canvas(item_frame, width=10, height=10, highlightthickness=0)
- status_canvas.pack(side="left", padx=5)
- if status == "online":
- status_canvas.create_oval(0, 0, 10, 10, fill="green")
- else:
- status_canvas.create_oval(0, 0, 10, 10, fill="red")
- # 状态按钮 (这里我们用一个简单的 Label 模拟)
- status_button = ttk.Label(item_frame, text="@", width=3, anchor="center", relief="groove")
- status_button.pack(side="right", padx=5)
- self.phone_items_data.append((check_var, device["serial"], status)) # 存储 CheckVar 和数据
- def toggle_check(self, check_var):
- if check_var.get():
- print("复选框被选中")
- else:
- print("复选框被取消选中")
- for var, _, _ in self.phone_items_data:
- var.set(check_var.get())
- pass
- def flush_data(self):
- """
- 刷新数据
- """
- self._populate_list() # 重新填充列表以显示新数据
- self._check_scrollable() # 添加数据后检查是否需要滚动条
- def _on_frame_configure(self, event):
- """当列表 Frame 大小改变时,更新 Canvas 的滚动区域并检查是否需要绑定滚轮事件"""
- self.canvas.configure(scrollregion=self.canvas.bbox("all"))
- self._check_scrollable()
- def _check_scrollable(self):
- """检查内容是否需要滚动条,并决定是否需要显示"""
- if self.canvas.winfo_height() < self.canvas.bbox("all")[3]:
- self.scrollbar.grid(row=1, column=4, sticky="ns") # 显示滚动条
- else:
- self.scrollbar.grid_remove() # 隐藏滚动条
- def _bind_mousewheel_enter(self, event):
- """鼠标进入 Canvas 时绑定滚轮事件"""
- if self.canvas.winfo_height() < self.canvas.bbox("all")[3]: # 只有在需要滚动时才绑定
- self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
- self.canvas.bind_all("<Button-4>", self._on_mousewheel) # Linux
- self.canvas.bind_all("<Button-5>", self._on_mousewheel) # Linux
- def _bind_mousewheel_leave(self, event):
- """鼠标离开 Canvas 时解绑滚轮事件"""
- self.canvas.unbind_all("<MouseWheel>")
- self.canvas.unbind_all("<Button-4>")
- self.canvas.unbind_all("<Button-5>")
- def _on_mousewheel(self, event):
- """鼠标滚轮滚动事件处理"""
- if event.delta:
- self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
- else:
- if event.num == 4:
- self.canvas.yview_scroll(-1, "units")
- elif event.num == 5:
- self.canvas.yview_scroll(1, "units")
- class RightPanel(tk.Frame):
- def __init__(self, master=None, control: UIControl = None, *args, **kwargs):
- super().__init__(master, *args, **kwargs)
- self._num_text = None
- self.control = control
- self.master = master
- self.create_args()
- self.create_info_ares()
- self.grid_columnconfigure(0, weight=1) # 让列可以水平扩展
- self.grid_rowconfigure(0, weight=0) # 参数设定区域不需要扩展
- self.grid_rowconfigure(1, weight=1) # 让操作区域可以垂直扩展
- def create_args(self):
- fieldset = ttk.LabelFrame(self, text="参数设定")
- fieldset.grid(row=0, column=0, padx=10, pady=10, sticky="nsew")
- # fieldset.grid_columnconfigure(0, weight=1)
- # fieldset.grid_rowconfigure(1, weight=1)
- # name_label = ttk.Label(fieldset, text="币种:", width=5)
- # name_label.grid(row=0, column=0, padx=5, pady=5, sticky="nw")
- #
- # name_val = tk.Text(fieldset, width=20, height=1.2, wrap='word')
- # name_val.grid(row=0, column=1, padx=5, pady=5, sticky="nw")
- # name_val.insert('1.0', 'HMSTR') # 插入文本
- # name_val.config(state='disabled') # 再禁用
- num_label = ttk.Label(fieldset, text="数量:", width=5)
- num_label.grid(row=0, column=1, padx=5, pady=5, sticky="nw")
- num_text = tk.Text(fieldset, height=1.2, width=10, wrap='word')
- num_text.grid(row=0, column=2, padx=5, pady=5, sticky="nw")
- # button1 = ttk.Button(fieldset, text="设置", command=lambda: print('----'))
- # button1.grid(row=0, column=3, padx=2, pady=(5, 2), sticky="ew")
- self._num_text = num_text
- def create_info_ares(self):
- # 创建一个 Frame 来模拟 <fieldset>
- fieldset = ttk.Frame(self)
- fieldset.grid(row=1, column=0, padx=10, pady=10, sticky="nsew")
- # 设置 fieldset 的网格权重配置
- fieldset.grid_columnconfigure(1, weight=3) # 让信息区域占据更多水平空间
- fieldset.grid_columnconfigure(0, weight=1) # 操作区域占据较少水平空间
- fieldset.grid_rowconfigure(0, weight=1) # 让内容区域可以垂直扩展
- fieldset_action = ttk.LabelFrame(fieldset, text="操作")
- fieldset_action.grid(row=0, column=0, padx=10, pady=10, sticky="new")
- # 设置列权重使按钮平分宽度
- fieldset_action.grid_columnconfigure(0, weight=1)
- fieldset_action.grid_columnconfigure(1, weight=1)
- fieldset_log = ttk.LabelFrame(fieldset, text="操作日志")
- fieldset_log.grid(row=0, column=1, padx=10, pady=10, sticky="nsew")
- fieldset_log.grid_columnconfigure(0, weight=1) # 文本框列可扩展
- fieldset_log.grid_rowconfigure(1, weight=1) # 文本框行可扩展
- # 给fieldset_log 添加一个多行文本区域
- log_text = tk.Text(fieldset_log, wrap='word')
- log_text.grid(row=1, column=0, padx=5, pady=5, sticky="nsew")
- log_text_scroll = ttk.Scrollbar(fieldset_log, command=log_text.yview)
- log_text_scroll.grid(row=1, column=1, sticky="ns")
- log_text.config(yscrollcommand=log_text_scroll.set)
- def handle_keypress(event):
- if event.keysym in ('Return', 'KP_Enter'):
- log_text.insert('end', '\n')
- return 'break'
- return None
- log_text.bind('<KeyPress>', handle_keypress)
- log_text.focus_set() # 让文本框获得焦点
- log_text.focus_set() # 让文本框获得焦点
- # 给fieldset_action 添加7个按钮,每行2个 共3行
- green_btn_style = ttk.Style()
- green_btn_style.configure('Green.TButton', background='#00cc00', foreground='#009900')
- red_btn_style = ttk.Style()
- red_btn_style.configure('Red.TButton', background='#ff4444', foreground='#cc0000')
- gray_btn_style = ttk.Style()
- gray_btn_style.configure('Gray.TButton', background='#888888', foreground='#666666')
- def check_number(text):
- try:
- float(text) # 尝试转换为浮点数,可以接受整数和小数
- return True
- except ValueError:
- return False
- def fun1():
- num = self._num_text.get("1.0", "end").rstrip()
- if not check_number(num):
- messagebox.showinfo("提示", "请输入数量!")
- return
- self.control.event_2(**{
- 'shuliang': num,
- 'log': log_text,
- })
- button1 = ttk.Button(fieldset_action, text="买入/开多", command=lambda: fun1(), style='Green.TButton')
- button1.grid(row=0, column=0, padx=2, pady=(5, 2), sticky="ew")
- def fun2():
- num = self._num_text.get("1.0", "end").rstrip()
- if not check_number(num):
- messagebox.showinfo("提示", "请输入数量!")
- return
- self.control.event_4(**{
- 'shuliang': num,
- 'log': log_text,
- })
- button2 = ttk.Button(fieldset_action, text="买入/平多", command=lambda: fun2(), style='Green.TButton')
- button2.grid(row=0, column=1, padx=2, pady=(5, 2), sticky="ew")
- def fun3():
- num = self._num_text.get("1.0", "end").rstrip()
- if not check_number(num):
- messagebox.showinfo("提示", "请输入数量!")
- return
- self.control.event_6(**{
- 'shuliang': num,
- 'log': log_text,
- })
- button3 = ttk.Button(fieldset_action, text="卖出/开空", command=lambda: fun3(), style='Red.TButton')
- button3.grid(row=1, column=0, padx=2, pady=2, sticky="ew")
- def fun4():
- num = self._num_text.get("1.0", "end").rstrip()
- if not check_number(num):
- messagebox.showinfo("提示", "请输入数量!")
- return
- self.control.event_8(**{
- 'shuliang': num,
- 'log': log_text,
- })
- button4 = ttk.Button(fieldset_action, text="卖出/平空", command=lambda: fun4(), style='Red.TButton')
- button4.grid(row=1, column=1, padx=2, pady=2, sticky="ew")
- button5 = ttk.Button(fieldset_action, text="一键全平", command=lambda: self.control.event_11(**{
- 'shuliang': self._num_text.get("1.0", "end").rstrip(),
- 'log': log_text,
- }))
- button5.grid(row=2, column=0, padx=2, pady=(2, 5), sticky="ew")
- button6 = ttk.Button(fieldset_action, text="一键撤单", command=lambda: self.control.event_9(**{
- 'shuliang': self._num_text.get("1.0", "end").rstrip(),
- 'log': log_text,
- }))
- button6.grid(row=2, column=1, padx=2, pady=(2, 5), sticky="ew")
- class PhoneListUI(tk.Frame):
- """
- 手机列表控制页面
- """
- def __init__(self, control: UIControl = None, master=None, cnf=None, **kw):
- super().__init__(master, cnf if cnf is not None else {}, **kw)
- self.right_panel = None
- self.left_panel = None
- self.control = control
- self.init_ui()
- def init_ui(self):
- self.left_panel = LeftPanel(self, control=self.control)
- self.left_panel.pack(side="left", fill="y")
- # 为了演示,我们创建一个简单的右侧区域
- self.right_panel = RightPanel(self, width=400, height=400, control=self.control)
- self.right_panel.pack(side="left", fill="both", expand=True)
|