优化submenu(10000数据量不卡)

This commit is contained in:
cxykevin 2024-04-14 14:46:09 +08:00
parent db3f0b2445
commit ad0dbc33a7
1 changed files with 57 additions and 42 deletions

View File

@ -2,35 +2,15 @@ import json
import tkinter import tkinter
import sys import sys
from tkinter import ttk from tkinter import ttk
from tkinter import font as tkfont
try: from magictk import color_tmpl
import color_tmpl from magictk import photoload
except ImportError: from magictk import fontconfig
from magictk import color_tmpl
try:
import photoload
except ImportError:
from magictk import photoload
transcolor = "#41342F" transcolor = "#41342F"
usetrans = sys.platform.startswith('win') usetrans = sys.platform.startswith('win')
def set_font():
global use_font
font_family = ["Helvetica Neue", "Helvetica", "PingFang SC", "Hiragino Sans GB",
"Microsoft YaHei",
"微软雅黑",
"Arial", "sans-serif"]
t_family = tkfont.families(root=None, displayof=None)
for i in font_family:
if i in t_family:
use_font = i
break
else:
print("Unknown font")
class MenuObjs: class MenuObjs:
def __init__(self): def __init__(self):
self.menu_lst = [] self.menu_lst = []
@ -60,6 +40,7 @@ class Menu:
__y_move = 0 __y_move = 0
___last_move = 1 ___last_move = 1
___last_highlight = 0 ___last_highlight = 0
__load_y_size = 10
ht = 12 ht = 12
lt = 22 lt = 22
ft = 34 ft = 34
@ -102,7 +83,8 @@ class Menu:
n += 1 n += 1
self.___last_move = self.__y_move self.___last_move = self.__y_move
n = 0 n = 0
for i in self.menuobj.menu_effect: for i_tmp in range((-self.__real_y_move+self.__y_move)//self.ft, min((-self.__real_y_move+self.__y_move)//self.ft+len(self.__items), len(self.menuobj.menu_effect))):
i = self.menuobj.menu_effect[i_tmp]
if (len(i) != 0): if (len(i) != 0):
self.canvas.itemconfigure( self.canvas.itemconfigure(
self.__itemsf[n], justify=tkinter.LEFT, **i) self.__itemsf[n], justify=tkinter.LEFT, **i)
@ -119,29 +101,35 @@ class Menu:
y = event.y y = event.y
self.__last_highlight = max( self.__last_highlight = max(
-1, min(len(self.__items), int((y-self.ht-self.__y_move)//self.ft))) -1, min(len(self.__items), int((y-self.ht-self.__y_move)//self.ft)))
if (self.__last_highlight == -1 or self.__last_highlight >= len(self.__items)): for i in self.__items:
if (self.___last_highlight != -2):
self.canvas.itemconfig(
self.__items[self.___last_highlight], fill=self.color["background"])
self.___last_highlight = -2
elif (self.___last_highlight != self.__last_highlight):
self.canvas.itemconfig( self.canvas.itemconfig(
self.__items[self.__last_highlight], fill=self.color["placeholder_light"]) i, fill=self.color["background"])
self.canvas.itemconfig( self.canvas.itemconfig(
self.__items[self.___last_highlight], fill=self.color["background"]) self.__items[self.__last_highlight], fill=self.color["placeholder_light"])
self.___last_highlight = self.__last_highlight
def close(self, *args): def close(self, *args):
self.__close_mode = 1 self.__close_mode = 1
if sys.platform.startswith('win'):
self.toplevel.unbind_all("<MouseWheel>")
elif sys.platform.startswith('darwin'):
self.toplevel.unbind_all("<MouseWheel>")
else:
self.toplevel.unbind_all(
"<Button-4>")
self.toplevel.unbind_all(
"<Button-5>")
if (self.__closecallback is not None): if (self.__closecallback is not None):
self.__closecallback(self) self.__closecallback(self)
def __init__(self, root, menuobj: MenuObjs, w=200, h=300, x=100, y=300, color_list: None | dict = None, closeonleave=True, fontsize=10, closecallback=None): def __init__(self, root, menuobj: MenuObjs, w=200, h=300, x=100, y=300, color_list: None | dict = None, closeonleave=True, fontsize=10, closecallback=None):
set_font() global use_font
use_font = fontconfig.getfont()
self.__closecallback = closecallback self.__closecallback = closecallback
self.font = (use_font, fontsize) self.font = (use_font, fontsize)
self.__items = [] self.__items = []
self.__itemsf = [] self.__itemsf = []
self.__itemsid = []
self.__real_y_move = 0
self.menuobj = menuobj self.menuobj = menuobj
self.w = w self.w = w
self.h = h self.h = h
@ -177,11 +165,13 @@ class Menu:
def __draw_menu(self): def __draw_menu(self):
n = 0 n = 0
for i in self.menuobj.menu_lst: for i_tmp in range(0, min(self.__load_y_size, len(self.menuobj.menu_lst))):
i = self.menuobj.menu_lst[i_tmp]
self.__items.append(self.canvas.create_rectangle( self.__items.append(self.canvas.create_rectangle(
2, n*self.ft+self.ht, self.w, (n+1)*self.ft+self.ht, fill=self.color["background"], width=0)) 2, n*self.ft+self.ht, self.w, (n+1)*self.ft+self.ht, fill=self.color["background"], width=0))
self.__itemsf.append(self.canvas.create_text( self.__itemsf.append(self.canvas.create_text(
10, n*self.ft+self.ht, text=i, font=self.font, justify=tkinter.LEFT, fill=self.color["regular_text"])) 10, n*self.ft+self.ht, text=i, font=self.font, justify=tkinter.LEFT, fill=self.color["regular_text"]))
self.__itemsid.append(n)
n += 1 n += 1
def __draw_corner(self, r_x, r_y, x, y, **kwargs): def __draw_corner(self, r_x, r_y, x, y, **kwargs):
@ -234,6 +224,8 @@ class Menu:
def __bind_scroll(self): def __bind_scroll(self):
def scrollwheel(event: tkinter.Event, setdelta=None): def scrollwheel(event: tkinter.Event, setdelta=None):
if (len(self.menuobj.menu_lst) <= 8):
return
if (setdelta is None): if (setdelta is None):
delta = event.delta delta = event.delta
else: else:
@ -241,10 +233,33 @@ class Menu:
if sys.platform.startswith('win'): if sys.platform.startswith('win'):
delta //= 120 delta //= 120
if delta > 0: if delta > 0:
self.__y_move = min(0, self.__y_move+delta) if (self.__real_y_move != 0):
self.__y_move += delta
self.__real_y_move = min(0, self.__real_y_move+delta)
else: else:
self.__y_move = max( if (self.__real_y_move != -(len(self.menuobj.menu_lst)*self.ft-self.h+8)):
-max(0, len(self.__items)*self.ft+self.ht-self.h), self.__y_move+delta) self.__y_move += delta
self.__real_y_move = max(self.__real_y_move+delta,
-(len(self.menuobj.menu_lst)*self.ft-self.h+8))
if (self.__y_move > 0):
self.__y_move -= self.ft
self.__items.insert(0, self.__items.pop())
self.__itemsf.insert(0, self.__itemsf.pop())
self.__itemsid.insert(0, self.__itemsid.pop()-10)
self.__mouse_move(event)
if (self.__itemsid[0] >= 0):
self.canvas.itemconfigure(
self.__itemsf[0], text=self.menuobj.menu_lst[self.__itemsid[0]])
elif (self.__y_move < -self.ft+1):
self.__y_move += self.ft
self.__items.append(self.__items.pop(0))
self.__itemsf.append(self.__itemsf.pop(0))
self.__itemsid.append(self.__itemsid.pop(0)+10)
self.__mouse_move(event)
if (self.__itemsid[-1] < len(self.menuobj.menu_lst)):
self.canvas.itemconfigure(
self.__itemsf[-1], text=self.menuobj.menu_lst[self.__itemsid[-1]])
if sys.platform.startswith('win'): if sys.platform.startswith('win'):
self.toplevel.bind_all("<MouseWheel>", scrollwheel) self.toplevel.bind_all("<MouseWheel>", scrollwheel)
@ -258,8 +273,8 @@ class Menu:
def __click(self, event): def __click(self, event):
click_item = max( click_item = max(
-1, min(len(self.__items), int((event.y-self.ht-self.__y_move)//self.ft))) -1, min(len(self.menuobj.menu_func), int((event.y-self.ht-self.__real_y_move)//self.ft)))
if (click_item == -1 or self.__last_highlight >= len(self.__items)): if (click_item == -1 or self.__last_highlight >= len(self.menuobj.menu_func)):
return return
self.close() self.close()
self.menuobj.menu_func[click_item](self, click_item) self.menuobj.menu_func[click_item](self, click_item)