1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
|
# Based on iwidgets2.2.0/buttonbox.itk code.
import types
import Tkinter
import Pmw
class ButtonBox(Pmw.MegaWidget):
def __init__(self, parent = None, **kw):
# Define the megawidget options.
INITOPT = Pmw.INITOPT
optiondefs = (
('labelmargin', 0, INITOPT),
('labelpos', None, INITOPT),
('orient', 'horizontal', INITOPT),
('padx', 3, INITOPT),
('pady', 3, INITOPT),
)
self.defineoptions(kw, optiondefs, dynamicGroups = ('Button',))
# Initialise the base class (after defining the options).
Pmw.MegaWidget.__init__(self, parent)
# Create the components.
interior = self.interior()
if self['labelpos'] is None:
self._buttonBoxFrame = self._hull
columnOrRow = 0
else:
self._buttonBoxFrame = self.createcomponent('frame',
(), None,
Tkinter.Frame, (interior,))
self._buttonBoxFrame.grid(column=2, row=2, sticky='nsew')
columnOrRow = 2
self.createlabel(interior)
orient = self['orient']
if orient == 'horizontal':
interior.grid_columnconfigure(columnOrRow, weight = 1)
elif orient == 'vertical':
interior.grid_rowconfigure(columnOrRow, weight = 1)
else:
raise ValueError, 'bad orient option ' + repr(orient) + \
': must be either \'horizontal\' or \'vertical\''
# Initialise instance variables.
# List of tuples describing the buttons:
# - name
# - button widget
self._buttonList = []
# The index of the default button.
self._defaultButton = None
self._timerId = None
# Check keywords and initialise options.
self.initialiseoptions()
def destroy(self):
if self._timerId:
self.after_cancel(self._timerId)
self._timerId = None
Pmw.MegaWidget.destroy(self)
def numbuttons(self):
return len(self._buttonList)
def index(self, index, forInsert = 0):
listLength = len(self._buttonList)
if type(index) == types.IntType:
if forInsert and index <= listLength:
return index
elif not forInsert and index < listLength:
return index
else:
raise ValueError, 'index "%s" is out of range' % index
elif index is Pmw.END:
if forInsert:
return listLength
elif listLength > 0:
return listLength - 1
else:
raise ValueError, 'ButtonBox has no buttons'
elif index is Pmw.DEFAULT:
if self._defaultButton is not None:
return self._defaultButton
raise ValueError, 'ButtonBox has no default'
else:
names = map(lambda t: t[0], self._buttonList)
if index in names:
return names.index(index)
validValues = 'a name, a number, Pmw.END or Pmw.DEFAULT'
raise ValueError, \
'bad index "%s": must be %s' % (index, validValues)
def insert(self, componentName, beforeComponent = 0, **kw):
if componentName in self.components():
raise ValueError, 'button "%s" already exists' % componentName
if not kw.has_key('text'):
kw['text'] = componentName
kw['default'] = 'normal'
button = apply(self.createcomponent, (componentName,
(), 'Button',
Tkinter.Button, (self._buttonBoxFrame,)), kw)
index = self.index(beforeComponent, 1)
horizontal = self['orient'] == 'horizontal'
numButtons = len(self._buttonList)
# Shift buttons up one position.
for i in range(numButtons - 1, index - 1, -1):
widget = self._buttonList[i][1]
pos = i * 2 + 3
if horizontal:
widget.grid(column = pos, row = 0)
else:
widget.grid(column = 0, row = pos)
# Display the new button.
if horizontal:
button.grid(column = index * 2 + 1, row = 0, sticky = 'ew',
padx = self['padx'], pady = self['pady'])
self._buttonBoxFrame.grid_columnconfigure(
numButtons * 2 + 2, weight = 1)
else:
button.grid(column = 0, row = index * 2 + 1, sticky = 'ew',
padx = self['padx'], pady = self['pady'])
self._buttonBoxFrame.grid_rowconfigure(
numButtons * 2 + 2, weight = 1)
self._buttonList.insert(index, (componentName, button))
return button
def add(self, componentName, **kw):
return apply(self.insert, (componentName, len(self._buttonList)), kw)
def delete(self, index):
index = self.index(index)
(name, widget) = self._buttonList[index]
widget.grid_forget()
self.destroycomponent(name)
numButtons = len(self._buttonList)
# Shift buttons down one position.
horizontal = self['orient'] == 'horizontal'
for i in range(index + 1, numButtons):
widget = self._buttonList[i][1]
pos = i * 2 - 1
if horizontal:
widget.grid(column = pos, row = 0)
else:
widget.grid(column = 0, row = pos)
if horizontal:
self._buttonBoxFrame.grid_columnconfigure(numButtons * 2 - 1,
minsize = 0)
self._buttonBoxFrame.grid_columnconfigure(numButtons * 2, weight = 0)
else:
self._buttonBoxFrame.grid_rowconfigure(numButtons * 2, weight = 0)
del self._buttonList[index]
def setdefault(self, index):
# Turn off the default ring around the current default button.
if self._defaultButton is not None:
button = self._buttonList[self._defaultButton][1]
button.configure(default = 'normal')
self._defaultButton = None
# Turn on the default ring around the new default button.
if index is not None:
index = self.index(index)
self._defaultButton = index
button = self._buttonList[index][1]
button.configure(default = 'active')
def invoke(self, index = Pmw.DEFAULT, noFlash = 0):
# Invoke the callback associated with the *index* button. If
# *noFlash* is not set, flash the button to indicate to the
# user that something happened.
button = self._buttonList[self.index(index)][1]
if not noFlash:
state = button.cget('state')
relief = button.cget('relief')
button.configure(state = 'active', relief = 'sunken')
self.update_idletasks()
self.after(100)
button.configure(state = state, relief = relief)
return button.invoke()
def button(self, buttonIndex):
return self._buttonList[self.index(buttonIndex)][1]
def alignbuttons(self, when = 'later'):
if when == 'later':
if not self._timerId:
self._timerId = self.after_idle(self.alignbuttons, 'now')
return
self.update_idletasks()
self._timerId = None
# Determine the width of the maximum length button.
max = 0
horizontal = (self['orient'] == 'horizontal')
for index in range(len(self._buttonList)):
gridIndex = index * 2 + 1
if horizontal:
width = self._buttonBoxFrame.grid_bbox(gridIndex, 0)[2]
else:
width = self._buttonBoxFrame.grid_bbox(0, gridIndex)[2]
if width > max:
max = width
# Set the width of all the buttons to be the same.
if horizontal:
for index in range(len(self._buttonList)):
self._buttonBoxFrame.grid_columnconfigure(index * 2 + 1,
minsize = max)
else:
self._buttonBoxFrame.grid_columnconfigure(0, minsize = max)
|