最新python tkinter,Python面试必问的HashMap

(1)Python所有方向的学习路线(新版)

这是我花了几天的时间去把Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

最近我才对这些路线做了一下新的更新,知识体系更全面了。

在这里插入图片描述

(2)Python学习视频

包含了Python入门、爬虫、数据分析和web开发的学习视频,总共100多个,虽然没有那么全面,但是对于入门来说是没问题的,学完这些之后,你可以按照我上面的学习路线去网上找其他的知识资源进行进阶。

在这里插入图片描述

(3)100多个练手项目

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了,只是里面的项目比较多,水平也是参差不齐,大家可以挑自己能做的项目去练练。

在这里插入图片描述

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

        self.msg['text']='重新打开或保存即可生效'
        self.msg.after(2500,clear)
    def clear():self.msg['text']=''
    coding.bind('<<ComboboxSelected>>',tip)
    coding["value"]=self.encodings
    coding.pack(side=LEFT)
    self.msg=Label(frame)
    self.msg.pack(side=LEFT)

    self.contents=ScrolledText(self,undo=True, width=75, height=24,
                    font = (self.NORMAL_FONT,self.NORMAL_FONTSIZE,"normal"),
                    wrap=self.AUTOWRAP, bg=self.TEXT_BG,fg=self.TEXT_FG)
    self.contents.pack(expand=True,fill=BOTH)
    self.contents.bind("<Key>",self.text_change)
    self.contents.bind("<B1-ButtonRelease>",self.update_status)
    order = self.contents.bindtags() # 修复无法获取选定的文本的bug
    self.contents.bindtags((order[1], order[0])+order[2:])
    self.update_offset()

    self.create_menu()
def create\_menu(self):
    menu=Menu(self)
    filemenu=Menu(self,tearoff=False)
    filemenu.add_command(label="新建",
                         command=self.new,accelerator="Ctrl+N")
    filemenu.add_command(label="新建二进制文件",command=self.new_binary)
    filemenu.add_command(label="打开",
                         command=self.open,accelerator="Ctrl+O")
    filemenu.add_command(label="打开二进制文件",command=self.open_as_binary)
    filemenu.add_command(label="保存",
                         command=self.save,accelerator="Ctrl+S")
    filemenu.add_command(label="另存为",command=self.save_as)
    filemenu.add_separator()
    filemenu.add_command(label="退出",command=self.ask_for_save)

    self.editmenu=Menu(self.contents,tearoff=False)
    master = self.contents
    self.editmenu.add_command(label="剪切 ",
                     command=lambda:self.text_change()\
                            ==master.event_generate("<<Cut>>"))
    self.editmenu.add_command(label="复制 ",
                     command=lambda:master.event_generate("<<Copy>>"))
    self.editmenu.add_command(label="粘贴 ",
                     command=lambda:self.text_change()\
                            ==master.event_generate("<<Paste>>"))
    self.editmenu.add_separator()
    self.editmenu.add_command(label="查找",accelerator="Ctrl+F",
                              command=lambda:self.show_dialog(SearchDialog))
    self.editmenu.add_command(label="查找下一个",accelerator="F3",
                              command=self.findnext)
    self.editmenu.add_command(label="替换",accelerator="Ctrl+H",
                              command=lambda:self.show_dialog(ReplaceDialog))
    self.editmenu.add_separator()
    self.editmenu.add_command(label="插入十六进制数据",state=DISABLED,
                              command=self.insert_hex)

    view=Menu(self.contents,tearoff=False)
    self.is_autowrap=IntVar(self.contents) # 是否自动换行
    self.is_autowrap.set(1 if self.AUTOWRAP!=NONE else 0)
    view.add_checkbutton(label="自动换行", command=self.set_wrap,
                         variable=self.is_autowrap)
    fontsize=Menu(self.contents,tearoff=False)
    fontsize.add_command(label="选择字体",
                         command=self.choose_font)
    fontsize.add_separator()
    fontsize.add_command(label="增大字体 ",accelerator='Ctrl+ "+"',
                         command=self.increase_font)
    fontsize.add_command(label="减小字体 ",accelerator='Ctrl+ "-"',
                         command=self.decrease_font)
    fontsize.add_separator()

    for i in range(len(self.FONTSIZES)):
        def resize(index=i):
            self.set_fontsize(index)
        fontsize.add_command(label=self.FONTSIZES[i],command=resize)

    self.contents.bind("<Button-3>",
                lambda event:self.editmenu.post(event.x_root,event.y_root))
    view.add_cascade(label="字体",menu=fontsize)
    theme_menu=Menu(self,tearoff=False)
    theme_menu.add_command(label="选择前景色",command=self.select_fg)
    theme_menu.add_command(label="选择背景色",command=self.select_bg)
    theme_menu.add_command(label="重置",command=self.reset_theme)
    view.add_cascade(label="主题",menu=theme_menu)
    self._show_status=IntVar(self)
    self._show_status.set(1 if self.SHOW_STATUS else 0)
    view.add_checkbutton(label="显示状态栏",command=self.show_statusbar,
                     variable=self._show_status)

    helpmenu=Menu(self,tearoff=False)
    helpmenu.add_command(label="关于",command=self.about)
    helpmenu.add_command(label="反馈",command=self.feedback)

    menu.add_cascade(label="文件",menu=filemenu)
    menu.add_cascade(label="编辑",menu=self.editmenu)
    menu.add_cascade(label="查看",menu=view)
    menu.add_cascade(label="帮助",menu=helpmenu)

    # 创建弹出在self.txt\_decoded和self.hexdata的菜单
    popup1=Menu(self.txt_decoded,tearoff=False)
    def \_cut():
        self.txt_decoded.event_generate("<<Cut>>")
        self._edit_decoded_event()
    def \_paste():
        self.txt_decoded.event_generate("<<Paste>>")
        self._edit_decoded_event()
    popup1.add_command(label="剪切",command=_cut)
    popup1.add_command(
        label="复制",command=lambda:self.txt_decoded.event_generate("<<Copy>>"))
    popup1.add_command(label="粘贴",command=_paste)

    popup2=Menu(self.hexdata,tearoff=False)
    popup2.add_command(
        label="复制",command=lambda:self.hexdata.event_generate("<<Copy>>"))

    self.txt_decoded.bind("<Button-3>",
                lambda event:popup1.post(event.x_root,event.y_root))
    self.txt_decoded.bind("<Key>",self._edit_decoded_event)
    self.hexdata.bind("<Button-3>",
                lambda event:popup2.post(event.x_root,event.y_root))

    # 显示菜单
    self.config(menu=menu)
