Tkinter文本小部件:多行闪烁插入框选择



我为tk.Text创建了一个框选择功能。小部件获得font高度并从中调制.xbm图像。.xbm通过image_create被用作伪插入符号,用于所有选定的行,除了真正插入符号所在的行。

如何使伪插入符号映像实例与真插入符号同步闪烁?

我可以往哪个方向去得到这些结果?

我的解决方案是明显地去掉真正的插入符号,在每一行上画一个伪插入符号,然后调用一个函数,该函数不断地将"开"伪插入符号与"关"伪插入符号交换。下面是一些相关的代码片段。注意:我实际上有3个伪插入符号,因为我想让真正的活动行上的插入符号颜色更深一些。

#FAUX-CARET
#concoct, load, assign, and delete xbm for faux-caret
def __loadcarets(self) -> None:
#store insert on/off times for faux-caret `.after` calls
self.__instime = (self['insertofftime'], self['insertontime'])

fh = self.__fh    #font height from 'linespace'

#make a temp xbm file
with tempfile.NamedTemporaryFile(mode='w+b', suffix='.xbm', delete=False) as f:
#create prettyprint xbm data
xbmdata = ',nt'.join(','.join('0xFF' for _ in range(min(8, fh-(8*i)))) for i in range(math.ceil(fh/8)))
#write xbm
f.write((f"#define image_width {INSWIDTH}n#define image_height {fh}n"
"static unsigned char image_bits[] = {nt"
f'{xbmdata}}};').encode())

#load xbm files for faux-caret ~ they have to be in this order 
#I gave this a placeholder name because you should never have to access this directly
#__fauxcaret does everything          
self.__  = (tk.BitmapImage(file=f.name, foreground='#999999'),                   #shadow caret 
tk.BitmapImage(file=f.name, foreground=self['background']),          #off caret
tk.BitmapImage(file=f.name, foreground=self['insertbackground']))    #main caret  

#delete file
os.unlink(f.name)

#faux-caret create or config
def __fauxcaret(self, index:str, on:bool=True, main:bool=False, cfg:bool=False) -> None:
(self.image_create, self.image_configure)[cfg](index, image=self.__[(main<<on)|(on^1)])

#blink the faux-caret(s)
def __blink(self, on:bool=True):
#nothing to do
if not self.__boxselect: return

#so we only do this once per first blink
if not self.__blinksrt:
#sort image indexes
self.__blinksrt = sorted((self.index(n) for n in self.image_names()), key=float)

if idx:=self.__blinksrt:
#flip `on`
on = not on
#consider direction in forward perspective
fw = not self.__lbounds.rv
#reconfigure all carets
for i in idx: self.__fauxcaret(i, on=on, cfg=True)
#reconfigure "active line" caret, if off it will assign off again
self.__fauxcaret(idx[-fw], on=on, main=True, cfg=True)
#schedule next call
self.__blinkid = self.after(self.__instime[on], self.__blink, on)
return

raise ValueError('__blink: Nothing to sort!')

#reset blink
def __blinkreset(self) -> None:
#cancel after
self.after_cancel(self.__blinkid)
#reset blinksort
self.__blinksrt  = None

最新更新