settings.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. import logging
  2. import tkinter as tk
  3. from tkinter import ttk
  4. from typing import List
  5. from control.base.base_control import BaseControl, AbsControl
  6. from utils.config import version
  7. class _SettingsConnect(tk.Frame):
  8. """
  9. 连接云手机
  10. """
  11. def __init__(self, master=None, control: BaseControl = None, cnf=None, **kw):
  12. super().__init__(master, cnf if cnf is not None else {}, **kw)
  13. self.control = control
  14. self.init_ui()
  15. self.pack(padx=10, pady=10)
  16. def init_ui(self):
  17. """
  18. 初始化连接
  19. 云手机开启 ABD后无法自动识别,需要通过shell 连接一下。
  20. :return:
  21. """
  22. logging.info(f"连接云手机--->")
  23. content = ttk.Frame(self)
  24. content.pack(fill=tk.BOTH, expand=True)
  25. fieldset = ttk.LabelFrame(content, text="连接信息")
  26. fieldset.grid(row=0, column=0, padx=10, pady=10, sticky="nsew")
  27. content.grid_columnconfigure(0, weight=1)
  28. content.grid_rowconfigure(0, weight=1)
  29. fieldset.grid_columnconfigure(0, weight=1)
  30. fieldset.grid_rowconfigure(1, weight=1)
  31. cmd_label = ttk.Label(fieldset, text="ADB连接(一行一个):")
  32. cmd_label.grid(row=0, column=0, padx=5, pady=5, sticky="nw")
  33. cmd_text = tk.Text(fieldset, height=10)
  34. cmd_text.grid(row=1, column=0, columnspan=2, padx=5, pady=5, sticky="nsew")
  35. def insert_advice_list() -> None:
  36. devices = self.control.devices_list()
  37. if devices:
  38. for device in devices:
  39. cmd_text.insert(tk.END, f"adb connect {device}\n")
  40. auto_btn = ttk.Button(fieldset, text="检查连接", command=lambda: insert_advice_list())
  41. auto_btn.grid(row=2, column=1, padx=(5, 2), pady=5, sticky="nw")
  42. test_btn = ttk.Button(fieldset, text="连接云手机",
  43. command=lambda: self.control.init_adb(cmd_text.get('1.0', tk.END).split('\n'), log_text,
  44. **{'ui': self}))
  45. test_btn.grid(row=2, column=0, padx=(2, 5), pady=5, sticky="nw")
  46. # 日志区域
  47. log_label = ttk.Label(content, text="连接信息:")
  48. log_label.grid(row=1, column=0, padx=5, pady=5, sticky="nw")
  49. log_text = tk.Text(content, height=10)
  50. log_text.grid(row=2, column=0, padx=10, pady=(0, 10), sticky="nsew")
  51. content.grid_rowconfigure(2, weight=1)
  52. # def _connect_adb(self, cmd_text, log_text):
  53. # # 创建加载指示器
  54. #
  55. # def func():
  56. # self.control.init_adb(cmd_text.get('1.0', tk.END).split('\n'), log_text)
  57. #
  58. # self.control.loadding(self, func)
  59. # loading_window = tk.Toplevel(self)
  60. # loading_window.title("连接中")
  61. # loading_window.geometry("200x100")
  62. # loading_window.transient(self) # 设置为模态
  63. # loading_window.grab_set() # 设置为模态
  64. # loading_window.overrideredirect(True) # 移除窗口边框和按钮
  65. # # 相对于父窗口居中显示
  66. # window_width = loading_window.winfo_reqwidth()
  67. # window_height = loading_window.winfo_reqheight()
  68. # parent_x = self.winfo_rootx()
  69. # parent_y = self.winfo_rooty()
  70. # parent_width = self.winfo_width()
  71. # parent_height = self.winfo_height()
  72. # position_right = parent_x + (parent_width - window_width) // 2
  73. # position_down = parent_y + (parent_height - window_height) // 2
  74. # loading_window.geometry(f"+{position_right}+{position_down}")
  75. # loading_label = ttk.Label(loading_window, text="连接中...", padding=20)
  76. # loading_label.pack(expand=True)
  77. #
  78. # def thread_task():
  79. # try:
  80. # self.control.init_adb(cmd_text.get('1.0', tk.END).split('\n'), log_text)
  81. # finally:
  82. # # 在主线程中销毁加载指示器
  83. # self.after(0, lambda: [loading_window.grab_release(), loading_window.destroy()])
  84. #
  85. # import threading
  86. # thread = threading.Thread(target=thread_task)
  87. # # thread.daemon = True # 设置为守护线程,这样主程序退出时线程会自动结束
  88. # thread.start()
  89. class _SettingsKey(tk.Frame):
  90. """
  91. 设置快捷键
  92. """
  93. keys_mappings = {
  94. '买入/开多': {'ctrl': False, 'shift': False, 'alt': False, 'key': ''},
  95. '买入/平多': {'ctrl': False, 'shift': False, 'alt': False, 'key': ''},
  96. '卖出/开空': {'ctrl': False, 'shift': False, 'alt': False, 'key': ''},
  97. '卖出/平空': {'ctrl': False, 'shift': False, 'alt': False, 'key': ''},
  98. "一键撤单": {'ctrl': False, 'shift': False, 'alt': False, 'key': ''},
  99. '撤销委托': {'ctrl': False, 'shift': False, 'alt': False, 'key': ''},
  100. }
  101. def __init__(self, master=None, cnf=None, **kw):
  102. super().__init__(master, cnf if cnf is not None else {}, **kw)
  103. self.control = None
  104. self.init_ui()
  105. self.pack(padx=10, pady=10)
  106. def init_ui(self):
  107. # 快捷键设置
  108. fieldset = ttk.LabelFrame(self, text="快捷键设置")
  109. fieldset.grid(row=0, column=0, padx=10, pady=10, sticky="nsew")
  110. fieldset.grid_columnconfigure(0, weight=1)
  111. fieldset.grid_rowconfigure(1, weight=1)
  112. # 配置Checkbutton样式
  113. style = ttk.Style()
  114. style.configure("TCheckbutton", )
  115. # 循环 keys_mappings
  116. for i, (key, value) in enumerate(self.keys_mappings.items()):
  117. # 创建一个 frame 来保存当前行的所有控件
  118. row_frame = ttk.Frame(fieldset)
  119. row_frame.grid(row=i, column=0, sticky="ew", padx=5, pady=5)
  120. # 创建说明标签
  121. label = ttk.Label(row_frame, text=f"{key:<7}:")
  122. label.pack(side=tk.LEFT, padx=(0, 10))
  123. # 为每个按键组合创建变量并保存在字典中
  124. key_state = {
  125. 'name': key,
  126. 'ctrl_var': tk.BooleanVar(value=value['ctrl']),
  127. 'alt_var': tk.BooleanVar(value=value['alt']),
  128. 'shift_var': tk.BooleanVar(value=value['shift']),
  129. 'key_var': tk.StringVar(value=value['key'])
  130. }
  131. # 创建复选框
  132. ttk.Checkbutton(row_frame, text="Ctrl", variable=key_state['ctrl_var'],
  133. command=lambda state=key_state: self._on_checkbox_click(state)).pack(side=tk.LEFT, padx=5)
  134. ttk.Checkbutton(row_frame, text="Alt", variable=key_state['alt_var'],
  135. command=lambda state=key_state: self._on_checkbox_click(state)).pack(side=tk.LEFT, padx=5)
  136. ttk.Checkbutton(row_frame, text="Shift", variable=key_state['shift_var'],
  137. command=lambda state=key_state: self._on_checkbox_click(state)).pack(side=tk.LEFT, padx=5)
  138. # 创建下拉框
  139. options = [chr(i) for i in range(65, 91)] + [f"F{i}" for i in range(1, 13)]
  140. combo = ttk.Combobox(row_frame, textvariable=key_state['key_var'], values=options,
  141. width=8, state='readonly', )
  142. combo.bind('<<ComboboxSelected>>', lambda event, state=key_state: self._on_checkbox_click(state))
  143. # 如果key_state中已有值就使用已有值,否则设置为第一个选项
  144. if key_state['key_var'].get():
  145. combo.set(key_state['key_var'].get())
  146. else:
  147. combo.current(i) # 设置第一个选项为默认值
  148. combo.pack(side=tk.LEFT, padx=5)
  149. # idx = len(self.keys_mappings)
  150. # save_btn = ttk.Button(self, text="保存",
  151. # command=lambda: print('保存快捷键设置'))
  152. # save_btn.grid(row=idx + 1, column=0, padx=5, pady=5, sticky="nwe")
  153. # test_btn = ttk.Button(self, text="恢复默认",
  154. # command=lambda: print('恢复默认'))
  155. # test_btn.grid(row=idx + 2, column=0, padx=5, pady=5, sticky="nwe")
  156. def _on_checkbox_click(self, key_state: dict):
  157. """
  158. 复选框点击事件处理
  159. """
  160. # 获取当前状态
  161. name = key_state['name']
  162. ctrl_state = key_state['ctrl_var'].get()
  163. alt_state = key_state['alt_var'].get()
  164. shift_state = key_state['shift_var'].get()
  165. key = key_state['key_var'].get()
  166. # 更新映射
  167. self.keys_mappings[name].update({
  168. 'ctrl': ctrl_state,
  169. 'alt': alt_state,
  170. 'shift': shift_state,
  171. 'key': key
  172. })
  173. logging.info(f"快捷键 '{name}' 更新: Ctrl={ctrl_state}, Alt={alt_state}, Shift={shift_state}, Key={key}")
  174. self._key_binds(name)
  175. def _key_binds(self, name: str):
  176. """
  177. 绑定快捷键
  178. :param name:
  179. :return:
  180. """
  181. key = self.keys_mappings[name]
  182. logging.info(f"<UNK> '{key}' <UNK>")
  183. key_combo = []
  184. if key['ctrl']:
  185. key_combo.append('Control')
  186. if key['shift']:
  187. key_combo.append('Shift')
  188. if key['alt']:
  189. key_combo.append('Alt')
  190. # 组合所有激活的修饰键
  191. if key_combo:
  192. key_bind = f"<{'-'.join(key_combo)}-{key['key'].lower()}>"
  193. self.winfo_toplevel().unbind_all(key_bind)
  194. self.winfo_toplevel().bind_all(key_bind, lambda event: self._demo_click(f'-->{name}'))
  195. logging.info(f'绑定快捷键: {key_bind} --> {name}')
  196. else:
  197. # 如果没有修饰键,直接绑定键值
  198. self.winfo_toplevel().unbind_all(f"<{key['key'].lower()}>")
  199. self.winfo_toplevel().bind_all(f"<{key['key'].lower()}>", lambda event: self._demo_click(f'-->{name}'))
  200. logging.info(f"<{key['key']}=> {name} ")
  201. pass
  202. def _demo_click(self, event):
  203. logging.info(f"<DEMO> {event} <DEMO>")
  204. def _keys_binds(self, keys: List[dict]):
  205. """
  206. 返回快捷键映射
  207. :param keys: [{'ctrl':True,'shift':True,'alt':True,'key':'a'},...]
  208. :return:
  209. """
  210. # 循环 keys 绑定快捷键, self.control
  211. for i, key in enumerate(keys):
  212. # 绑定快捷键
  213. self.init_ui(keys)
  214. class _SettingsOther(tk.Frame):
  215. """
  216. 其他设置
  217. """
  218. def __init__(self, master=None, cnf=None, **kw):
  219. super().__init__(master, cnf if cnf is not None else {}, **kw)
  220. self.tel_connect = None
  221. self.control = None
  222. self.init_ui()
  223. def init_ui(self):
  224. # 创建并配置notebook
  225. notebook = ttk.Notebook(self)
  226. # 设置notebook的填充
  227. notebook.pack(anchor="w", fill=tk.BOTH, expand=True)
  228. class _SettingsAbout(tk.Frame):
  229. """
  230. 关于
  231. """
  232. def __init__(self, master=None, cnf=None, **kw):
  233. super().__init__(master, cnf if cnf is not None else {}, **kw)
  234. self.init_ui()
  235. self.pack(padx=10, pady=10)
  236. def init_ui(self):
  237. # 创建一个 Frame 来模拟 <fieldset>
  238. fieldset = ttk.LabelFrame(self, text="群控助手")
  239. fieldset.grid(row=0, column=0, padx=10, pady=10, sticky="nw")
  240. self.grid_columnconfigure(0, weight=1)
  241. self.grid_rowconfigure(0, weight=0)
  242. fieldset.grid_columnconfigure(0, weight=1)
  243. fieldset.grid_rowconfigure(1, weight=1)
  244. cmd_label = ttk.Label(fieldset, text=f"版本:{version}")
  245. cmd_label.grid(row=0, column=0, padx=5, pady=5, sticky="nw")
  246. cmd_label = ttk.Label(fieldset, text=f"作者:强哥")
  247. cmd_label.grid(row=2, column=0, padx=5, pady=5, sticky="nw")
  248. cmd_label = ttk.Label(fieldset, text=f"邮箱:fzxs88@yeah.net")
  249. cmd_label.grid(row=3, column=0, padx=5, pady=5, sticky="nw")
  250. class SettingUI(tk.Frame):
  251. """
  252. 设置页面
  253. """
  254. def __init__(self, master=None, control: BaseControl = None, cnf=None, **kw):
  255. super().__init__(master, cnf if cnf is not None else {}, **kw)
  256. self.about = None
  257. self.options = None
  258. self.key_mapping = None
  259. self.tel_connect = None
  260. self.control = control
  261. self.init_ui()
  262. def init_ui(self):
  263. # 创建并配置notebook
  264. notebook = ttk.Notebook(self)
  265. #
  266. # 设置notebook的填充
  267. notebook.pack(anchor="w", fill=tk.BOTH, expand=True)
  268. #
  269. # 第一个选项卡的内容
  270. self.tel_connect = ttk.Frame(notebook)
  271. notebook.add(self.tel_connect, text="连接云手机")
  272. _SettingsConnect(master=self.tel_connect, control=self.control)
  273. # 第二个选项卡的内容
  274. self.key_mapping = ttk.Frame(notebook)
  275. notebook.add(self.key_mapping, text="设置快捷键")
  276. _SettingsKey(self.key_mapping)
  277. # 第三个选项卡的内容
  278. self.options = ttk.Frame(notebook)
  279. notebook.add(self.options, text="其他设置")
  280. label3 = ttk.Label(self.options, text="其他设置")
  281. label3.pack(padx=10, pady=10)
  282. # 第四个选项卡的内容
  283. self.about = ttk.Frame(notebook)
  284. notebook.add(self.about, text="关于")
  285. _SettingsAbout(self.about)