历史文章
1.记录基于Python tkinter的音乐播放器的实现过程
基于python tkinter的本地小说阅读器
前言
之前有用过carlibre在电脑上看小说,carlibre整体感觉还不错,引入小说然后转换就可以阅读了,有点不爽的是,转换有点慢,等待时间有点长。现在利用python tinker来模拟carlibre转换、阅读小说。
一、阅读器功能设计思路
1.转换功能:这里的转换不是将".txt"转换“.epub”格式的小说,而是将txt小说按章节切割、转换为多个章节文本,并且形成章节目录,方便使用者根据目录阅读。
2.选择小说:转换后会在txt小说的文件目录下生成小说同名文件夹,里面包含转换后的章节文件。阅读者选择该同名文件夹即可阅读。
3.阅读小说:读取当前选中的小说章节,将章节内容插入到阅读区。
4.上/下章:根据当前小说章节索引,操作读取上/下章文件内容。
5.阅读记录:记录阅读该小说时的章节次序,方便阅读者查看自己的阅读痕迹,同时方便再次打开该小说时,立马读取到上次阅读的最新章节。
6.朗读:机器朗读阅读区的文字内容,可以停止和继续朗读,朗读语速也可以调节。并且阅读区自动跟踪当前朗读的小说段落。朗读引擎选择的是pyttsx3。
7.字体设置:目前设置适配有“楷体”,“隶书”,“微软雅黑”三款字体。默认楷体,因为个人感觉楷体最简洁美观,阅读时赏心悦目。因为不同的字体,字体的像素也不同,所以切换字体时,组件的尺寸大小也会伸缩。为了达到美观,在切换字体时,需重新适配字体对应的参数。
二、阅读器使用展示
1.准备工作:将下载好的txt小说放到某个文件夹下,这里以《诛仙》小说为例。
2.点击界面的转换按钮,在文件资源管理器里选择txt小说,就会自动转换。转换时按钮会亮,转换完成后会变回原来的颜色,所以可以根据颜色判断是否转换完成。转换完成后,在txt小说文件目录下,会看到小说同名文件夹。
转换一次就行,下次阅读直接通过选择按钮打开小说同名文件夹就可以了。
3.点击“选择”按钮,在文件资源管理器里选择同名小说文件夹,如果是第一次打开该小说,就会读取小说最前面的章节;如果阅读过,就会打开上次读到过的最新章节。点击记录按钮可以查看阅读章节痕迹。
4. 读取章节:选中目录框里章节,点击读取按钮,阅读区就会该章内容。也可以双击章节打开,或者通过上/下章来打开章节内容。
5.查看阅读记录,最新阅读的章节在上面,最早阅读过的章节在下面。这里的背景颜色本应是灰色的,为了方便展示,特地调成白色。因为读者在阅读时不会太在意章节、记录这些,而目录的白色或其他颜色,会太过显眼而吸引读者的目光,削弱读者对阅读区的注意力。因而背景颜色默认都是灰黑色。
6.打开小说文件夹,可以看到3项
chapter文件夹,里面存放切割后的章节文本
chapterName.txt 记录小说的章节目录
readRecord.txt 记录阅读过的章节
7.朗读功能:打开某章节,点击朗读,就会重头开始朗读本章内容。
可以停止/继续朗读, 点击“慢速”、“快速”用来调节朗读语速。
8.字体设置:“楷体”显示当前的字体,默然楷体。点击“楷体”,可以切换阅读的字体。
ps: 按钮区空出来的两个位置,后续想到新的功能,再将按钮补上吧。
三、 代码展示
下面是阅读器的完整代码:
import tkinter as tk
from tkinter import *
from tkinter import filedialog
from tkinter import ttk
from tkinter import scrolledtext
import os
import time
import threading
import pyttsx3
import shutil
class Reader():
def __init__(self):
# colors
self.GlobalColor = '#F1E9D2' # 羊皮纸颜色
self.lightyellow = '#FFE57D'
self.gray = "#414441"
black = "#081010" #rgb(8,16,16) 背景色:暗黑色
self.COLOR_SIZE = 12
self.myColors = [self.GlobalColor]*self.COLOR_SIZE
self.wordStyle = '楷体'
self.bgStyle = self.gray
self.fgStyle = 'white'
self.fsize = 12
self.oneSize = 4
self.numSize = 3
self.listbox_WidthSize = 45
self.listbox_HeightSize = 52
self.scorllT_WidthSize = 80
self.scorllT_HeightSize = 28
self.Label_novelName_size = 30
self.Label_chapterName_size = 89
self.PressCnt = 0
self.SPEED = 200
self.Step = 50
self.OrientPath = ""
self.chapterName_path = ""
self.chapterId = 0
self.BreakNum = 40
self.CHANGE_NEW = 0
self.FlagNo = 0
self.SWITCH = 1
# 朗读初始化
self.speak = pyttsx3.init()
self.screen = tk.Tk()
self.screen.geometry('1500x700')
self.screen.title('本地阅读器')
# 小说名
self.StrngVar_novelName = tk.StringVar()
self.Label_novelName = tk.Label(self.screen, width=self.Label_novelName_size, height=2, fg=self.fgStyle, bg=self.bgStyle, font=(self.wordStyle, self.fsize+self.oneSize),
textvariable=self.StrngVar_novelName)
self.Label_novelName.place(x=400, y=10)
# 章节名
self.StrngVar_chapterName = tk.StringVar()
self.Label_chapterName = tk.Label(self.screen, width=self.Label_chapterName_size, height=2, fg=self.fgStyle, bg=self.bgStyle, font=(self.wordStyle, self.fsize+self.oneSize),
textvariable=self.StrngVar_chapterName)
self.Label_chapterName.place(x=700, y=10)
#滑动条
self.scroll1 = tk.Scrollbar(self.screen)
self.ListBox_chapterName = tk.Listbox(self.screen, width=self.listbox_WidthSize, height=self.listbox_HeightSize, bg=self.bgStyle, fg=black, font=(self.wordStyle, self.fsize),
yscrollcommand=self.scroll1.set)
#章节名列表框
self.ListBox_chapterName.config(yscrollcommand=self.scroll1.set)
self.scroll1.config(command=self.ListBox_chapterName.yview)
self.ListBox_chapterName.place(x=20, y=105)
self.scroll1.pack(side='left', fill='both')
# 选择小说文件夹
self.Button_chooseFloder = tk.Button(self.screen, text='选择', bg=self.GlobalColor, fg=black, font=(self.wordStyle, self.fsize), command=self.get_floder)
self.Button_chooseFloder.place(x=20, y=10)
self.CreateToolTip(self.Button_chooseFloder, "选择小说文件夹")
# 列出章节按钮
self.Button_readMenu = tk.Button(self.screen, text='目录', bg=self.GlobalColor, fg=black, font=(self.wordStyle, self.fsize), command=self.readChapterName)
self.Button_readMenu.place(x=70, y=10)
self.CreateToolTip(self.Button_readMenu, "显示目录")
# 读取章节按钮
self.Button_readTxt = tk.Button(self.screen, text='读取', bg=self.GlobalColor, fg=black, font=(self.wordStyle, self.fsize), command=self.readText)
self.Button_readTxt.place(x=120, y=10)
self.CreateToolTip(self.Button_readTxt, "读取选中的章节")
# 阅读历史
self.Button_readHistory = tk.Button(self.screen, text='记录', bg=self.GlobalColor, fg=black, font=(self.wordStyle, self.fsize), command=self.readHistory)
self.Button_readHistory.place(x=170, y=10)
self.CreateToolTip(self.Button_readHistory, "显示阅读该小说的章节痕迹")
# 转换分割小说
self.Button_splitChapter = tk.Button(self.screen, text='转换', bg=self.GlobalColor, fg=black, font=(self.wordStyle, self.fsize), command=self.split_chapter)
self.Button_splitChapter.place(x=220, y=10)
self.CreateToolTip(self.Button_splitChapter, "选中txt小说转换")
# 自动朗读小说
self.Button_scrollread = tk.Button(self.screen, text='朗读', bg=self.GlobalColor, fg=black, font=(self.wordStyle, self.fsize), command=lambda: self.thread_it(self.srcollRead))
self.Button_scrollread.place(x=270, y=10)
self.CreateToolTip(self.Button_scrollread, "机器朗读")
# 停止朗读小说
self.Button_scrollreadStop = tk.Button(self.screen, text='停止', bg=self.GlobalColor, fg=black, font=(self.wordStyle, self.fsize), command=self.srcollReadStop)
self.Button_scrollreadStop.place(x=320, y=10)
self.CreateToolTip(self.Button_scrollreadStop, "停止朗读")
# 字体设置
self.Button_setFont = tk.Button(self.screen, text='楷体', bg=self.GlobalColor, fg=black, font=(self.wordStyle, self.fsize), command=self.setFont)
self.Button_setFont.place(x=20, y=60)
self.CreateToolTip(self.Button_setFont, "设置字体")
# 上一章
self.Button_lastChapter = tk.Button(self.screen, text='上章', bg=self.GlobalColor, fg=black, font=(self.wordStyle, self.fsize), command=self.lastChapter)
self.Button_lastChapter.place(x=70, y=60)
self.CreateToolTip(self.Button_lastChapter, "读取上一章")
# 下一章
self.Button_nextChapter = tk.Button(self.screen, text='下章', bg=self.GlobalColor, fg=black, font=(self.wordStyle, self.fsize), command=self.nextChapter)
self.Button_nextChapter.place(x=120, y=60)
self.CreateToolTip(self.Button_nextChapter, "读取下一章")
# 减慢朗读速度
self.Button_voiceReduce = tk.Button(self.screen, text='慢速', bg=self.GlobalColor, fg=black, font=(self.wordStyle, self.fsize), command=self.voiceReduce)
self.Button_voiceReduce.place(x=270, y=60)
self.CreateToolTip(self.Button_voiceReduce, "朗读减慢")
# 减慢朗读速度
self.Button_voiceIncrease = tk.Button(self.screen, text='快速', bg=self.GlobalColor, fg=black, font=(self.wordStyle, self.fsize), command=self.voiceIncrease)
self.Button_voiceIncrease.place(x=320, y=60)
self.CreateToolTip(self.Button_voiceIncrease, "朗读加快")
# 阅读区
self.Scoller_text = scrolledtext.ScrolledText(self.screen, width=self.scorllT_WidthSize, height=self.scorllT_HeightSize, wrap = tk.WORD, bg=self.bgStyle, fg=self.fgStyle, font=(self.wordStyle, self.fsize+self.numSize*self.oneSize))
self.Scoller_text.place(x=400, y=60)
self.ListBox_chapterName.bind('<Double-Button-1>', self.readText)
self.ListBox_chapterName.bind('<Return>', self.readText)
self.screen.mainloop()
# 设置字体
def setFont(self, *args):
self.setColor(7)
if(self.PressCnt%3 == 0):
self.wordStyle = "微软雅黑"
self.fsize = 12
self.listbox_WidthSize = 40
self.listbox_HeightSize = 40
self.scorllT_WidthSize = 80
self.scorllT_HeightSize = 26
self.Label_chapterName_size = 75
self.numSize = 2
self.Button_setFont.config(text="雅黑", font=(self.wordStyle,self.fsize))
self.BreakNum = 47
elif(self.PressCnt%3 == 1):
self.wordStyle = "隶书"
self.fsize = 14
self.listbox_WidthSize = 37
self.listbox_HeightSize = 44
self.scorllT_WidthSize = 71
self.scorllT_HeightSize = 26
self.Label_chapterName_size = 81
self.numSize = 3
self.Button_setFont.config(text="隶书",font=(self.wordStyle,self.fsize))
self.BreakNum = 35
else:
self.wordStyle = "楷体"
self.fsize = 12
self.listbox_WidthSize = 45
self.listbox_HeightSize = 52
self.scorllT_WidthSize = 80
self.scorllT_HeightSize = 28
self.Label_novelName_size = 30
self.Label_chapterName_size = 89
self.numSize = 3
self.Button_setFont.config(text="楷体", font=(self.wordStyle,self.fsize))
self.BreakNum = 40
self.Label_novelName.config(width=self.Label_novelName_size,font=(self.wordStyle, self.fsize+self.oneSize))
self.Label_chapterName.config(width=self.Label_chapterName_size, font=(self.wordStyle, self.fsize+self.oneSize))
self.ListBox_chapterName.config(width=self.listbox_WidthSize, height=self.listbox_HeightSize,font=(self.wordStyle,self.fsize))
self.Button_chooseFloder.config(font=(self.wordStyle,self.fsize))
self.Button_readMenu.config(font=(self.wordStyle,self.fsize))
self.Button_readTxt.config(font=(self.wordStyle,self.fsize))
self.Button_readHistory.config(fon=(self.wordStyle,self.fsize))
self.Button_splitChapter.config(font=(self.wordStyle,self.fsize))
self.Button_scrollread.config(font=(self.wordStyle,self.fsize))
self.Button_scrollreadStop.config(font=(self.wordStyle,self.fsize))
self.Button_lastChapter.config(fon=(self.wordStyle,self.fsize))
self.Button_nextChapter.config(font=(self.wordStyle,self.fsize))
self.Button_voiceReduce.config(font=(self.wordStyle,self.fsize))
self.Button_voiceIncrease.config(font=(self.wordStyle,self.fsize))
self.Scoller_text.config(width=self.scorllT_WidthSize, height=self.scorllT_HeightSize,font=(self.wordStyle, self.fsize+self.numSize*self.oneSize))
self.fillScrolledText()
self.PressCnt += 1
# 点击按钮时色亮,突出显现
def setColorWay(self, way, *args):
for i in range(self.COLOR_SIZE):
if way == i:
self.myColors[i] = self.lightyellow
else:
self.myColors[i] = self.GlobalColor
# button颜色变换封装
def buttonColor(self, *args):
self.Button_chooseFloder.config(bg=self.myColors[0])
self.Button_readMenu.config(bg=self.myColors[1])
self.Button_readTxt.config(bg=self.myColors[2])
self.Button_readHistory.config(bg=self.myColors[3])
self.Button_splitChapter.config(bg=self.myColors[4])
self.Button_scrollread.config(bg=self.myColors[5])
self.Button_scrollreadStop.config(bg=self.myColors[6])
self.Button_setFont.config(bg=self.myColors[7])
self.Button_lastChapter.config(bg=self.myColors[8])
self.Button_nextChapter.config(bg=self.myColors[9])
self.Button_voiceReduce.config(bg=self.myColors[10])
self.Button_voiceIncrease.config(bg=self.myColors[11])
# 设置点击时的颜色
def setColor(self, num):
self.setColorWay(num)
self.buttonColor()
# 选择小说
def get_floder(self, *args):
self.setColor(0)
order = self.threadChangeFlag()
self.OrientPath = filedialog.askdirectory()
start = len(self.OrientPath) - self.OrientPath[::-1].index("/")
novel = "《 "+self.OrientPath[start:]+" 》"
self.StrngVar_novelName.set(novel)
self.readChapterName()
# 分割小说时保存章节名
def write_Name(self, chapter_name):
chapterName = self.OrientPath + "\\" + "chapterName.txt"
with open(chapterName, "a") as f:
f.write(chapter_name)
f.write("\n")
# 获取小说的章节名
def get_name(self, line):
jieName = ""
chapter = self.OrientPath + "\\chapter"
if (("第" in line)
and ( ( ("回 " in line) or ("章 " in line) or ("节 " in line)
or ("卷 " in line) or ("部 " in line) )
or ( ("回:" in line) or ("章:" in line) or ("节:" in line)
or ("卷:" in line) or ("部:" in line)) ) ):
line = "".join([char for char in line if(char != "?") or (char != "*")])
jieName = chapter + "\\" + line.strip() + ".txt"
self.write_Name(jieName)
return jieName
# 换行
def lineBreak(self, line):
cnt = 1
if(line.strip() == ""):
return line
string = "\n"
for i in range(len(line)):
string = string+line[i]
if(cnt%self.BreakNum==0):
string = string + "\n\n"
cnt += 1
return string
# 按小说章节名分割
def split_chapter(self):
self.setColor(4)
order = self.threadChangeFlag()
file = filedialog.askopenfilename()
start = len(file) - file[::-1].index("/")
end = file.index(".txt")
floder_path = file[:end]
floder_name = file[start:end]
self.OrientPath = floder_path
if os.path.exists(floder_path):
for f in os.listdir(floder_path):
file_path = os.path.join(floder_path, f)
if(f.endswith(".txt")):
os.remove(file_path)
else:
shutil.rmtree(file_path)
os.rmdir(floder_path)
else:
os.makedirs(floder_path)
chapter_path = floder_path+"\\chapter"
os.makedirs(chapter_path)
chapterName = ""
with open(file, "r", encoding="utf-8") as f:
try:
lines = f.readlines()
for line in lines:
jieName = self.get_name(line)
if(len(jieName)>1):
chapterName = jieName
if(len(chapterName)>1):
with open(chapterName, "a+") as f2:
f2.write(line)
f2.write("\n")
except:
with open(file, "r", encoding="gbk") as f:
lines = f.readlines()
for line in lines:
jieName = self.get_name(line)
if(len(jieName)>1):
chapterName = jieName
if(len(chapterName)>1):
with open(chapterName, "a+") as f2:
f2.write(line)
f2.write("\n")
print(f"《 {floder_name} 》转换完成!")
self.setColor(self.COLOR_SIZE)
# 截取小说章节名
def get_chaterName(self, string):
start = string.index("第")
name = string[start:-5]
return name
# 按保存的章节名读取出来就是小说目录了
def readChapterName(self, *args):
chapterName = self.OrientPath + "\\" + "chapterName.txt"
readRecord = self.OrientPath + "\\" + "readRecord.txt"
path = self.OrientPath + "\\" + "chapter"
self.setColor(1)
order = self.threadChangeFlag()
first_chapter = ""
with open(chapterName, 'r+', encoding="utf-8") as f:
try:
lines = f.readlines()
first_chapter = lines[0]
self.ListBox_chapterName.delete(0, tk.END)
for line in lines:
name = self.get_chaterName(line)
self.ListBox_chapterName.insert('end', name)
except:
with open(chapterName, 'r+',encoding="gbk") as f:
lines = f.readlines()
first_chapter = lines[0]
self.ListBox_chapterName.delete(0, tk.END)
for line in lines:
name = self.get_chaterName(line)
self.ListBox_chapterName.insert('end', name)
try:
with open(readRecord, 'r+') as f1:
lines = f1.readlines()
if(len(lines)>0):
lines.reverse()
line = lines[0]
end = line.index(":")
index = int(line[:end])
self.chapterId = self.ListBox_chapterName.index(index)
self.chapterName_path = path+"\\"+line[end+1:].strip() +".txt"
self.StrngVar_chapterName.set(line[end+1:].strip())
self.Scoller_text.delete(1.0, tk.END)
self.listBoxSee()
with open(self.chapterName_path, 'r') as f2:
lines = f2.readlines()
for line in lines:
strings = self.lineBreak(line)
self.Scoller_text.insert("end", strings)
except:
self.chapterName_path = first_chapter.strip()
self.StrngVar_chapterName.set(self.get_chaterName(first_chapter))
self.chapterId = 0
self.listBoxSee()
with open(self.chapterName_path,"r", encoding="utf-8") as f3:
try:
lines = f3.readlines()
self.Scoller_text.delete(1.0, tk.END)
for line in lines:
strings = self.lineBreak(line)
self.Scoller_text.insert("end", strings)
except:
with open(self.chapterName_path,"r", encoding="gbk") as f3:
lines = f3.readlines()
self.Scoller_text.delete(1.0, tk.END)
for line in lines:
strings = self.lineBreak(line)
self.Scoller_text.insert("end", strings)
# 每读取一章,就保存该章节的名字
def mark(self, string):
readRecord = self.OrientPath + "\\" + "readRecord.txt"
with open(readRecord, "a+") as f:
f.write(string)
f.write("\n")
# 换字体时重新读取阅读区
def fillScrolledText(self):
self.Scoller_text.delete(1.0, tk.END)
with open(self.chapterName_path, "r") as f:
lines = f.readlines()
for line in lines:
strings = self.lineBreak(line)
self.Scoller_text.insert("end", strings)
# 读取小说章节
def readText(self, *args):
order = self.threadChangeFlag()
self.setColor(2)
path = self.OrientPath + "\\" + "chapter"
chapterName = self.ListBox_chapterName.get(self.ListBox_chapterName.curselection())
self.chapterId = self.ListBox_chapterName.index(self.ListBox_chapterName.curselection())
self.StrngVar_chapterName.set(self.ListBox_chapterName.get(self.ListBox_chapterName.curselection()))
self.chapterName_path = path+"\\"+chapterName+".txt"
string = str(self.chapterId) + ":" + chapterName
self.mark(string)
self.Scoller_text.delete(1.0, tk.END)
with open(self.chapterName_path, "r") as f:
lines = f.readlines()
for line in lines:
strings = self.lineBreak(line)
self.Scoller_text.insert("end", strings)
# 读取阅读后的章节历史
def readHistory(self, *args):
readRecord = self.OrientPath + "\\" + "readRecord.txt"
self.ListBox_chapterName.delete(0,tk.END)
order = self.threadChangeFlag()
self.setColor(3)
with open(readRecord, "r+") as f:
lines = f.readlines()
lines.reverse()
for line in lines:
self.ListBox_chapterName.insert('end', line)
# 滚动浏览需要用到延时,所以需要线程
# 这是线程的信令
def threadChangeFlag(self, *args):
if self.FlagNo >= 100:
self.FlagNo = 0
else:
self.FlagNo += 1
self.CHANGE_NEW = self.FlagNo
return self.FlagNo
# 无参数传递的线程封装,按钮函数
def thread_it(self, func, *args):
'''将函数放入线程中执行'''
# 创建线程
t = threading.Thread(target=func, args=args)
# 守护线程
t.setDaemon = True
# 启动线程
t.start()
# 等待结束
# t.join()
# 朗读速度增加
def voiceIncrease(self, *args):
self.SPEED += self.Step
self.setColor(11)
return self.SPEED
# 朗读速度减慢
def voiceReduce(self, *args):
self.SPEED -= self.Step
self.setColor(10)
return self.SPEED
# 朗读文本
def recitation(self, text):
self.speak.setProperty("rate", self.SPEED)
self.speak.setProperty("voice", "zh+m7")
self.speak.say(text)
self.speak.runAndWait()
# 滚动朗读
def srcollRead(self, *args):
lines = []
size = 0
index = 0
order = self.threadChangeFlag()
self.setColor(5)
with open(self.chapterName_path, "r") as f:
lines = f.readlines()
size = len(lines)
self.Scoller_text.delete(1.0, tk.END)
while(index < size and order == self.CHANGE_NEW):
if(self.SWITCH == 1):
paragraph = lines[index]
text = self.lineBreak(paragraph)
self.Scoller_text.insert(tk.END, text)
self.Scoller_text.update()
self.Scoller_text.see(tk.END)
self.recitation(text)
index += 1
elif(self.SWITCH == 0):
index += 0
time.sleep(1)
# 停止滚动浏览
def srcollReadStop(self, *args):
self.setColor(6)
if(self.SWITCH == 1):
self.SWITCH = 0
self.Button_scrollreadStop.config(text="停止")
else:
self.SWITCH = 1
self.Button_scrollreadStop.config(text="继续")
# 上下章的中间处理过程
def chapterProcess(self):
chapterName = self.ListBox_chapterName.get(self.chapterId)
self.chapterName_path = self.OrientPath + "\\" + "chapter" + "\\" + chapterName + ".txt"
self.StrngVar_chapterName.set(chapterName)
string = str(self.chapterId) + ":" + chapterName
self.mark(string)
self.listBoxSee()
self.Scoller_text.delete(1.0, tk.END)
with open(self.chapterName_path, "r", encoding="utf-8") as f:
lines = f.readlines()
for line in lines:
strings = self.lineBreak(line)
self.Scoller_text.insert("end", strings)
# 上一章
def lastChapter(self, *args):
order = self.threadChangeFlag()
self.setColor(8)
self.chapterId -= 1
self.chapterProcess()
# 下一章
def nextChapter(self, *args):
order = self.threadChangeFlag()
self.setColor(9)
self.chapterId += 1
self.chapterProcess()
# 跟踪显示章节名
def listBoxSee(self):
self.ListBox_chapterName.selection_clear(0, 'end')
self.ListBox_chapterName.selection_set(self.chapterId)
self.ListBox_chapterName.see(self.chapterId)
#创建该控件的函数
"""
第一个参数:是定义的控件的名称
第二个参数,是要显示的文字信息
"""
def CreateToolTip(self, widget, text):
toolTip = ToolTip(widget)
def enter(event):
toolTip.showtip(text)
def leave(event):
toolTip.hidetip()
widget.bind('<Enter>', enter)
widget.bind('<Leave>', leave)
#对提示信息控件的定义
class ToolTip(object):
def __init__(self, widget):
self.widget = widget
self.tipwindow = None
self.id = None
self.x = self.y = 0
#当光标移动指定控件是显示消息
def showtip(self, text):
"Display text in tooltip window"
self.text = text
if self.tipwindow or not self.text:
return
x, y, cx, cy = self.widget.bbox("insert")
x = x + self.widget.winfo_rootx()+30
y = y + cy + self.widget.winfo_rooty()+30
self.tipwindow = tw = Toplevel(self.widget)
tw.wm_overrideredirect(True)
tw.wm_geometry("+%d+%d" % (x, y))
label = Label(tw, text=self.text,justify=LEFT,
background="white", relief=SOLID, borderwidth=1,
font=("雅黑", "10"))
label.pack(side=BOTTOM)
#当光标移开时提示消息隐藏
def hidetip(self):
tw = self.tipwindow
self.tipwindow = None
if tw:
tw.destroy()
if __name__ == "__main__":
app = Reader()