开头感谢Roger D. Serwy University of Illinois(写LineNumbers.py的大佬)
以及 感谢大佬们的介绍,以下是主要参考博客网址
1. https://blog.csdn.net/gfs258/article/details/107535027?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160173762319724836741631%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=160173762319724836741631&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v25-3-107535027.pc_search_result_cache&utm_term=Python3.8+IDLE行号&spm=1018.2118.3001.4187
2. https://jingyan.baidu.com/article/915fc414a8734051394b20eb.html
那么,我们开始吧
Step 1. 首先我们需要下载一个.py的文件,是用来解决行号的
下载地址:svwh.dl.sourceforge.net/project/sourcetrac/tmp/IDLE/idlexlib/extensions/LineNumbers.py
这个网址需要科学上网,所以我把.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, Xfrom idlelib.configHandler import idleConf
from idlelib.Delegator import Delegator
from idlelib.Percolator import PercolatorFONTUPDATEINTERVAL &#61; 1000 # milliseconds_AFTER_UNDO &#61; True # Flag to have the LineNumberDelegator inserted after the undo delegatorjn &#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 tupledef dbprint(func): # A decorator for debuggingdef f(*args, **kwargs):print(func, args, kwargs)return func(*args, **kwargs)return fclass LineNumbers(object):menudefs &#61; [(&#39;options&#39;, [(&#39;!Show Line Numbers&#39;, &#39;<>&#39;)])]def __init__(self, editwin):self.editwin &#61; editwinself.text &#61; self.editwin.textself.textfont &#61; Noneself.width &#61; 2self.after_id &#61; Noneself.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; Falsedef adjust_font(self):try:# taken from CodeContext.pynewtextfont &#61; self.editwin.text["font"]if self.textln and newtextfont !&#61; self.textfont:self.textfont &#61; newtextfontself.textln["font"] &#61; self.textfontif self._cc_text:self._cc_text["font"] &#61; self.textfontself.update_numbers()except Exception as err:import traceback; traceback.print_exc()def font_timer(self):if not self.visible:returnself.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; bif self.visible:self.text.after(1, self.font_timer) # avoid a start-up bugself.show()# use .after to avoid a start-up error caused by update_idletasks in update_numbersself.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.editwintext &#61; self.texttext_frame &#61; editwin.text_frameself.textln &#61; textln &#61; Text(text_frame, width&#61;self.width,height&#61;1, wrap&#61;NONE)# adjust fonttextln.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 numbersself.per &#61; per &#61; Percolator(textln)self.line_delegator &#61; LineDelegator()per.insertfilter(self.line_delegator)textln._insert &#61; self.line_delegator.delegate.inserttextln._delete &#61; self.line_delegator.delegate.deletelines &#61; LineNumberDelegator(self)if _AFTER_UNDO:# Percolator.py&#39;s .insertfilter should have an "after&#61;" argumentlines.setdelegate(editwin.undo.delegate)editwin.undo.setdelegate(lines)else:editwin.per.insertfilter(lines)editwin.vbar[&#39;command&#39;] &#61; self.vbar_spliteditwin.text[&#39;yscrollcommand&#39;] &#61; self.yscroll_splitdef 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: returntextln &#61; self.textlntext &#61; self.editwin.textendline1, col1 &#61; sp(text.index(END))endline2, col2 &#61; sp(textln.index(END))if endline1 endline2:# add numbersq &#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; 2elif endline1 <&#61; 1000:width &#61; 3elif endline1 <&#61; 10000:width &#61; 4else: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 shrinkself.width &#61; widthtextln.configure(width&#61;width)if self._cc_text: # adjust CC widthself._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; Noneself._cc_frame &#61; Nonedef 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:returnif not self.visible:if self._cc_frame:L &#61; cc.labelL.pack_forget()self._cc_frame.destroy()L.pack(side&#61;TOP, fill&#61;X, expand&#61;False,before&#61;self.editwin.text_frame)returneditwin &#61; self.editwintext &#61; self.texttext_frame &#61; editwin.text_frame# repack the Label in a frameif cc.label:cc.label.pack_forget()F &#61; Frame(self.editwin.top)F.lower() # fix Z-ordert &#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; Fself._cc_text &#61; telse:if self._cc_frame:self._cc_frame.destroy()self._cc_frame &#61; Noneself._cc_text &#61; Noneclass LineNumberDelegator(Delegator):# for editwin.textdef __init__(self, line_number_instance):Delegator.__init__(self)self.ext &#61; line_number_instancedef 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 textlndef insert(self, *args, **kargs):passdef delete(self, *args, **kargs):pass
Step 2. 接着&#xff0c;我们要找到安装目录下的Lib\idlelib目录&#xff0c;复制LineNumber到这个目录
这里有个问题&#xff0c;就是&#xff08;至少对我来说&#xff0c;在MacOS下找安装目录不是很方便&#xff09;&#xff0c;建议的方法是&#xff0c;直接在Finder&#xff08;Finder的Macintosh HD&#xff09;下搜索idlelib,理论上会搜到两个,因为Mac会自带一个Python2的环境&#xff0c;找咱们下的Python3环境&#xff0c;我电脑上的路径长这样&#xff1a;
这个就是对应&#xff08;目前大多数Windows系统下的所在idlelib目录&#xff09;
然后就是复制LineNumber到这个目录就可以
Step 3. 再接着&#xff0c;打开LineNumber.py文件&#xff0c;把文件中的下述这三行代码
from idlelib.configHandler import idleConf
from idlelib.Delegator import Delegator
from idlelib.Percolator import Percolator
改为&#xff1a;
from idlelib.config import idleConf
from idlelib.delegator import Delegator
from idlelib.percolator import Percolator
改完记得保存下
Step 4. 之后&#xff0c;开始配置extensions.def&#xff1a;
还是在刚刚的那个idlelib目录下&#xff0c;找到config-extensions.def文件&#xff0c;往config-extensions.def文件配置如下数据&#xff1a;
[LineNumbers]
enable&#61;True
#开启扩展
enable_editor&#61;True
#开启idle编辑器支持
enable_shell&#61;True
#开启idle shell支持
visible&#61;True
#扩展可见
我添加的位置不知道规不规范&#xff0c;但是亲测可行
我加在了这里&#xff1a;如图示&#xff0c;第20-28行的位置
至此&#xff0c;配置工作结束。
重启后&#xff0c;在Options选项中有Show Line Numbers&#xff0c;点击勾选就可以拥有行号了
&#xff08;但是有两个&#xff0c;下面的那个不好使&#xff0c;不知道为什么&#xff0c;但是上面那个好使就可以了啊-- &#xff09;
至于还有其他问题详见这位大佬的博客 以及他的参考博客&#xff1a;
https://blog.csdn.net/gfs258/article/details/107535027?ops_request_misc&#61;%257B%2522request%255Fid%2522%253A%2522160173762319724836741631%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id&#61;160173762319724836741631&biz_id&#61;0&utm_medium&#61;distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v25-3-107535027.pc_search_result_cache&utm_term&#61;Python3.8&#43;IDLE行号&spm&#61;1018.2118.3001.4187