tkinter即时渲染文本框

引言

像CSDN的Markdown编辑器一样,tkinter同样可以实现边编写边进行渲染。但由于调用tcl的效率问题,我们还需要考虑取舍。

这篇文章主要是思路。

选择渲染文本(引擎)

tkinter公开的纯拓展只有能够显示HTML3的tkhtmlview,功能还是比较简陋的。为了提高丰富性,我决定使用自己写的Tin标记语言。

Tin标记语言的介绍在我的专栏 Tin标记语言 中。

那么既然选择这个编辑语言,就要有相应的渲染文本框。当然,我已经编译了 TinEngine.pyd 可供快速调用,在 Tin知识库 中有下载、依赖、内部环境和使用的介绍(预览和接口中)。TinEngine是专门解析并渲染Tin标记语言的文本框,完全依靠tkinter自身实现。

基础效果如下:
在这里插入图片描述

取舍

排除标签

因为 Tin 在被解析后有一定的交互能力,所以在Tin标记语言中,有一些标签会影响渲染。那么当遇到这类标签时,就跳过不解析。

当然,TinEngine 没有提供这个功能,这需要在即时编辑器的代码中进行处理。

比如:

if obj[0] in ['<-pass->','</-pass>','<key>','<-askyesno->','</-askyesno>','<jit>','<stop>','<webopen>']:#跳过影响解析时间的标签
    if obj[0]=='<webopen>':
        units.append('<main>暂不显示网址打开请求;center;white-grey')
elif obj[0]=='<img>':
    units.append('<main>图片暂不显示;center;white-grey')
elif obj[0]=='<html>':
    html=1
    units.append('<main>暂不显示HTML文本;center;white-grey')
else:
    units.append(i.replace('<pass>','<main>').replace('<askyesno>','<main>'))

选择渲染范围

这也是一个无奈的选择,浏览器由编译类语言编写,即时渲染速度快。但Python本身就是解释类语言,而且还要调用tcl显示窗口,所以不得不限定渲染范围。

我选择的是光标上下30行的范围进行渲染。

具体如下:

insert=int(str(Text.index('insert')).split('.')[0])
#为了加快解析效率,值获取鼠标上下各30行内容解析
lines=len(Text.get(1.0,'end').split('\n'))
if insert<=30:
    startline='1.0'
else:
    startline=str(insert-30)+'.0'
if lines-insert<=30:
    endline='end'
else:
    endline=str(insert+30)+'.0'
words=Text.get(startline,endline)

是否不变

如果接收到鼠标或键盘事件时,需要判断是否与之前的内容一样,如果一样,就不渲染了。这个很简单,下面直接给出完整代码。

完整代码

#  -*- coding: utf-8 -*-
# 仅作为Tin的一个小工具,因为效率和速度影响,不会运用到实际中

import sys
import tkinter as tk
from tkinter import scrolledtext
import tkinter.ttk as ttk
import re
import PIL#need
import requests#need
import win32gui#need
from TinEngine import TinText,set_name,set_file

old=''
html=0#不显示HTML
def call_back(event):
    global old,html
    insert=int(str(Text.index('insert')).split('.')[0])
    #为了加快解析效率,值获取鼠标上下各30行内容解析
    lines=len(Text.get(1.0,'end').split('\n'))
    if insert<=30:
        startline='1.0'
    else:
        startline=str(insert-30)+'.0'
    if lines-insert<=30:
        endline='end'
    else:
        endline=str(insert+30)+'.0'
    words=Text.get(startline,endline)
    if words!=old:
        old=words
        words=words.split('\n')
        units=['']
        for i in words:
            obj=re.findall('^(<.*?>).*$',i)
            if len(obj)==0:
                if html!=1:
                    units.append(i)
                continue
            if obj[0]=='</html>':
                html=0
            if html==1:
                continue
            if obj[0] in ['<-pass->','</-pass>','<key>','<-askyesno->','</-askyesno>','<jit>','<stop>','<webopen>']:#跳过影响解析时间的标签
                if obj[0]=='<webopen>':
                    units.append('<main>暂不显示网址打开请求;center;white-grey')
            elif obj[0]=='<img>':
                units.append('<main>图片暂不显示;center;white-grey')
            elif obj[0]=='<html>':
                html=1
                units.append('<main>暂不显示HTML文本;center;white-grey')
            else:
                units.append(i.replace('<pass>','<main>').replace('<askyesno>','<main>'))
        MyText.point_file(units,1)
    else:
        MyText.update()
        Wheel(Text,[MyText])

def Wheel(text,other:list):
    first=text.vbar.get()[0]
    for i in other:
        i.yview('moveto',first)

top=tk.Tk()
top.geometry("1250x780+30+0")
top.minsize(152, 1)
top.maxsize(1924, 1055)
top.resizable(1, 1)
top.title("Tin即时渲染")
top.configure(background="#d9d9d9")

Text = scrolledtext.ScrolledText(top,font=('宋体',13))
Text.place(relx=0.0, rely=0.0, relheight=1, relwidth=0.481)
Text.configure(background="white")
Text.configure(foreground="black")
Text.configure(highlightbackground="#d9d9d9")
Text.configure(highlightcolor="black")
Text.configure(insertbackground="black")
Text.configure(selectbackground="#c4c4c4")
Text.configure(selectforeground="black")
Text.configure(wrap="word")
Text.bind('<KeyRelease>',call_back)
#Text.bind('<Return>',call_back)

MyText = TinText(top,font=('宋体',13))
MyText.place(relx=0.501, rely=0.0, relheight=1, relwidth=0.501)
MyText.configure(background="white")
MyText.configure(foreground="black")
MyText.configure(highlightbackground="#d9d9d9")
MyText.configure(highlightcolor="black")
MyText.configure(insertbackground="black")
MyText.configure(selectbackground="#c4c4c4")
MyText.configure(selectforeground="black")
MyText.configure(wrap="word")
set_name(MyText)

Text.bind('<MouseWheel>',lambda event:Wheel(Text,[MyText]))
MyText.bind('<MouseWheel>',lambda event:Wheel(MyText,[Text]))


top.iconbitmap('Tin.ico')
top.mainloop()

效果如下:

在这里插入图片描述

结语

这篇文章仅给出了思路,如何加快解析效率,“任重而道远”。

☀tkinter创新☀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值