12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259 |
- import time
- import conf
- import cv2
- import random
- import traceback
- import abc
- import tkinter as tk
- from tkinter import ttk
- import datetime
- from PIL import Image, ImageTk
- from tool.type_ import *
- from tool.tk import set_tk_disable_from_list, make_font
- from core.user import User, UserNotSupportError
- from core.garbage import GarbageBag, GarbageType, GarbageBagNotUse
- from sql.db import DB
- from sql.user import update_user, find_user_by_id
- from sql.garbage import update_garbage
- from equipment.scan import HGSCapture, HGSQRCoder
- from event import TkEventMain
- class GarbageStationException(Exception):
- ...
- class ControlNotLogin(GarbageStationException):
- ...
- class ThrowGarbageError(GarbageStationException):
- ...
- class CheckGarbageError(GarbageStationException):
- ...
- class RankingUserError(GarbageStationException):
- ...
- class GarbageStationBase(TkEventMain, metaclass=abc.ABCMeta):
- status_normal = 1
- status_get_garbage_type = 2
- status_get_garbage_check = 3
- scan_switch_user = 1
- scan_throw_garbage = 2
- scan_check_garbage = 3
- scan_no_to_done = 4
- def __init__(self,
- db: DB,
- cap: HGSCapture,
- qr: HGSQRCoder,
- loc: location_t = conf.base_location):
- self._db: DB = db
- self._cap: HGSCapture = cap
- self._qr: HGSQRCoder = qr
- self._loc: location_t = loc
- self._user: Optional[User] = None # 操作者
- self._user_last_time: time_t = 0
- self._garbage: Optional[GarbageBag] = None
- self._flat = GarbageStationBase.status_normal
- self._have_easter_eggs = False
- self.rank = None
- self.rank_index = 0
- super(GarbageStationBase, self).__init__()
- def get_db(self):
- return self._db
- def update_user_time(self):
- if self.check_user():
- self._user_last_time = time.time()
- def get_user(self):
- return self._user
- def is_manager(self):
- if not self.check_user():
- return False
- return self._user.is_manager()
- def check_user(self):
- if self._user is None:
- return False
- if not self._user.is_manager() and time.time() - self._user_last_time > 20:
- self._user = None
- return False
- return True
- def __check_user(self):
- if not self.check_user():
- raise ControlNotLogin
- self._user_last_time = time.time()
- def __check_normal_user(self):
- self.__check_user()
- if self._user.is_manager():
- raise UserNotSupportError
- def __check_manager_user(self):
- self.__check_user()
- if not self._user.is_manager():
- raise UserNotSupportError
- def get_user_info(self):
- self.__check_user()
- return self._user.get_info()
- def get_uid_no_update(self):
- if not self.check_user():
- return ""
- return self._user.get_uid()
- def get_user_info_no_update(self) -> Dict[str, str]:
- if not self.check_user():
- return {}
- return self._user.get_info()
- def get_cap_img(self):
- return self._cap.get_frame()
- def switch_user(self, user: User) -> bool:
- """
- 切换用户: 退出/登录
- :param user: 新用户
- :return: 登录-True, 退出-False
- """
- if self._user is not None and self._user.get_uid() == user.get_uid() and self.check_user(): # 正在登陆期
- self._user = None # 退出登录
- self._user_last_time = 0
- return False
- self._user = user
- self._user_last_time = time.time()
- return True # 登录
- def throw_garbage_core(self, garbage: GarbageBag, garbage_type: enum):
- self.__check_normal_user()
- if not self._user.throw_rubbish(garbage, garbage_type, self._loc):
- raise ThrowGarbageError
- update_garbage(garbage, self._db)
- update_user(self._user, self._db)
- def check_garbage_core(self, garbage: GarbageBag, check_result: bool):
- self.__check_manager_user()
- user = find_user_by_id(garbage.get_user(), self._db)
- if user is None:
- raise GarbageBagNotUse
- if not self._user.check_rubbish(garbage, check_result, user):
- raise CheckGarbageError
- update_garbage(garbage, self._db)
- update_user(self._user, self._db)
- update_user(user, self._db)
- def ranking(self, limit: int = 0, order_by: str = 'DESC') -> list[Tuple[uid_t, uname_t, score_t, score_t]]:
- """
- 获取排行榜的功能
- :return:
- """
- if limit > 0:
- limit = f"LIMIT {int(limit)}"
- else:
- limit = ""
- if order_by != 'ASC' and order_by != 'DESC':
- order_by = 'DESC'
- cur = self._db.search((f"SELECT UserID, Name, Score, Reputation "
- f"FROM user "
- f"WHERE IsManager = 0 "
- f"ORDER BY Reputation {order_by}, Score {order_by} "
- f"{limit}"))
- if cur is None:
- raise RankingUserError
- return list(cur.fetchall())
- def to_get_garbage_type(self, garbage: GarbageBag):
- self._flat = GarbageStationBase.status_get_garbage_type
- self.set_garbage(garbage)
- def to_get_garbage_check(self, garbage: GarbageBag):
- self._flat = GarbageStationBase.status_get_garbage_check
- self.set_garbage(garbage)
- def set_garbage(self, garbage: GarbageBag):
- self._garbage = garbage
- def get_garbage(self) -> Optional[GarbageBag]:
- if not self.check_user():
- self._garbage = None
- return self._garbage
- def throw_garbage(self, garbage_type: enum):
- self.update_user_time()
- if self._flat != GarbageStationBase.status_get_garbage_type or self._garbage is None:
- self.show_warning("操作失败", "请先登录, 扫描垃圾袋")
- return
- event = tk_event.ThrowGarbageEvent(self).start(self._garbage, garbage_type)
- self.push_event(event)
- self._flat = GarbageStationBase.status_normal
- self._garbage = None
- def check_garbage(self, check: bool):
- self.update_user_time()
- if self._flat != GarbageStationBase.status_get_garbage_check or self._garbage is None:
- self.show_warning("操作失败", "请先登录, 扫描垃圾袋")
- return
- event = tk_event.CheckGarbageEvent(self).start(self._garbage, check)
- self.push_event(event)
- self._flat = GarbageStationBase.status_normal
- self._garbage = None
- def show_garbage_info(self):
- self.update_user_time()
- if self._flat != GarbageStationBase.status_get_garbage_check or self._garbage is None:
- self.show_warning("操作失败", "请先登录, 扫描垃圾袋")
- return
- if not self._garbage.is_use():
- self.show_warning("操作失败", "垃圾袋还未被使用")
- return
- info = self._garbage.get_info()
- garbage_type = GarbageType.GarbageTypeStrList_ch[int(info['type'])]
- if self._garbage.is_check():
- time_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(float(info['use_time'])))
- check = f'Checker is f{info["checker"][0:conf.tk_show_uid_len]}\n'
- if info["check"] == '1':
- check += f'检查结果为 投放正确\n'
- else:
- check += f'检查结果为 投放错误\n'
- self.show_msg("垃圾袋信息", (f"垃圾类型为 {garbage_type}\n"
- f"用户是 {info['user'][0:conf.tk_show_uid_len]}\n"
- f"地址:\n {info['loc']}\n"
- f"{check}"
- f"使用日期:\n {time_str}"), show_time=5.0) # 遮蔽Pass和Fail按键
- elif self._garbage.is_use():
- time_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(float(info['use_time'])))
- self.show_msg("垃圾袋信息", (f"垃圾类型为 {garbage_type}\n"
- f"用户是 {info['user'][0:conf.tk_show_uid_len]}\n"
- f"地址:\n {info['loc']}\n"
- f"垃圾袋还未检查\n"
- f"使用日期:\n {time_str}"), big=False, show_time=5.0) # 不遮蔽Pass和Fail按键
- else:
- self.show_msg("垃圾袋信息", f"垃圾袋还未使用", show_time=5.0) # 遮蔽Pass和Fail按键
- def show_user_info(self):
- self.update_user_time()
- if not self.check_user():
- self.show_warning("操作失败", "请先登录")
- return
- info = self.get_user_info()
- if info.get('manager', '0') == '1':
- self.show_msg("About User", (f"管理者用户\n"
- f"用户名: {info['name']}\n"
- f"用户ID:\n {info['uid']}"), show_time=5.0)
- else:
- self.show_msg("About User", (f"普通用户\n"
- f"用户名: {info['name']}\n"
- f"用户ID:\n {info['uid']}\n"
- f"评分: {info['score']}\n"
- f"垃圾分类信用: {info['reputation']}\n"
- f"垃圾量(7天): {info['rubbish']}"), show_time=5.0)
- def show_help_info(self):
- self.update_user_time()
- self.show_msg("帮助", f'''
- 所有用户: 离开前请确保账户退出(再次扫描用户二维码退出登录)
-
- 投放垃圾使用说明(普通用户):
- 1) 扫码用户二维码登录
- 2) 扫码垃圾袋二维码
- 3) 选择垃圾类型
- 4) 投放垃圾到垃圾桶 (投放完成, 可以离开或继续投放)
- 5) 等待结果反馈 (可能需要数日)
-
- 检测垃圾使用说明(管理用户):
- 1) 扫码用户二维码登录
- 2) 扫码垃圾袋二维码
- 3) 检查垃圾是否投放正确
- 4) 操作完成 (投放完成, 可以离开或继续投放)
- '''.strip(), show_time=60.0)
- def show_about_info(self):
- self.update_user_time()
- self.show_msg("关于", conf.about_info, show_time=5.0)
- def show_exit(self):
- self.update_user_time()
- if self.is_manager():
- self.exit_win()
- return
- self.show_warning("退出", f'用户不具有退出权限')
- def easter_eggs(self):
- self.update_user_time()
- if (not self._have_easter_eggs) and random.randint(0, 10) != 1: # 10% 概率触发
- return
- self._have_easter_eggs = True
- self.show_msg("Easter Agg", f'''
- 恭喜触发彩蛋
- 尝试一下新的编程语言: aFunlang.
- 来自: github
- [斯人若彩虹, 遇上方知有]
- [期待再次与你相遇]
- '''.strip(), show_time=15.0)
- def show_search_info(self):
- self.update_user_time()
- self.show_msg("搜索", f'''
- 搜索功能将根据摄像头获取物品信息, 反馈该物品垃圾类型。
- 该功能尚未开放, 敬请期待
- '''.strip(), show_time=5.0)
- def thread_show_rank(self, rank_list):
- self.rank = [[]]
- for i, r in enumerate(rank_list):
- if len(self.rank[-1]) == 5:
- self.rank.append([])
- color = None
- if i == 0:
- color = "#eaff56"
- elif i == 1:
- color = "#ffa631"
- elif i == 2:
- color = "#ff7500"
- elif r[0] == self.get_uid_no_update():
- color = "#b0a4e3"
- self.rank[-1].append((i + 1, r[1], r[0], r[2], r[3], color))
- if len(self.rank[0]) == 0:
- self.rank = None
- self.show_warning("排行榜错误", f'无法获取排行榜信息')
- return
- self.rank_index = 0
- self.get_rank(0)
- def get_rank(self, n: int):
- self.update_user_time()
- self.rank_index += n
- if self.rank_index < 0 or self.rank_index >= len(self.rank):
- self.show_warning("排行榜错误", f'无法获取排行榜信息')
- return
- self.show_rank(self.rank_index + 1, len(self.rank), self.rank[self.rank_index])
- def scan(self):
- """
- 处理扫码事务
- 二维码扫描的任务包括: 登录, 扔垃圾, 标记垃圾
- :return:
- """
- self._cap.get_image()
- qr_code = self._qr.get_qr_code()
- if qr_code is None:
- return GarbageStationBase.scan_no_to_done, None
- user_scan_event = tk_event.ScanUserEvent(self).start(qr_code)
- self.push_event(user_scan_event)
- def get_show_rank(self):
- event = tk_event.RankingEvent(self)
- self.push_event(event)
- @abc.abstractmethod
- def show_msg(self, title, info, msg_type='info', big: bool = True, show_time: float = 10.0):
- ...
- @abc.abstractmethod
- def show_warning(self, title, info, show_time: float = 15.0):
- ...
- @abc.abstractmethod
- def show_rank(self, page: int, page_c: int,
- rank_info: List[Tuple[int, uname_t, uid_t, score_t, score_t, Optional[str]]],
- title: str = '排行榜'):
- ...
- @abc.abstractmethod
- def hide_msg_rank(self, update: bool = False):
- ...
- @abc.abstractmethod
- def show_loading(self, title: str):
- ...
- @abc.abstractmethod
- def stop_loading(self):
- ...
- @abc.abstractmethod
- def set_after_run(self, ms, func, *args):
- ...
- @abc.abstractmethod
- def update_control(self):
- ...
- @abc.abstractmethod
- def update_scan(self):
- ...
- @abc.abstractmethod
- def update_msg(self):
- ...
- @abc.abstractmethod
- def mainloop(self):
- ...
- @abc.abstractmethod
- def exit_win(self):
- ...
- import station_event as tk_event
- class GarbageStation(GarbageStationBase):
- """
- GarbageStation 垃圾站系统
- 使用tkinter作为GUI
- """
- def set_after_run(self, ms, func, *args): # 正常运行前设置定时任务 super.__init__可能会调用
- self.init_after_run_list.append((ms, func, args))
- def __conf_set_after_run(self): # 配合 set_after_run 使用
- for ms, func, args in self.init_after_run_list:
- self.set_after_run_now(ms, func, *args)
- def set_after_run_now(self, ms, func, *args): # 正常运行时设置定时任务
- self._window.after(ms, func, *args)
- def __init__(self,
- db: DB,
- cap: HGSCapture,
- qr: HGSQRCoder,
- loc: location_t = conf.base_location,
- refresh_delay: int = conf.tk_refresh_delay):
- self.init_after_run_list: List[Tuple[int, Callable, Tuple]] = []
- super(GarbageStation, self).__init__(db, cap, qr, loc)
- self.refresh_delay = refresh_delay
- self._window = tk.Tk() # 系统窗口
- self._sys_height = self._window.winfo_screenheight()
- self._sys_width = self._window.winfo_screenwidth()
- self._win_height = int(self._sys_height * (2 / 3)) # 窗口高度
- self._win_width = int(self._sys_width * (2 / 3)) # 窗口宽度
- self._full_screen = False # 是否全屏模式
- self.__conf_windows()
- self._cap_img = None # 存储 PIL.image 的变量 防止gc释放
- self._user_im = None
- self._msg_time: Optional[float] = None # msg 显示时间累计
- self._msg_show_time: float = 10.0
- self._disable_all_btn: bool = False # 禁用所有按钮和操作
- self.__conf_font_size() # 配置字体大小
- self.__create_tk() # 创建组件
- self.__conf_tk() # 配置组件
- self.__conf_after()
- self.__conf_set_after_run()
- self.__switch_to_no_user()
- def __create_tk(self):
- """
- 创建tkinter组件
- 该函数只被 __init__ 调用
- """
- self._title_label = tk.Label(self._window) # 标题
- # 窗口操纵
- self._win_ctrl_button: List[tk.Button, tk.Button, tk.Button] = [tk.Button(self._window),
- tk.Button(self._window),
- tk.Button(self._window)]
- # 用户信息显示框
- win_info_type = Tuple[tk.Label, tk.Label, tk.Variable, str]
- self._user_frame = tk.Frame(self._window)
- self._user_name: win_info_type = (tk.Label(self._user_frame), tk.Label(self._user_frame),
- tk.StringVar(), "用户名")
- self._user_uid: win_info_type = (tk.Label(self._user_frame), tk.Label(self._user_frame),
- tk.StringVar(), "用户ID")
- self._user_score: win_info_type = (tk.Label(self._user_frame), tk.Label(self._user_frame),
- tk.StringVar(), "积分")
- self._user_rubbish: win_info_type = (tk.Label(self._user_frame), tk.Label(self._user_frame),
- tk.StringVar(), "垃圾量(7天)")
- self._user_eval: win_info_type = (tk.Label(self._user_frame), tk.Label(self._user_frame),
- tk.StringVar(), "垃圾分类信用")
- self._user_img = tk.Label(self._user_frame)
- # 扔垃圾相关按钮 (可回收, 不可回收, 有害垃圾, 厨余垃圾)
- self._throw_ctrl_frame = tk.Frame(self._window)
- self._throw_ctrl_btn: List[tk.Button] = [tk.Button(self._throw_ctrl_frame), tk.Button(self._throw_ctrl_frame),
- tk.Button(self._throw_ctrl_frame), tk.Button(self._throw_ctrl_frame)]
- # 确认垃圾相关按钮 (通过, 不通过)
- self._check_ctrl_frame = tk.Frame(self._window)
- self._check_ctrl_btn: List[tk.Button] = [tk.Button(self._check_ctrl_frame), tk.Button(self._check_ctrl_frame)]
- # 系统信息显示框 (垃圾袋ID和当前时间)
- self._sys_info_frame = tk.Frame(self._window)
- self._garbage_id: win_info_type = (tk.Label(self._sys_info_frame), tk.Label(self._sys_info_frame),
- tk.StringVar(), "垃圾袋ID")
- self._sys_date: win_info_type = (tk.Label(self._sys_info_frame), tk.Label(self._sys_info_frame),
- tk.StringVar(), "系统时间")
- # 摄像头显示
- self._cap_label = tk.Label(self._window)
- # 用户操纵按钮
- self._user_btn_frame = tk.Frame(self._window)
- self._user_btn: List[tk.Button] = [tk.Button(self._user_btn_frame), tk.Button(self._user_btn_frame),
- tk.Button(self._user_btn_frame)]
- # 消息提示框
- self._msg_frame = tk.Frame(self._window)
- self._msg_line = tk.Label(self._msg_frame)
- self._msg_label: Tuple[tk.Label, tk.Text, tk.Variable] = (tk.Label(self._msg_frame),
- tk.Text(self._msg_frame),
- tk.StringVar())
- self._msg_y_scroll = tk.Scrollbar(self._msg_frame)
- self._msg_x_scroll = tk.Scrollbar(self._msg_frame)
- self._msg_hide = tk.Button(self._msg_frame)
- # 排行榜
- self._rank_frame = tk.Frame(self._window)
- self._rank_label = [tk.Label(self._rank_frame),
- tk.Label(self._rank_frame),
- tk.Label(self._rank_frame),
- tk.Label(self._rank_frame),
- tk.Label(self._rank_frame),
- tk.Label(self._rank_frame)]
- self._rank_var = [tk.StringVar(),
- tk.StringVar(),
- tk.StringVar(),
- tk.StringVar(),
- tk.StringVar(),
- tk.StringVar()]
- self._rank_btn = [tk.Button(self._rank_frame), tk.Button(self._rank_frame), tk.Button(self._rank_frame)]
- # 进度条
- self._loading_frame = tk.Frame(self._window)
- self._loading_line = tk.Label(self._loading_frame)
- self._loading_title: Tuple[tk.Label, tk.Variable] = tk.Label(self._loading_frame), tk.StringVar()
- self._loading_pro = ttk.Progressbar(self._loading_frame)
- def __conf_font_size(self, n: Union[int, float] = 1):
- """
- 设置字体大小
- :param n: 缩放因子, 1为不缩放
- :return:
- """
- self._title_font_size = int(27 * n) # 标题
- self._win_ctrl_font_size = int(15 * n) # 控制按键
- self._win_info_font_size = int(18 * n) # 用户信息
- self._throw_ctrl_btn_font_size = int(20 * n) # 扔垃圾相关按钮
- self._check_ctrl_btn_font_size = int(20 * n) # 检查垃圾相关按钮
- self._sys_info_font_size = int(18 * n) # 系统信息
- self._user_btn_font_size = int(20 * n) # 用户按键
- self._msg_font_size = int(20 * n) # 消息提示框
- self._rank_font_title_size = int(24 * n) # 排行榜标题
- self._rank_font_size = int(16 * n) # 排行榜内容
- self._loading_tile_font = int(20 * n) # 进度条
- def __conf_tk(self):
- """
- 配置(绘制)窗口
- 当切换全屏或启动界面时需要调用
- :return:
- """
- self.__conf_title_label()
- self.__conf_win_ctrl_button()
- self.__conf_user_info_label()
- self.__conf_throw_btn()
- self.__conf_check_btn()
- self.__conf_sys_info_label()
- self.__conf_cap_label()
- self.__conf_user_btn()
- self.__conf_msg()
- self.__conf_rank()
- self.__conf_loading()
- self.hide_msg_rank() # 隐藏消息
- def __conf_windows(self):
- self._window.title('HGSSystem: Garbage Station')
- self._window.geometry(f'{self._win_width}x{self._win_height}')
- self._window['bg'] = conf.tk_win_bg
- self._window.resizable(False, False) # 禁止缩放
- self._window.protocol("WM_DELETE_WINDOW", lambda: self.show_exit()) # 设置标题栏[x]按钮
- self._window.overrideredirect(False) # 显示标题栏
- # 快捷键相关配置
- def lock_windows(_):
- if self._disable_all_btn:
- return
- self.__set_windows_overrideredirect(True)
- def unlock_windows(_):
- if self._disable_all_btn:
- return
- if self.is_manager():
- self.__set_windows_overrideredirect(False)
- return
- self.show_warning("解锁窗口失败", f'用户不具备解锁窗口权限'.strip())
- def full_screen_windows(_):
- if self._disable_all_btn:
- return
- if not self._full_screen or self.is_manager():
- self.__full_screen(not self._full_screen)
- return
- self.show_warning("切换全屏失败", f'用户不具备切换全屏权限'.strip())
- def easter_eggs(_):
- if self._disable_all_btn:
- return
- self.easter_eggs()
- self._window.bind("<Alt-Control-KeyPress-s>", lock_windows) # 锁定窗口
- self._window.bind("<Alt-Control-KeyPress-e>", unlock_windows) # 解锁窗口
- self._window.bind("<F11>", full_screen_windows) # 切换全屏
- self._window.bind("<F5>", easter_eggs) # 触发彩蛋
- def __full_screen(self, full: bool = True):
- """
- 切换全屏或非全屏
- 计算缩放因子(窗口变大倍数)
- 调用函数重绘窗口
- self.__conf_font_size
- self.__conf_tk
- :param full: True为切换至全屏, 否则切换至非全屏
- """
- self._window.attributes("-fullscreen", full)
- self._full_screen = full
- width = self._sys_width * (2 / 3)
- height = self._sys_height * (2 / 3)
- self._win_width = self._window.winfo_width()
- self._win_height = self._window.winfo_height()
- n = ((self._win_height / height) + (self._win_width / width)) / 2 # 平均放大倍数
- self.__conf_font_size(n)
- self.__conf_tk()
- def __set_windows_overrideredirect(self, show: bool = False):
- """
- :param show: True则显示标题栏, 否则不显示
- :return:
- """
- self._window.overrideredirect(show)
- def __conf_title_label(self):
- title_font = make_font(size=self._title_font_size, weight="bold")
- self._title_label['font'] = title_font
- self._title_label['bg'] = conf.tk_win_bg # 蜜瓜绿
- self._title_label['text'] = "HGSSystem: Garbage Station Control Center" # 使用英语标题在GUI更美观
- self._title_label['anchor'] = 'w'
- self._title_label.place(relx=0.02, rely=0.01, relwidth=0.7, relheight=0.07)
- def __conf_win_ctrl_button(self):
- title_font = make_font(size=self._win_ctrl_font_size)
- for bt in self._win_ctrl_button:
- bt: tk.Button
- bt['font'] = title_font
- bt['bg'] = conf.tk_btn_bg
- rely = 0.02
- relwidth = 0.05
- relheight = 0.05
- bt_help: tk.Button = self._win_ctrl_button[0]
- bt_help['text'] = '帮助'
- bt_help['command'] = lambda: self.show_help_info()
- bt_help.place(relx=0.81, rely=rely, relwidth=relwidth, relheight=relheight)
- bt_about: tk.Button = self._win_ctrl_button[1]
- bt_about['text'] = '关于'
- bt_about['command'] = lambda: self.show_about_info()
- bt_about.place(relx=0.87, rely=rely, relwidth=relwidth, relheight=relheight)
- bt_exit: tk.Button = self._win_ctrl_button[2]
- bt_exit['text'] = '退出'
- bt_exit['command'] = lambda: self.show_exit()
- bt_exit.place(relx=0.93, rely=rely, relwidth=relwidth, relheight=relheight)
- def __conf_user_info_label(self):
- title_font = make_font(size=self._win_info_font_size - 1, weight="bold")
- info_font = make_font(size=self._win_info_font_size + 1)
- frame_width = self._win_width * 0.4 # frame宽度 (像素)
- frame_height = self._win_height * 0.4 # frame高度 (像素)
- bg_color = "#FA8072" # 背景颜色
- self._user_frame['bg'] = bg_color
- self._user_frame['bd'] = 5
- self._user_frame['relief'] = "ridge"
- self._user_frame.place(relx=0.02, rely=0.1, relwidth=0.4, relheight=0.40)
- h_label = 5
- h_label_s = 1
- h_top = 2
- height_count = h_label * 5 + h_label_s * 4 + h_top * 2
- height_label = h_label / height_count
- height = h_top / height_count
- for lb_list in [self._user_score, self._user_rubbish, self._user_eval, self._user_name, self._user_uid]:
- lb_list[0]['font'] = title_font
- lb_list[0]['bg'] = bg_color
- lb_list[0]['fg'] = "#fffbf0" # 字体颜色使用象牙白
- lb_list[0]['text'] = lb_list[3] + ":"
- lb_list[0]['anchor'] = 'e'
- lb_list[0].place(relx=0.0, rely=height, relwidth=0.35, relheight=height_label)
- height += height_label + h_label_s / height_count
- for lb_list in [self._user_score, self._user_rubbish, self._user_eval, self._user_name, self._user_uid]:
- lb_list[1]['font'] = info_font
- lb_list[1]['bg'] = bg_color
- lb_list[1]['fg'] = "#000000" # 字体颜色使用纯黑
- lb_list[1]['textvariable'] = lb_list[2]
- lb_list[1]['anchor'] = 'w'
- lb_list[2].set('test')
- height = h_top / height_count
- for lb_list in [self._user_score, self._user_rubbish, self._user_eval]:
- lb_list[1].place(relx=0.36, rely=height, relwidth=0.19, relheight=height_label)
- height += height_label + h_label_s / height_count
- for lb_list in [self._user_name, self._user_uid]:
- lb_list[1].place(relx=0.36, rely=height, relwidth=0.63, relheight=height_label)
- height += height_label + h_label_s / height_count
- # 显示一张图片 (GUI更美观)
- img_relwidth = 0.30
- img_relheight = height_label * 3 + (h_label_s / height_count) * 2
- img = (Image.open(conf.pic_d['head']).
- resize((int(img_relwidth * frame_width), int(img_relheight * frame_height))))
- self._user_im = ImageTk.PhotoImage(image=img)
- self._user_img['image'] = self._user_im
- self._user_img.place(relx=1 - img_relwidth - 0.06, rely=0.09,
- relwidth=img_relwidth, relheight=img_relheight)
- self._user_img['bd'] = 5
- self._user_img['relief'] = "ridge"
- def __conf_throw_btn(self):
- btn_font = make_font(size=self._throw_ctrl_btn_font_size, weight="bold")
- btn_info: List[Tuple[str, str]] = [("可回收垃圾", "#00BFFF"), # 按钮文字及其颜色
- ("其他垃圾", "#A9A9A9"),
- ("有害垃圾", "#DC143C"),
- ("厨余垃圾", "#32CD32")]
- self.__show_throw_frame()
- for btn, info in zip(self._throw_ctrl_btn, btn_info):
- btn['font'] = btn_font
- btn['bg'] = info[1]
- btn['text'] = info[0]
- self._throw_ctrl_btn[0]['command'] = lambda: self.throw_garbage(GarbageType.recyclable)
- self._throw_ctrl_btn[1]['command'] = lambda: self.throw_garbage(GarbageType.other)
- self._throw_ctrl_btn[2]['command'] = lambda: self.throw_garbage(GarbageType.hazardous)
- self._throw_ctrl_btn[3]['command'] = lambda: self.throw_garbage(GarbageType.kitchen)
- self._throw_ctrl_btn[0].place(relx=0.000, rely=0.000, relwidth=0.495, relheight=0.495)
- self._throw_ctrl_btn[1].place(relx=0.505, rely=0.000, relwidth=0.495, relheight=0.495)
- self._throw_ctrl_btn[2].place(relx=0.000, rely=0.505, relwidth=0.495, relheight=0.495)
- self._throw_ctrl_btn[3].place(relx=0.505, rely=0.505, relwidth=0.495, relheight=0.495)
- def __conf_check_btn(self):
- btn_font = make_font(size=self._check_ctrl_btn_font_size, weight="bold")
- btn_info: List[Tuple[str, str]] = [("投放错误", "#ef7a82"), # 按钮文字及其颜色
- ("投放正确", "#70f3ff")]
- self.__show_check_frame()
- for btn, info in zip(self._check_ctrl_btn, btn_info):
- btn['font'] = btn_font
- btn['text'] = info[0]
- btn['bg'] = info[1]
- self._check_ctrl_btn[0]['command'] = lambda: self.check_garbage(False)
- self._check_ctrl_btn[1]['command'] = lambda: self.check_garbage(True)
- self._check_ctrl_btn[0].place(relx=0.000, rely=0.000, relwidth=0.495, relheight=1)
- self._check_ctrl_btn[1].place(relx=0.505, rely=0.000, relwidth=0.495, relheight=1)
- def __conf_sys_info_label(self):
- title_font = make_font(size=self._sys_info_font_size - 1, weight="bold")
- info_font = make_font(size=self._sys_info_font_size + 1)
- bg_color = "#F0F8FF"
- self._sys_info_frame['bg'] = bg_color
- self._sys_info_frame['bd'] = 5
- self._sys_info_frame['relief'] = "ridge"
- self._sys_info_frame.place(relx=0.02, rely=0.51, relwidth=0.4, relheight=0.14)
- h_label = 5
- h_label_s = 1
- h_top = 2
- height_count = h_label * 2 + h_label_s * 1 + h_top * 2
- height_label = h_label / height_count
- height = h_top / height_count
- for info_list in [self._garbage_id, self._sys_date]:
- info_list[0]['font'] = title_font
- info_list[0]['bg'] = bg_color
- info_list[0]['anchor'] = 'e'
- info_list[0]['text'] = info_list[3] + ":"
- info_list[0].place(relx=0.0, rely=height, relwidth=0.35, relheight=height_label)
- height += height_label + h_label_s / height_count
- height = h_top / height_count
- for info_list in [self._garbage_id, self._sys_date]:
- info_list[1]['font'] = info_font
- info_list[1]['bg'] = bg_color
- info_list[1]['textvariable'] = info_list[2]
- info_list[1]['anchor'] = 'w'
- info_list[2].set('test')
- info_list[1].place(relx=0.36, rely=height, relwidth=0.63, relheight=height_label)
- height += height_label + h_label_s / height_count
- def __conf_user_btn(self):
- btn_font = make_font(size=self._user_btn_font_size, weight="bold")
- btn_info: List[Tuple[str, str]] = [("详细信息", "#DDA0DD"),
- ("排行榜", "#B0C4DE"),
- ("搜索", "#F4A460")]
- self._user_btn_frame.place(relx=0.02, rely=0.66, relwidth=0.19, relheight=0.32)
- self._user_btn_frame['bg'] = conf.tk_win_bg
- """
- 计算标签和间隔的大小比例(相对于Frame)
- 标签和间隔的比例为5:1
- 3个标签和2个间隔
- (h_label * 3 + h_label_s * 2) 表示 Frame 总大小
- height_label 标签相对于 Frame 的大小
- height_sep 间隔相对于 Frame 的大小
- """
- h_label = 5
- h_label_s = 1
- height_label = h_label / (h_label * 3 + h_label_s * 2)
- height_sep = h_label_s / (h_label * 3 + h_label_s * 2)
- height = 0
- for btn, info in zip(self._user_btn, btn_info):
- btn['font'] = btn_font
- btn['text'] = info[0]
- btn['bg'] = info[1]
- btn.place(relx=0.0, rely=height, relwidth=1.00, relheight=height_label)
- height += height_label + height_sep
- self._user_btn[0]['state'] = 'disable' # 第一个按键默认为disable且点击无效果
- self._user_btn[1]['command'] = lambda: self.get_show_rank()
- self._user_btn[2]['command'] = lambda: self.show_search_info()
- def __conf_cap_label(self):
- self._cap_label['bg'] = "#000000"
- self._cap_label['bd'] = 5
- self._cap_label['relief'] = "ridge"
- self._cap_label.place(relx=0.22, rely=0.66, relwidth=0.2, relheight=0.32)
- def __conf_msg(self):
- title_font = make_font(size=self._msg_font_size + 1, weight="bold")
- info_font = make_font(size=self._msg_font_size - 1)
- bg_color = "#F5FFFA"
- self._msg_frame['bg'] = bg_color
- self._msg_frame['bd'] = 5
- self._msg_frame['relief'] = "ridge"
- # frame 不会立即显示
- self._msg_label[0]['font'] = title_font
- self._msg_label[0]['bg'] = bg_color
- self._msg_label[0]['anchor'] = 'w'
- self._msg_label[0]['textvariable'] = self._msg_label[2]
- self._msg_line['bg'] = '#000000' # 分割线
- self._msg_label[1]['font'] = info_font
- self._msg_label[1]['bg'] = bg_color
- self._msg_label[1]['fg'] = '#000000'
- self._msg_label[1]['state'] = 'disable'
- self._msg_label[1]['bd'] = 0
- self._msg_label[1]['exportselection'] = False
- self._msg_label[1]['selectbackground'] = bg_color # 被选中背景颜色和未选中颜色相同, 不启用选中
- self._msg_label[1]['selectforeground'] = '#000000'
- self._msg_label[1]['wrap'] = 'none'
- self._msg_y_scroll['orient'] = 'vertical'
- self._msg_y_scroll['command'] = lambda *args: (self.set_msg_time_now(), self._msg_label[1].yview(*args))
- self._msg_label[1]['yscrollcommand'] = lambda *args: (self.set_msg_time_now(), self._msg_y_scroll.set(*args))
- self._msg_x_scroll['orient'] = 'horizontal'
- self._msg_x_scroll['command'] = lambda *args: (self.set_msg_time_now(), self._msg_label[1].xview(*args))
- self._msg_label[1]['xscrollcommand'] = lambda *args: (self.set_msg_time_now(), self._msg_x_scroll.set(*args))
- self._msg_label[0].place(relx=0.05, rely=0.05, relwidth=0.9, relheight=0.1)
- self._msg_line.place(relx=0.05, rely=0.15, relwidth=0.9, height=1) # 一个像素的高度即可
- x_scroll = 0.03
- y_scroll = 0.02
- self._msg_label[1].place(relx=0.05, rely=0.20, relwidth=0.90 - y_scroll, relheight=0.64 - x_scroll)
- self._msg_x_scroll.place(relx=0.05, rely=0.84 - x_scroll, relwidth=0.90 - y_scroll, relheight=x_scroll)
- self._msg_y_scroll.place(relx=0.95 - y_scroll, rely=0.20, relwidth=y_scroll, relheight=0.64)
- self._msg_hide['font'] = info_font
- self._msg_hide['bg'] = conf.tk_btn_bg
- self._msg_hide['text'] = '关闭'
- self._msg_hide['command'] = lambda: self.hide_msg_rank(True)
- self._msg_hide.place(relx=0.42, rely=0.85, relwidth=0.16, relheight=0.09)
- def set_msg_time_now(self, show_time: float = 10.0):
- self._msg_time = time.time()
- self._msg_show_time = show_time
- def set_msg_time_none(self):
- self._msg_time = None
- def show_msg(self, title, info: str, msg_type='提示', big: bool = True, show_time: float = 10.0):
- if self._disable_all_btn:
- return
- self._msg_label[2].set(f'{msg_type}: {title}')
- self._msg_label[1]['state'] = 'normal'
- self._msg_label[1].delete(1.0, 'end') # 删除所有元素
- for i in info.split('\n'):
- self._msg_label[1].insert('end', i + '\n')
- self._msg_label[1]['state'] = 'disable'
- if big:
- self._msg_frame.place(relx=0.45, rely=0.15, relwidth=0.53, relheight=0.70)
- self._check_ctrl_frame.place_forget()
- self._throw_ctrl_frame.place_forget()
- self._rank_frame.place_forget()
- else:
- self._msg_frame.place(relx=0.45, rely=0.20, relwidth=0.53, relheight=0.50)
- self.__show_check_frame()
- self._throw_ctrl_frame.place_forget()
- self._rank_frame.place_forget()
- self.set_msg_time_now(show_time)
- def show_warning(self, title, info, show_time: float = 15.0):
- self.show_msg(title, info, msg_type='警告', show_time=show_time)
- def __conf_rank(self):
- title_font = make_font(size=self._rank_font_title_size, weight="bold")
- info_font = make_font(size=self._rank_font_size)
- btn_font = make_font(size=self._msg_font_size - 1)
- bg_color = "#F5F5DC"
- self._rank_frame['bg'] = bg_color
- self._rank_frame['relief'] = "ridge"
- self._rank_frame['bd'] = 5
- # frame 不会立即显示
- self._rank_label[0]['font'] = title_font
- self._rank_label[0]['bg'] = bg_color
- self._rank_label[0]['textvariable'] = self._rank_var[0]
- self._rank_label[0].place(relx=0.02, rely=0.00, relwidth=0.96, relheight=0.1)
- for lb, v in zip(self._rank_label[1:], self._rank_var[1:]):
- lb['font'] = info_font
- lb['bg'] = "#F5FFFA"
- lb['textvariable'] = v
- lb['relief'] = "ridge"
- lb['bd'] = 2
- # 标签结束的高度为 0.12 + 0.15 * 5 = 0.87
- for btn, text in zip(self._rank_btn, ("上一页", "关闭", "下一页")):
- btn['font'] = btn_font
- btn['bg'] = conf.tk_btn_bg
- btn['text'] = text
- self._rank_btn[0].place(relx=0.050, rely=0.88, relwidth=0.25, relheight=0.08)
- self._rank_btn[0]['command'] = lambda: self.get_rank(-1)
- self._rank_btn[1].place(relx=0.375, rely=0.88, relwidth=0.25, relheight=0.08)
- self._rank_btn[1]['command'] = lambda: self.hide_msg_rank(True)
- self._rank_btn[2].place(relx=0.700, rely=0.88, relwidth=0.25, relheight=0.08)
- self._rank_btn[2]['command'] = lambda: self.get_rank(+1)
- def __set_rank_info(self, rank_info: List[Tuple[int, uname_t, uid_t, score_t, score_t, Optional[str]]]):
- """
- 显示排行榜信息
- :param rank_info: 排行榜信息, 共计五个元组, 元组包含: 排名, uid, name, 分数, 评分
- :return:
- """
- if len(rank_info) > 5:
- rank_info = rank_info[:5]
- for lb in self._rank_label[1:]: # 隐藏全部标签
- lb.place_forget()
- height = 0.12
- for i, info in enumerate(rank_info):
- no, name, uid, score, eval_, color = info
- self._rank_var[i + 1].set(f"NO.{no} {name}\n\n" # 中间空一行 否则中文字体显得很窄
- f"ID: {uid[0:conf.ranking_tk_show_uid_len]} "
- f"信用: {eval_} 积分: {score}")
- if color is None:
- self._rank_label[i + 1]['bg'] = "#F5FFFA"
- else:
- self._rank_label[i + 1]['bg'] = color
- self._rank_label[i + 1].place(relx=0.04, rely=height, relwidth=0.92, relheight=0.13)
- height += 0.15
- def show_rank(self, page: int, page_c: int,
- rank_info: List[Tuple[int, uname_t, uid_t, score_t, score_t, Optional[str]]],
- title: str = '排行榜'):
- if self._disable_all_btn:
- return
- self._rank_var[0].set(f'{title} ({page}/{page_c})')
- self._rank_frame.place(relx=0.47, rely=0.15, relwidth=0.47, relheight=0.80)
- frame_width = self._win_width * 0.53
- for lb in self._rank_label[1:]:
- lb['wraplength'] = frame_width * 0.85 - 5 # 设定自动换行的像素
- if page == 1:
- self._rank_btn[0]['state'] = 'disable'
- else:
- self._rank_btn[0]['state'] = 'normal'
- if page == page_c:
- self._rank_btn[2]['state'] = 'disable'
- else:
- self._rank_btn[2]['state'] = 'normal'
- self.__set_rank_info(rank_info)
- self._throw_ctrl_frame.place_forget()
- self._check_ctrl_frame.place_forget()
- self._msg_frame.place_forget()
- self.set_msg_time_none()
- def hide_msg_rank(self, update: bool = False):
- self.__show_check_frame() # rank会令此消失
- self.__show_throw_frame() # rank和msg令此消失
- self._msg_frame.place_forget()
- self._rank_frame.place_forget()
- self.set_msg_time_none()
- if update:
- self.update_user_time()
- def __conf_loading(self):
- title_font = make_font(size=self._loading_tile_font, weight="bold")
- self._loading_frame['bg'] = conf.tk_win_bg
- self._loading_frame['bd'] = 5
- self._loading_frame['relief'] = "ridge"
- # frame 不会立即显示
- self._loading_title[0]['font'] = title_font
- self._loading_title[0]['bg'] = conf.tk_win_bg
- self._loading_title[0]['anchor'] = 'w'
- self._loading_title[0]['textvariable'] = self._loading_title[1]
- self._loading_title[0].place(relx=0.02, rely=0.00, relwidth=0.96, relheight=0.6)
- self._loading_line['bg'] = '#000000'
- self._loading_line.place(relx=0.02, rely=0.6, relwidth=0.96, height=1) # 一个像素的高度即可
- self._loading_pro['mode'] = 'indeterminate' # 来回显示
- self._loading_pro['orient'] = 'horizontal' # 横向进度条
- self._loading_pro['maximum'] = 100
- self._loading_pro.place(relx=0.02, rely=0.73, relwidth=0.96, relheight=0.22)
- def show_loading(self, title: str):
- self.set_all_btn_disable()
- self._loading_title[1].set(f"加载: {title}")
- self._loading_pro['value'] = 0
- self._loading_frame.place(relx=0.30, rely=0.40, relwidth=0.40, relheight=0.15)
- self._loading_pro.start(50)
- def stop_loading(self):
- self._loading_frame.place_forget()
- self._loading_pro.stop()
- self.set_reset_all_btn()
- def __show_check_frame(self):
- self._check_ctrl_frame.place(relx=0.45, rely=0.82, relwidth=0.53, relheight=0.16)
- def __show_throw_frame(self):
- self._throw_ctrl_frame.place(relx=0.45, rely=0.1, relwidth=0.53, relheight=0.70)
- def __define_after(self, ms, func, *args):
- self._window.after(ms, self.__after_func_maker(func), *args)
- def __conf_after(self):
- self.__define_after(self.refresh_delay, self.update_time)
- self.__define_after(self.refresh_delay, self.update_control)
- self.__define_after(self.refresh_delay, self.update_scan)
- self.__define_after(self.refresh_delay, self.update_msg)
- def __after_func_maker(self, func):
- def new_func(*args, **kwargs):
- try:
- func(*args, **kwargs)
- except: # 捕获未考虑的错误
- self.show_msg("系统错误", "运行时产生了错误...", "错误", show_time=3.0)
- traceback.print_exc()
- finally:
- self._window.after(self.refresh_delay, new_func)
- return new_func
- def update_time(self):
- var: tk.Variable = self._sys_date[2]
- t = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- var.set(f"{t}")
- def update_control(self):
- name: tk.Variable = self._user_name[2]
- uid: tk.Variable = self._user_uid[2]
- score: tk.Variable = self._user_score[2]
- rubbish: tk.Variable = self._user_rubbish[2]
- eval_: tk.Variable = self._user_eval[2]
- user_info: Dict[str, str] = self.get_user_info_no_update()
- if user_info.get('uid') is None:
- name.set('未登录')
- uid.set('未登录')
- eval_.set('---')
- rubbish.set('---')
- score.set('---')
- self.__switch_to_no_user()
- elif user_info.get('manager', '0') == '1':
- name.set(user_info.get('name'))
- uid_get = user_info.get('uid', None)
- if uid_get is None or len(uid_get) < 32:
- uid.set('error')
- else:
- uid.set(uid_get[0:21])
- eval_.set('无(管理员)')
- rubbish.set('无(管理员)')
- score.set('无(管理员)')
- self.__switch_to_manager_user()
- else:
- name.set(user_info.get('name'))
- uid_get = user_info.get('uid', None)
- if uid_get is None or len(uid_get) < 32:
- uid.set('error')
- else:
- uid.set(uid_get[0:conf.tk_show_uid_len])
- eval_.set(user_info.get('reputation'))
- rubbish.set(user_info.get('rubbish'))
- score.set(user_info.get('score'))
- self.__switch_to_normal_user()
- garbage = self.get_garbage()
- if garbage is None:
- self._garbage_id[2].set('---')
- else:
- gid = garbage.get_gid()
- if len(gid) > 20:
- gid = gid[-20:]
- self._garbage_id[2].set(gid)
- def update_scan(self):
- self.scan()
- # 需要存储一些数据 谨防被gc释放
- _cap_img_info = (Image.fromarray(cv2.cvtColor(self.get_cap_img(), cv2.COLOR_BGR2RGB)).
- transpose(Image.FLIP_LEFT_RIGHT))
- self._cap_img = ImageTk.PhotoImage(image=_cap_img_info)
- self._cap_label['image'] = self._cap_img
- def update_msg(self):
- if self._msg_time is None:
- return
- if time.time() - self._msg_time > self._msg_show_time: # 自动关闭消息
- self.hide_msg_rank()
- def __switch_to_normal_user(self):
- if self._disable_all_btn:
- return
- self.normal_user_disable()
- self.normal_user_able()
- def __switch_to_manager_user(self):
- if self._disable_all_btn:
- return
- self.manager_user_disable()
- self.manager_user_able()
- def __switch_to_no_user(self):
- self.manager_user_disable()
- self.normal_user_disable()
- self._user_btn[0]['state'] = 'disable'
- def normal_user_disable(self):
- set_tk_disable_from_list(self._check_ctrl_btn, flat='disable')
- self._user_btn[0]['state'] = 'normal'
- self._user_btn[0]['command'] = lambda: self.show_user_info()
- def manager_user_disable(self):
- set_tk_disable_from_list(self._throw_ctrl_btn, flat='disable')
- self._user_btn[0]['state'] = 'normal'
- self._user_btn[0]['command'] = lambda: self.show_garbage_info()
- def normal_user_able(self):
- set_tk_disable_from_list(self._throw_ctrl_btn, flat='normal')
- def manager_user_able(self):
- set_tk_disable_from_list(self._check_ctrl_btn, flat='normal')
- def set_all_btn_disable(self):
- self.__switch_to_no_user() # 禁用所有操作性按钮
- self.hide_msg_rank()
- set_tk_disable_from_list(self._user_btn, flat='disable')
- set_tk_disable_from_list(self._win_ctrl_button, flat='disable')
- self._disable_all_btn = True
- def set_reset_all_btn(self):
- set_tk_disable_from_list(self._user_btn, flat='normal')
- set_tk_disable_from_list(self._win_ctrl_button, flat='normal')
- self.update_control() # 位于_user_btn之后, 会自动设定detail按钮
- self._disable_all_btn = False
- def mainloop(self):
- self._window.mainloop()
- def exit_win(self):
- self._window.destroy()
- if __name__ == '__main__':
- mysql_db = DB()
- capture = HGSCapture()
- qr_capture = HGSQRCoder(capture)
- station_ = GarbageStation(mysql_db, capture, qr_capture)
- station_.mainloop()
|