1. 配置LineNumbers.py文件
创建名为:LineNumbers.py 文件,粘贴下面的代码到文件中
# IDLEX EXTENSION
## """
## Copyright(C) 2011 The Board of Trustees of the University of Illinois.
## All rights reserved.
##
## Developed by: Roger D. Serwy
## University of Illinois
##
## Permission is hereby granted, free of charge, to any person obtaining
## a copy of this software and associated documentation files (the
## "Software"), to deal with the Software without restriction, including
## without limitation the rights to use, copy, modify, merge, publish,
## distribute, sublicense, and/or sell copies of the Software, and to
## permit persons to whom the Software is furnished to do so, subject to
## the following conditions:
##
## + Redistributions of source code must retain the above copyright
## notice, this list of conditions and the following disclaimers.
## + Redistributions in binary form must reproduce the above copyright
## notice, this list of conditions and the following disclaimers in the
## documentation and/or other materials provided with the distribution.
## + Neither the names of Roger D. Serwy, the University of Illinois, nor
## the names of its contributors may be used to endorse or promote
## products derived from this Software without specific prior written
## permission.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
## IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR
## ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
## CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
## THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
##
##
##
## LineNumbers Extension
##
## Provides line numbers to the left of the source code.
##
## The width of the line numbers adapts. Limit of 99,999 lines (for proper display).
##
## """
config_extension_def = """
[LineNumbers]
enable=1
enable_shell=0
visible=True
[LineNumbers_cfgBindings]
linenumbers-show=
"""
import sys
if sys.version <&#39;3&#39;:
from Tkinter import END, Text, LEFT, Y, NONE, RIGHT, NORMAL, DISABLED, Label, TOP, Frame, X
else:
from tkinter import END, Text, LEFT, Y, NONE, RIGHT, NORMAL, DISABLED, Label, TOP, Frame, X
from idlelib.configHandler import idleConf
from idlelib.Delegator import Delegator
from idlelib.Percolator import Percolator
FONTUPDATEINTERVAL &#61; 1000 # milliseconds
_AFTER_UNDO &#61; True # Flag to have the LineNumberDelegator inserted after the undo delegator
jn &#61; lambda x,y: &#39;%i.%i&#39; % (x,y) # join integers to text coordinates
sp &#61; lambda x: map(int, x.split(&#39;.&#39;)) # convert tkinter Text coordinate to a line and column tuple
def dbprint(func): # A decorator for debugging
def f(*args, **kwargs):
print(func, args, kwargs)
return func(*args, **kwargs)
return f
class LineNumbers(object):
menudefs &#61; [(&#39;options&#39;, [(&#39;!Show Line Numbers&#39;, &#39;<>&#39;)])]
def __init__(self, editwin):
self.editwin &#61; editwin
self.text &#61; self.editwin.text
self.textfont &#61; None
self.width &#61; 2
self.after_id &#61; None
self.create_linenumbers()
e &#61; idleConf.GetOption("extensions", "LineNumbers",
"visible", type&#61;"bool", default&#61;True)
self.set_visible(e)
self.code_context_fix()
def close(self):
if self.after_id:
self.text.after_cancel(self.after_id)
self.visible &#61; False
def adjust_font(self):
try:
# taken from CodeContext.py
newtextfont &#61; self.editwin.text["font"]
if self.textln and newtextfont !&#61; self.textfont:
self.textfont &#61; newtextfont
self.textln["font"] &#61; self.textfont
if self._cc_text:
self._cc_text["font"] &#61; self.textfont
self.update_numbers()
except Exception as err:
import traceback; traceback.print_exc()
def font_timer(self):
if not self.visible:
return
self.adjust_font()
if self.after_id:
self.text.after_cancel(self.after_id)
self.after_id &#61; self.text.after(FONTUPDATEINTERVAL, self.font_timer)
if not _AFTER_UNDO:
self.update_numbers() # fixes a bug due to this percolator being ahead of undo percolator.
def set_visible(self, b&#61;True):
self.visible &#61; b
if self.visible:
self.text.after(1, self.font_timer) # avoid a start-up bug
self.show()
# use .after to avoid a start-up error caused by update_idletasks in update_numbers
self.text.after(1, self.update_numbers)
else:
self.hide()
idleConf.SetOption("extensions", "LineNumbers",
"visible", &#39;%s&#39; % self.visible)
self.editwin.setvar("<>", self.visible)
def linenumbers_show_event(self, ev&#61;None):
self.set_visible(not self.visible)
self._code_context_toggle()
def create_linenumbers(self):
""" Create the widget for displaying line numbers. """
editwin &#61; self.editwin
text &#61; self.text
text_frame &#61; editwin.text_frame
self.textln &#61; textln &#61; Text(text_frame, width&#61;self.width,
height&#61;1, wrap&#61;NONE)
# adjust font
textln.config(font&#61;(idleConf.GetOption(&#39;main&#39;, &#39;EditorWindow&#39;, &#39;font&#39;),
idleConf.GetOption(&#39;main&#39;, &#39;EditorWindow&#39;, &#39;font-size&#39;)))
textln.bind("", self.focus_in_event)
textln.bind(&#39;&#39;, self.button_ignore)
textln.bind(&#39;&#39;, self.button_ignore)
textln.bind(&#39;&#39;, self.button_ignore)
textln.bind(&#39;&#39;, self.button_ignore)
textln.bind(&#39;&#39;, self.button_ignore)
textln.bind(&#39;&#39;, self.button_ignore)
textln.bind("", self.button4)
textln.bind("", self.button5)
textln.tag_config(&#39;LINE&#39;, justify&#61;RIGHT)
textln.insert(END, &#39;1&#39;)
textln.tag_add(&#39;LINE&#39;, &#39;1.0&#39;, END)
# start the line numbers
self.per &#61; per &#61; Percolator(textln)
self.line_delegator &#61; LineDelegator()
per.insertfilter(self.line_delegator)
textln._insert &#61; self.line_delegator.delegate.insert
textln._delete &#61; self.line_delegator.delegate.delete
lines &#61; LineNumberDelegator(self)
if _AFTER_UNDO:
# Percolator.py&#39;s .insertfilter should have an "after&#61;" argument
lines.setdelegate(editwin.undo.delegate)
editwin.undo.setdelegate(lines)
else:
editwin.per.insertfilter(lines)
editwin.vbar[&#39;command&#39;] &#61; self.vbar_split
editwin.text[&#39;yscrollcommand&#39;] &#61; self.yscroll_split
def button4(self, ev&#61;None):
self.text.event_generate("")
return "break"
def button5(self, ev&#61;None):
self.text.event_generate("")
return "break"
def button_ignore(self, ev&#61;None):
return "break"
def show(self):
self.textln.pack(side&#61;LEFT, fill&#61;Y, before&#61;self.editwin.text)
def hide(self):
self.textln.pack_forget()
def focus_in_event(self, event&#61;None):
self.editwin.text.focus_set()
self.textln.tag_remove(&#39;sel&#39;, &#39;1.0&#39;, &#39;end&#39;)
#self.editwin.text.event_generate("<>")
def generate_goto_event(self, event&#61;None):
self.editwin.text.event_generate("<>")
return "break"
def vbar_split(self, *args, **kwargs):
""" split scrollbar commands to the editor text widget and the line number widget """
self.textln.yview(*args, **kwargs)
self.text.yview(*args, **kwargs)
def yscroll_split(self, *args, **kwargs):
""" send yview commands to both the scroll bar and line number listing """
#import traceback; traceback.print_stack()
self.editwin.vbar.set(*args)
self.textln.yview_moveto(args[0])
def update_numbers(self, add&#61;None, remove&#61;None):
if not self.visible: return
textln &#61; self.textln
text &#61; self.editwin.text
endline1, col1 &#61; sp(text.index(END))
endline2, col2 &#61; sp(textln.index(END))
if endline1 # delete numbers textln._delete(&#39;%i.0&#39; % endline1, END) elif endline1 > endline2: # add numbers q &#61; range(endline2, endline1) r &#61; map(lambda x: &#39;%i&#39; % x, q) s &#61; &#39;\n&#39; &#43; &#39;\n&#39;.join(r) textln._insert(END, s) textln.tag_add(&#39;LINE&#39;, &#39;1.0&#39;, END) # adjust width of textln, if needed. (counts from 1, not zero) if endline1 <&#61; 100: width &#61; 2 elif endline1 <&#61; 1000: width &#61; 3 elif endline1 <&#61; 10000: width &#61; 4 else: width &#61; 5 # more than 9999 lines in IDLE? Really? # XXX: If your code requires width>5, i.e > 100,000 lines of code, # you probably should not be using IDLE. if width > self.width: # 2011-12-18 - only grow, not shrink self.width &#61; width textln.configure(width&#61;width) if self._cc_text: # adjust CC width self._cc_text.configure(width&#61;width) self.textln.update_idletasks() a &#61; self.text.yview() self.textln.yview_moveto(a[0]) def code_context_fix(self): self._cc_text &#61; None self._cc_frame &#61; None def f(): self.text.bind(&#39;<>&#39;, self._code_context_toggle, &#39;&#43;&#39;) self._code_context_toggle() self.text.after(10, f) def _code_context_toggle(self, event&#61;None): cc &#61; self.editwin.extensions.get(&#39;CodeContext&#39;, None) if cc is None: return if not self.visible: if self._cc_frame: L &#61; cc.label L.pack_forget() self._cc_frame.destroy() L.pack(side&#61;TOP, fill&#61;X, expand&#61;False, before&#61;self.editwin.text_frame) return editwin &#61; self.editwin text &#61; self.text text_frame &#61; editwin.text_frame # repack the Label in a frame if cc.label: cc.label.pack_forget() F &#61; Frame(self.editwin.top) F.lower() # fix Z-order t &#61; Text(F, width&#61;self.width, height&#61;1, takefocus&#61;0) t.bind("", lambda x: self.text.focus()) t["font"] &#61; self.textln.cget(&#39;font&#39;) t.pack(side&#61;LEFT, fill&#61;Y) cc.label.pack(in_&#61;F, fill&#61;X, expand&#61;False) F.pack(side&#61;TOP, before&#61;text_frame, fill&#61;X, expand&#61;False) self._cc_frame &#61; F self._cc_text &#61; t else: if self._cc_frame: self._cc_frame.destroy() self._cc_frame &#61; None self._cc_text &#61; None class LineNumberDelegator(Delegator): # for editwin.text def __init__(self, line_number_instance): Delegator.__init__(self) self.ext &#61; line_number_instance def insert(self, index, chars, tags&#61;None): self.delegate.insert(index, chars, tags) if &#39;\n&#39; in chars: self.ext.update_numbers()#add&#61;chars.count(&#39;\n&#39;)) def delete(self, index1, index2&#61;None): t &#61; self.get(index1, index2) self.delegate.delete(index1, index2) if &#39;\n&#39; in t: self.ext.update_numbers()#remove&#61;t.count(&#39;\n&#39;)) class LineDelegator(Delegator): # for textln def insert(self, *args, **kargs): pass def delete(self, *args, **kargs): pass 复制 LineNumbers.py文件到Python安装目录下的Lib\idlelib文件夹。 2. 启动扩展 配置idlelib目录下的config-extensions.def文件 往config-extensions.def文件配置如下数据&#xff1a; [LineNumbers] enable&#61;True #开启扩展 enable_editor&#61;True #开启idle编辑器支持 enable_shell&#61;True #开启idle shell支持 visible&#61;True #扩展可见![](https://img2020.cnblogs.com/blog/1995639/202004/1995639-20200406141238406-1079269100.png) 保存之后重启IDLE&#xff0c;可以看到我们的Shell和editor都有了行号。