def create\_binarytools(self): # 用于二进制文件
    if self.isbinary: # self.txt\_decoded 用于显示解码的转义字符
        self.txt_decoded.pack(side=LEFT,expand=True,fill=BOTH)
        self.hexdata.pack(fill=Y) # hexdata 用于显示转义字符的十六进制
        self.status.pack_forget()
        self.status.pack(fill=X)
        self.editmenu.entryconfig(8,state=NORMAL)
    else: # 隐藏工具
        if self.txt_decoded:
            self.txt_decoded.pack_forget()
        if self.hexdata:
            self.hexdata.pack_forget()
        self.status.pack(side=RIGHT)
        self.editmenu.entryconfig(8,state=DISABLED) # 禁止插入

以下是部分控件事件的处理, 包含了实现快捷键、改变字体和显示/隐藏状态栏功能:



def \_get\_fontname(self):
    font=' '.join(self.contents["font"].split(' ')[:-2])
    # tkinter会将带空格的字体名称用{}括起来
    if '{' in font:
        font = font[1:-1]
    return font
def set\_fontsize(self,index):
    newsize=self.FONTSIZES[index]
    fontname = self._get_fontname()
    self.contents["font"]=(fontname,newsize,"normal")
def choose\_font(self):
    def ok():
        self.contents["font"]=[opt.get()] + \
                   self.contents["font"].split(' ')[-2:] # 保留原先大小、样式
        dialog.destroy()
    dialog = Toplevel(self)
    dialog.title('选择字体')
    dialog.resizable(False,False)
    dialog.attributes('-toolwindow',True)
    opt = ttk.Combobox(dialog)
    # tkinter.font.families() 获取所有字体名称, 注意root参数
    opt['values']=sorted(font.families(root=self))
    opt.grid(row=0,column=0,columnspan=2,padx=15,pady=20)
    ttk.Button(dialog,text='确定',command=ok).grid(row=1,column=0)
    ttk.Button(dialog,text='取消',command=dialog.destroy).grid(row=1,column=1)
    oldfont = self._get_fontname()
    opt.set(oldfont)
    dialog.grab_set() # 对话框打开时, 不允许用户操作主窗口
    dialog.focus_force()
