tkinter.Canvas
行番号用に追加されたテキストエディタを作成しました。tkinter.Text
ウィジェットtkinter.Canvas
はの中にありtkinter.Frame
、そのフレームはtkinter.ttk.Notebook
タブに追加されていました。追加しようとした[ノートブック]タブから切り取ったコードは次のとおりです。
from tkinter import *
import tkinter as tk
class LineNumberCanvas(Canvas):
def __init__(self, *args, **kwargs):
Canvas.__init__(self, *args, **kwargs)
self.text_widget = None
self.breakpoints = []
def connect(self, text_widget):
self.text_widget = text_widget
def re_render(self):
"""Re-render the line canvas"""
self.delete('all') # To prevent drawing over the previous canvas
temp = self.text_widget.index("@0, 0")
while True :
dline= self.text_widget.dlineinfo(temp)
if dline is None:
break
y = dline[1]
x = dline[0]
linenum = str(temp).split(".")[0]
id = self.create_text(2, y, anchor="nw", text=linenum, font='Consolas 13')
if int(linenum) in self.breakpoints:
x1, y1, x2, y2 = self.bbox(id)
self.create_oval(x1, y1, x2, y2, fill='red')
self.tag_raise(id)
temp = self.text_widget.index("%s+1line" % temp)
def get_breakpoint_number(self,event):
if self.find_withtag('current'):
i = self.find_withtag('current')[0]
linenum = int(self.itemcget(i,'text'))
if linenum in self.breakpoints:
self.breakpoints.remove(linenum)
else:
self.breakpoints.append(linenum)
self.re_render()
class CustomText:
def __init__(self, text):
self.text = text
self.master = text.master
self.mechanise()
self._set_()
self.binding_keys()
def mechanise(self):
self.text.tk.eval('''
proc widget_interceptor {widget command args} {
set orig_call [uplevel [linsert $args 0 $command]]
if {
([lindex $args 0] == "insert") ||
([lindex $args 0] == "delete") ||
([lindex $args 0] == "replace") ||
([lrange $args 0 2] == {mark set insert}) ||
([lrange $args 0 1] == {xview moveto}) ||
([lrange $args 0 1] == {xview scroll}) ||
([lrange $args 0 1] == {yview moveto}) ||
([lrange $args 0 1] == {yview scroll})} {
event generate $widget <<Changed>>
}
#return original command
return $orig_call
}
''')
self.text.tk.eval('''
rename {widget} new
interp alias {{}} ::{widget} {{}} widget_interceptor {widget} new
'''.format(widget=str(self.text)))
return
def binding_keys(self):
for key in ['<Down>', '<Up>', "<<Changed>>", "<Configure>"]:
self.text.bind(key, self.changed)
self.linenumbers.bind('<Button-1>', self.linenumbers.get_breakpoint_number)
return
def changed(self, event):
self.linenumbers.re_render()
#print "render"
return
def _set_(self):
self.linenumbers = LineNumberCanvas(self.master, width=30)
self.linenumbers.connect(self.text)
self.linenumbers.pack(side="left", fill="y")
return
if __name__ == '__main__':
root = Tk()
l = Text(root, font='Consolas 13')
CustomText(l)
l.pack(expand=TRUE, fill=BOTH)
root.mainloop()
ここでの問題は、tcl言語がわからないことと、プログラムが生成するエラーがCustomTextクラスのmechanise関数にあり、「new」キーワードがあることです。それは言う:
File "C:\Users\Prerak\AppData\Local\Programs\Python\Python37\EZ_PY\ColorText.py", line 590, in mechanise
'''.format(widget=str(self)))
_tkinter.TclError: can't rename to "new": command already exists
誰かplsがこれを解決するのを手伝ってくれますか...そして私がしているのは、CustomTextオブジェクトがtkinter.Notebookタブに追加されているボタンをクリックした後に新しいタブを追加することだけです。
問題はそれが何であるかということです:Tclインタープリターにはすでに。というコマンドがありnew
ます。これは基本のTclコマンドセットの一部ではないため、デフォルトでロードされているパッケージからのものである可能性があります。それが何であれ、それがあなたのものでない場合は、おそらくそのままにしておく必要があります。そうしないと、何か他のものが壊れてしまいます。
これを処理する最も簡単な方法は、一意のカウンターを使用して、インターセプトされたすべてのウィジェットが一意のものを取得することです(これはgensym
Lispで行うことと類似しています)。この問題はTcl側で発生するため、そのカウンターをその側に保持できますinstall_widget_interceptor
。これを行う便利な方法には、2番目の手順を作成することが含まれます。これをと呼びます。ボーナスとして、それを利用するための呼び出しがより簡単になりCustomText
、一度に2つのインスタンスを持つことができるようになります。
(…変更されないコードを省略し、widget_interceptor
手順をもう少し慣用的にするように整理しました…)
# You probably shouldn't repeat this bit every time you create a widget
self.text.tk.eval('''
proc widget_interceptor {widget command args} {
set orig_call [uplevel 1 [linsert $args 0 $command]]
if {
[lindex $args 0] in {insert delete replace} ||
([lrange $args 0 2] == {mark set insert}) ||
([lrange $args 0 1] == {xview moveto}) ||
([lrange $args 0 1] == {xview scroll}) ||
([lrange $args 0 1] == {yview moveto}) ||
([lrange $args 0 1] == {yview scroll})
} then {
event generate $widget <<Changed>>
}
#return original command
return $orig_call
}
proc install_widget_interceptor {widget} {
global unique_widget_id
set handle ::_intercepted_widget_[incr unique_widget_id]
rename $widget $handle
interp alias {} ::$widget {} widget_interceptor $widget $handle
}
''')
# This bit you absolutely need each time
self.text.tk.eval('''
install_widget_interceptor {widget}
'''.format(widget=str(self.text)))
コードに記載されているように、Tcl側でのプロシージャの作成は、Pythonクラスの作成時に1回だけ実行する必要があります。毎回それを行うことは重要ではありません。ただ無駄です。
また、Tk自体は<<Modified>>
、テキストウィジェットが変更されると、それらのイベントを生成します。モデルのビューではなく、管理するモデルへの変更に焦点を当てて、重要なものの異なる感覚を使用します(したがって、カーソルを移動したりスクロールしたりしてもトリガーされません)。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加