# Based on iwidgets2.2.0/scrolledtext.itk code.
import Tkinter
import Pmw
class ScrolledText(Pmw.MegaWidget):
def __init__(self, parent = None, **kw):
# Define the megawidget options.
INITOPT = Pmw.INITOPT
optiondefs = (
('labelmargin', 0, INITOPT),
('labelpos', None, INITOPT),
('scrollmargin', 2, INITOPT),
('vscrollmode', 'dynamic', self._vscrollMode),
('hscrollmode', 'dynamic', self._hscrollMode),
)
self.defineoptions(kw, optiondefs)
# Initialise the base class (after defining the options).
Pmw.MegaWidget.__init__(self, parent)
# Create the components.
interior = self.interior()
# Create the text widget.
self._textbox = self.createcomponent('text',
(), None,
Tkinter.Text, (interior,),
xscrollcommand=self._scrollTextX,
yscrollcommand=self._scrollTextY)
self._textbox.grid(row = 2, column = 2, sticky = 'news')
interior.grid_rowconfigure(2, weight = 1, minsize = 0)
interior.grid_columnconfigure(2, weight = 1, minsize = 0)
# Create the vertical scrollbar
self._vertScrollbar = self.createcomponent('vertscrollbar',
(), 'Scrollbar',
Tkinter.Scrollbar, (interior,),
orient='vertical', command=self._textbox.yview)
# Create the horizontal scrollbar
self._horizScrollbar = self.createcomponent('horizscrollbar',
(), 'Scrollbar',
Tkinter.Scrollbar, (interior,),
orient='horizontal', command=self._textbox.xview)
self.createlabel(interior, childCols = 3, childRows = 3)
# Initialise instance variables.
self._vertMode = None
self._horizMode = None
self._horizRecurse = 0
# Check keywords and initialise options.
self.initialiseoptions(ScrolledText)
# ======================================================================
# Configuration methods.
def _vscrollMode(self):
mode = self['vscrollmode']
if mode == 'static':
self._vertScrollbarDisplay(1)
elif mode == 'dynamic' or mode == 'none':
self._vertScrollbarDisplay(0)
else:
message = 'bad vscrollmode option "%s": should be static, dynamic, or none' % mode
raise ValueError, message
def _hscrollMode(self):
mode = self['hscrollmode']
if mode == 'static':
self._horizScrollbarDisplay(1)
elif mode == 'dynamic' or mode == 'none':
self._horizScrollbarDisplay(0)
else:
message = 'bad hscrollmode option "%s": should be static, dynamic, or none' % mode
raise ValueError, message
# ======================================================================
# Public methods.
def clear(self):
self._textbox.delete('1.0', 'end')
def importfile(self, fileName, where = 'end'):
file = open(fileName, 'r')
self._textbox.insert(where, file.read())
file.close()
def exportfile(self, fileName):
file = open(fileName, 'w')
file.write(self._textbox.get('1.0', 'end'))
file.close()
def settext(self, text):
disabled = (self._textbox.cget('state') == 'disabled')
if disabled:
self._textbox.configure(state='normal')
self._textbox.delete('0.0', 'end')
self._textbox.insert('end', text)
if disabled:
self._textbox.configure(state='disabled')
# Override Tkinter.Text get method, so that if it is called with
# no arguments, return all text (consistent with other widgets).
def get(self, first=None, last=None):
if not first and not last:
return self._textbox.get('1.0', 'end')
else:
return self._textbox.get(first, last)
# ======================================================================
# Private methods.
def _vertScrollbarDisplay(self, mode):
if mode != self._vertMode:
self._vertMode = mode
margin = self['scrollmargin']
interior = self.interior()
if self._vertMode:
self._vertScrollbar.grid(row = 2, column = 4, sticky = 'news')
interior.grid_columnconfigure(3, minsize = margin)
else:
self._vertScrollbar.grid_forget()
interior.grid_columnconfigure(3, minsize = 0)
def _horizScrollbarDisplay(self, mode):
if mode != self._horizMode:
self._horizMode = mode
margin = self['scrollmargin']
interior = self.interior()
if self._horizMode:
self._horizScrollbar.grid(row = 4, column = 2, sticky = 'news')
interior.grid_rowconfigure(3, minsize = margin)
else:
self._horizScrollbar.grid_forget()
interior.grid_rowconfigure(3, minsize = 0)
def _scrollTextX(self, first, last):
self._horizScrollbar.set(first, last)
# Infinite recursion must be avoided for dynamic horizontal scrollbars.
# A max depth of 1 is allowed for hiding the scrollbar, 2 for showing
# it, so that showing always 'wins'!
if self['hscrollmode'] == 'dynamic':
if first == '0' and last == '1':
if self._horizMode:
if self._horizRecurse < 2:
self._horizRecurse = self._horizRecurse + 1
self._horizScrollbarDisplay(0)
self.update_idletasks()
self._horizRecurse = self._horizRecurse - 1
else:
if not self._horizMode:
if self._horizRecurse < 3:
self._horizRecurse = self._horizRecurse + 1
self._horizScrollbarDisplay(1)
self.update_idletasks()
self._horizRecurse = self._horizRecurse - 1
def _scrollTextY(self, first, last):
# The text widget calls this just after it has been created,
# with arguments ('0', '0').
if first == '0' and last == '0':
return
self._vertScrollbar.set(first, last)
if self['vscrollmode'] == 'dynamic':
if first == '0' and last == '1':
self._vertScrollbarDisplay(0)
else:
self._vertScrollbarDisplay(1)
# Need to explicitly forward this to override the stupid
# (grid_)bbox method inherited from Tkinter.Frame.Grid.
def bbox(self, index):
return self._textbox.bbox(index)
Pmw.forwardmethods(ScrolledText, Tkinter.Text, '_textbox')