def increase\_font(self):
    # 增大字体
    fontsize=int(self.contents["font"].split(' ')[1])
    index=self.FONTSIZES.index(fontsize)+1
    if 0<=index<len(self.FONTSIZES): self.set_fontsize(index)
def decrease\_font(self):
    # 减小字体
    fontsize=int(self.contents["font"].split(' ')[1])
    index=self.FONTSIZES.index(fontsize)-1
    if 0<=index<len(self.FONTSIZES): self.set_fontsize(index)
def set\_wrap(self):
    if self.is_autowrap.get():
        self.contents['wrap'] = CHAR
    else:
        self.contents['wrap'] = NONE
    # 注意:由于tkinter会自动设置菜单复选框的变量, 所以不需要此行代码

self.is_autowrap.set(int(not self.is_autowrap.get()))

def show\_statusbar(self):
    if self._show_status.get():
        if self.isbinary:
            self.statusbar.pack(side=BOTTOM,fill=X)
        else:
            self.statusbar.pack(side=BOTTOM,fill=X)
    else:
        self.statusbar.pack_forget()
def window\_onkey(self,event):
    # 实现快捷键的部分
    # 如果按下Ctrl键
    if event.state in (4,6,12,14,36,38,44,46): # 适应多种按键情况(Num,Caps,Scroll)
        key=event.keysym.lower()
        if key=='o':#按下Ctrl+O键
            self.open()
        elif key=='s':#Ctrl+S键
            self.save()
        elif key=='n':
            self.new()
        elif key=='f':
            self.show_dialog(SearchDialog)
        elif key=='h':
            self.show_dialog(ReplaceDialog)
        elif key=='equal':#Ctrl+ "+" 增大字体
            self.increase_font()
        elif key=='minus':#Ctrl+ "-" 减小字体
            self.decrease_font()
    elif event.keysym.lower()=='f3':
        self.findnext()
    elif event.keycode == 93: # 按下了菜单键
        self.editmenu.post(self.winfo_x()+self.winfo_width(),
                           self.winfo_y()+self.winfo_height())
def about(self):
    msgbox.showinfo("关于","版本: %s\n作者: %s"%(__version__, __author__), parent=self)

## 2.文本打开, 保存


打开文件有两种方法, 一种是在当前窗口中打开, 第二种是新建一个`Editor`实例, 在新窗口中打开。这里在新窗口中打开文件。


`ask_for_save()`的部分有一些复杂, 需要多次判断, 如判断用户是否取消操作、询问打开文件前是否需要保存等。  
 如: 用户在"是否保存"中选择了"是", 但在输入文件名的对话框中点击了取消, 应该如何处理?具体可看注释。


关于使用`chardet`库自动检测编码:  
 `chardet.detect()`函数返回一个字典, 包含检测结果。其中`encoding`键即为检测到的编码。


在之前的**Editor类中**加入以下代码:



def new(self): # 新建一个Editor实例
    try:self.saveconfig() # 保存配置,使新的窗口加载修改后的配置
    except OSError:pass # 忽略写入文件可能产生的异常
    window=Editor()
    window.focus_force()
    return window
def new\_binary(self): # 创建新二进制文件
    try:self.saveconfig()
    except OSError:pass
    window=Editor()
    window.isbinary=True
    window.create_binarytools()
    window.change_title()
    window.change_mode()
    window.contents.edit_reset()
    window.focus_force()
    return window
def open(self):
    #加载一个文件
    filename=filediag.askopenfilename(master=self,title='打开',
                        initialdir=os.path.split(self.filename)[0],
                        filetypes=self.FILETYPES)
    if not filename:return
    if not self.filename and not self.file_modified: # 如果是刚新建的, 在当前窗口中打开
        self.load(filename)
    else:self.new().load(filename)
def open\_as\_binary(self):
    filename=filediag.askopenfilename(master=self,title='打开二进制文件',
                            initialdir=os.path.split(self.filename)[0],
                            filetypes=self.FILETYPES)
    if not filename:return
    if not self.filename and not self.file_modified: # 如果是刚新建的
        self.load(filename,binary=True)
    else:self.new().load(filename,binary=True)
def load(self,filename,binary=False):
    # 加载文件
    self.isbinary=binary
    try:
        data=self._load_data(filename)
        if data==0:return
        self.filename=filename
        self.contents.delete('1.0', END)
        if self.isbinary:
            self.contents.insert(INSERT,data)
        else:
            for char in data:
                try:
                    self.contents.insert(INSERT,char)
                except TclError:self.contents.insert(INSERT,' ')
        self.contents.mark_set(INSERT,"1.0")
        self.create_binarytools()
        self.file_modified=False
        self.change_title()
        self.change_mode()
        self.contents.edit_reset() # 重置文本框的撤销功能
        self.contents.focus_force()
    except Exception as err:handle(err,parent=self)
def \_load\_data(self,filename):
    # 从文件加载数据
    f=open(filename,"rb")
    if self.isbinary:
        data=to_escape_str(f.read())
        return data
    else:
        try:
            #读取文件,并对文件内容进行编码
            raw=f.read()
            if self.coding.get()=="自动":
                # 调用chardet库
                encoding=chardet.detect(raw[:100000])['encoding']
                if encoding is None:
                    encoding='utf-8'
                self.coding.set(encoding)
            data=str(raw,encoding=self.coding.get())
        except UnicodeDecodeError:
            f.seek(0)
            result=msgbox.askyesnocancel("PyNotepad","""%s编码无法解码此文件,

是否使用二进制模式打开?“”“%self.coding.get(),parent=self)
if result:
self.isbinary=True
data=to_escape_str(f.read())
elif result is not None:
self.isbinary=False
data=str(f.read(),encoding=self.coding.get(),errors=“replace”)
else:
return 0 # 表示取消
return data
def ask_for_save(self,quit=True):
my_ret=None
if self.file_modified:
retval=msgbox.askyesnocancel(“文件尚未保存”,
“是否保存{}的更改?”.format(
os.path.split(self.filename)[1] or “当前文件”)
,parent=self)
# retval 为 None表示取消, False为否, True为是
if not retval is None:
if retvalTrue:
# 是
ret=self.save()
# 在保存对话框中取消
if ret
0:
my_ret=0;quit=False
# 否
else:
# 取消
my_ret=0;quit=False # 0表示cancel
if quit:
Editor.windows.remove(self)
try:self.saveconfig() # 保存配置, 见附
except OSError:pass
self.destroy() # tkinter不会自动关闭窗口, 需调用函数手动关闭
return my_ret
def save(self):
#保存文件
if not self.filename:
self.filename=filediag.asksaveasfilename(master=self,
initialdir=os.path.split(self.filename)[0],
filetypes=self.FILETYPES)
filename=self.filename
if filename.strip():
text=self.contents.get(‘1.0’, END)[:-1] # [:-1]: 去除末尾换行符
if self.isbinary:
data=to_bytes(text)
else:
data=bytes(text,encoding=self.coding.get(),errors=‘replace’)
# Text文本框的bug:避免多余的\r换行符
# 如:输入文字foobar, data中变成\rfoobar
# -感谢文章末尾用户评论的反馈-
data=data.replace(b’\r’,b’')
with open(filename, ‘wb’) as f:
f.write(data)
self.filename=filename
self.file_modified=False
self.change_title()
self.change_mode()
else:
return 0 # 0表示cancel
def save_as(self):
filename=filediag.asksaveasfilename(master=self,
initialdir=os.path.split(self.filename)[0],
filetypes=self.FILETYPES)
if filename: # 如果未选择取消
self.filename=filename
self.save()
def change_title(self):
file = os.path.split(self.filename)[1] or “未命名”
newtitle=“PyNotepad - “+ file +
(” (二进制模式)” if self.isbinary else ‘’)
if self.file_modified:
newtitle=”*%s*"%newtitle
self.title(newtitle)


## 3.文本编辑


其中, `text_change()`在文本被修改时调用, `update_status()`和`update_offset()`用于更新状态栏中的数据。  
 在二进制模式中, update\_status获取用户选择的文本, 更新解码的数据和十六进制值。update\_offset更新偏移量。在文本模式中, update\_offset更新当前的行数和列数。  
 在ScrolledText控件中,  
 获取选择的文本: `text.get(SEL_FIRST,SEL_LAST)`  
 获取当前光标位置: `text.index(INSERT)`  
 在之前的**Editor类中**加入以下代码:



def text\_change(self,event=None):
    self.file_modified=True
    self.update_status();self.change_title()
def update\_status(self,event=None):
    if not self._show_status.get():return
    if self.isbinary:
        # 用于二进制文件
        try:
            selected=self.contents.get(SEL_FIRST,SEL_LAST) # 获取从开头到光标处的文本
            raw=to_bytes(selected)
            coding=self.coding.get()
            # 调用chardet库
            if coding=="自动":
                coding=chardet.detect(raw[:100000])['encoding']
                if coding is None:coding='utf-8'
            try:text=str(raw,encoding=coding,
                         errors="backslashreplace")
            except TypeError:
                # 修复Python 3.4中的bug: don't know how to handle
                # UnicodeDecodeError in error callback
                text=str(raw,encoding=coding,
                         errors="replace")
            except LookupError as err: # 未知编码
                handle(err,parent=self);return
            self.txt_decoded.delete("1.0",END)
            self.txt_decoded.insert(INSERT,text)
            self.hexdata.delete("1.0",END)
            self.hexdata.insert(INSERT,view_hex(raw))
            self.status["text"]="选区长度: %d (Bytes)"%len(raw)
        except (TclError,SyntaxError): #忽略未选取内容, 或格式不正确
            self.txt_decoded.delete("1.0",END)
            self.hexdata.delete("1.0",END)
            self.update_offset()
    else:self.update_offset()
def update\_offset(self,event=None):
    if self.isbinary:
        prev=self.contents.get("1.0",INSERT) # 获取从开头到光标处的文本
        try:
            data=to_bytes(prev)
        except SyntaxError:
            sep='\\'
            prev=sep.join(prev.split(sep)[0:-1])
            try:data=to_bytes(prev)
            except SyntaxError:data=None
        if data is not None:
            self.status["text"]="偏移量: {} ({})"\
                                 .format(len(data),hex(len(data)))
    else:
        offset=self.contents.index(INSERT).split('.') # 不能用CURRENT
        self.status["text"]="Ln: {} Col: {}".format(\*offset)

## 4.编辑二进制文件


在Python中, bytes数据可用转义序列形式表示, 如\x00\x01\x02\n属于转义序列,  
 可通过`repr(bytes)[2:-1]`,`eval('b"""'+str+'"""')` 实现转义序列与bytes类型的转换。  
 这次, 在**Editor类外部**加入以下代码:



def to_escape_str(byte):
# 将字节(bytes)转换为转义字符串
str=‘’;length=1024
for i in range(0,len(byte),length):
str+=repr( byte[i: i+length] ) [2:-1]
str+=‘\n’
return str

def to_bytes(escape_str):
# 将转义字符串转换为字节
# -*****- 1.2.5版更新: 忽略二进制模式中文字的换行符
escape_str=escape_str.replace(‘\n’,‘’)
escape_str=escape_str.replace(‘“”"’,‘\“\”\"’) # 避免引号导致的SyntaxError
escape_str=escape_str.replace(“‘’'”,“\‘\’\'”)
try:
return eval(‘b"“”’+escape_str+‘“”"’)
except SyntaxError:
return eval(“b’‘’”+escape_str+“‘’'”)


以下代码用于兼容WinHex等软件的十六进制数据, 使用`bytes`对象的`fromhex`、`hex`方法。  
 知识点: `bytes`对象有`fromhex()`和`hex()`方法, 可实现十六进制数据和`bytes`对象之间的**相互转换**。`fromhex()`方法会忽略参数中的空格, 换行符等字符。  
 在Editor类外部加入以下代码:



def view_hex(byte):
result=‘’
for i in range(0,len(byte)):
result+= byte[i:i+1].hex().zfill(2) + ’ ’
if (i+1) % 4 == 0:result+=‘\n’
return result


在**Editor类中**加入以下代码:



def insert\_hex(self):
    hex = simpledialog.askstring('',
                "输入WinHex十六进制数据(如:00 1a 3d ff) :",parent=self)
    if hex is None:return
    try:
        data=bytes.fromhex(hex)
        self.contents.insert('insert',to_escape_str(data))
    except Exception as err:
        handle(err,parent=self)
# 以下代码用于直接在self.txt\_decoded中编辑数据
def \_edit\_decoded\_event(self,event=None):
    self.after(20,self.edit_decoded) # 如果不使用after(),self.txt\_decoded.get不会返回最新的值
def edit\_decoded(self):
    range_=self.contents.tag_ranges(SEL) # 获取选区
    if range_:
        start,end=range_[0].string,range_[1].string # 转换为字符串
    else:start=self.contents.index(INSERT);end=None
    try:
        coding=self.coding.get()
        if coding=="自动":
            msgbox.showinfo('','不支持自动编码, 请选择或输入其他编码',parent=self)
            return
        byte = self.txt_decoded.get('1.0',END)[:-1].encode(coding)
        esc_char = to_escape_str(byte,linesep=False)
        self.file_modified=True;self.change_title()
        if range_:
            self.contents.delete(start,end)
        self.contents.insert(start,esc_char)
        end = '%s+%dc'%(start, len(esc_char))
        self.contents.tag_add(SEL,start,end)
    except Exception as err:handle(err,parent=self)

## 5.查找、替换对话框


这里主要用到文本框Text的`search`方法,  
 该函数接收2个必选参数, 分别是pattern和index, index为起始索引, search 方法返回起始索引处或之后的第一个匹配项的索引。  
 search方法还有一些可选参数:  
 `regexp`: 是否使用正则表达式查找 (比自己编写代码查找要快)。  
 `nocase`: 是否不区分大小写。


显示对话框时, 还需调用Tk,Toplevel的focus方法, 用于使对象获得焦点。  
 注意: 创建`IntVar()`, `StringVar()`时, 需指定参数`master`, 避免创建的变量无法使用。  
 \* 使对话框跟随父窗口最小化、恢复显示的方法: 调用`transient()`方法。


在**Editor类外部**加入以下代码:



class SearchDialog(Toplevel):
#查找对话框
def __init__(self,master):
self.master=master
self.coding=self.master.coding.get()
def init_window(self,title=“查找”):
Toplevel.init(self,self.master)
self.title(title)
self.attributes(“-toolwindow”,True)
self.attributes(“-topmost”,True)
# 当父窗口隐藏后,窗口也跟随父窗口隐藏
self.transient(self.master)
self.wm_protocol(“WM_DELETE_WINDOW”,self.onquit)
def show(self):
self.init_window()
frame=Frame(self)
ttk.Button(frame,text=“查找下一个”,command=self.search).pack()
ttk.Button(frame,text=“退出”,command=self.onquit).pack()
frame.pack(side=RIGHT,fill=Y)
inputbox=Frame(self)
Label(inputbox,text=“查找内容:”).pack(side=LEFT)
self.keyword=StringVar(self.master)
keyword=ttk.Entry(inputbox,textvariable=self.keyword)
keyword.pack(side=LEFT,expand=True,fill=X)
keyword.bind(“”,self.search)
keyword.focus_force()
inputbox.pack(fill=X)
options=Frame(self)
self.create_options(options)
options.pack(fill=X)
def create_options(self,master):
Label(master,text="选项: ").pack(side=LEFT)
self.use_regexpr=IntVar(self.master)
ttk.Checkbutton(master,text=“使用正则表达式”,variable=self.use_regexpr)
.pack(side=LEFT)
self.match_case=IntVar(self.master)
ttk.Checkbutton(master,text=“区分大小写”,variable=self.match_case)
.pack(side=LEFT)
self.use_escape_char=IntVar(self.master)
self.use_escape_char.set(self.master.isbinary)
ttk.Checkbutton(master,text=“使用转义字符”,variable=self.use_escape_char)
.pack(side=LEFT)

def search(self,event=None,mark=True,bell=True):
    text=self.master.contents
    key=self.keyword.get()
    if not key:return
    # 验证用户输入是否正常
    if self.use_escape_char.get():
        try:key=str(to_bytes(key),encoding=self.coding)
        except Exception as err:
            handle(err,parent=self);return
    if self.use_regexpr.get():
        try:re.compile(key)
        except re.error as err:
            handle(err,parent=self);return
    # 默认从当前光标位置开始查找
    pos=text.search(key,INSERT,'end-1c',# end-1c:忽略末尾换行符
                    regexp=self.use_regexpr.get(),
                    nocase=not self.match_case.get())
    if not pos:
        # 尝试从开头循环查找
        pos=text.search(key,'1.0','end-1c',
                    regexp=self.use_regexpr.get(),
                    nocase=not self.match_case.get())
    if pos:
        if self.use_regexpr.get(): # 获取正则表达式匹配的字符串长度
            text_after = text.get(pos,END)
            flag = re.IGNORECASE if not self.match_case.get() else 0
            length = re.match(key,text_after,flag).span()[1]
        else:
            length = len(key)
        newpos="%s+%dc"%(pos,length)
        text.mark_set(INSERT,newpos)
        if mark:self.mark_text(pos,newpos)
        return pos,newpos
    elif bell: # 未找到,返回None
        bell_(widget=self)
def findnext(self,cursor_pos='end',mark=True,bell=True):
    # cursor\_pos:标记文本后将光标放在找到文本开头还是末尾
    # 因为search()默认从当前光标位置开始查找
    # end 用于查找下一个操作, start 用于替换操作
    result=self.search(mark=mark,bell=bell)
    if not result:return
    if cursor_pos=='end':
        self.master.contents.mark_set('insert',result[1])
    elif cursor_pos=='start':
        self.master.contents.mark_set('insert',result[0])
    return result
def mark\_text(self,start_pos,end_pos):
    text=self.master.contents
    text.tag_remove("sel","1.0",END) # 移除旧的tag
    # 已知问题: 代码高亮显示时, 无法突出显示找到的文字
    text.tag_add("sel", start_pos,end_pos) # 添加新的tag 
    lines=text.get('1.0',END)[:-1].count(os.linesep) + 1
    lineno=int(start_pos.split('.')[0])
     # 滚动文本框, 使被找到的内容显示 ( 由于只判断行数, 已知有bug); 另外, text['height']不会随文本框缩放而变化
    text.yview('moveto', str((lineno-text['height'])/lines))
    text.focus_force()
    self.master.update_status()
def onquit(self):
    self.withdraw()

class ReplaceDialog(SearchDialog):
#替换对话框
def show(self):
self.init_window(title=“替换”)
frame=Frame(self)
ttk.Button(frame,text=“查找下一个”, command=self._findnext).pack()
ttk.Button(frame,text=“替换”, command=self.replace).pack()
ttk.Button(frame,text=“全部替换”, command=self.replace_all).pack()
ttk.Button(frame,text=“退出”, command=self.onquit).pack()
frame.pack(side=RIGHT,fill=Y)

    inputbox=Frame(self)
    Label(inputbox,text="查找内容:").pack(side=LEFT)
    self.keyword=StringVar(self.master)
    keyword=ttk.Entry(inputbox,textvariable=self.keyword)
    keyword.pack(side=LEFT,expand=True,fill=X)
    keyword.focus_force()
    inputbox.pack(fill=X)

最后

🍅 硬核资料:关注即可领取PPT模板、简历模板、行业经典书籍PDF。
🍅 技术互助:技术群大佬指点迷津,你的问题可能不是问题,求资源在群里喊一声。
🍅 面试题库:由技术群里的小伙伴们共同投稿,热乎的大厂面试真题,持续更新中。
🍅 知识体系:含编程语言、算法、大数据生态圈组件(Mysql、Hive、Spark、Flink)、数据仓库、Python、前端等等。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 12
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值