Home | Trees | Indices | Help |
|
---|
|
1 # Natural Language Toolkit: graphical representations package 2 # 3 # Copyright (C) 2001-2008 NLTK Project 4 # Author: Edward Loper <[email protected]> 5 # URL: <http://nltk.org> 6 # For license information, see LICENSE.TXT 7 # 8 # $Id: __init__.py 6339 2008-07-30 01:54:47Z stevenbird $ 9 10 """ 11 Tools for graphically displaying and interacting with the objects and 12 processing classes defined by the Toolkit. These tools are primarily 13 intended to help students visualize the objects that they create. 14 15 The graphical tools are typically built using X{canvas widgets}, each 16 of which encapsulates the graphical elements and bindings used to 17 display a complex object on a Tkinter C{Canvas}. For example, NLTK 18 defines canvas widgets for displaying trees and directed graphs, as 19 well as a number of simpler widgets. These canvas widgets make it 20 easier to build new graphical tools and demos. See the class 21 documentation for L{CanvasWidget} for more information. 22 23 The C{nltk.draw} module defines the abstract C{CanvasWidget} base 24 class, and a number of simple canvas widgets. The remaining canvas 25 widgets are defined by submodules, such as L{nltk.draw.tree}. 26 27 The C{nltk.draw} module also defines L{CanvasFrame}, which 28 encapsulates a C{Canvas} and its scrollbars. It uses a 29 L{ScrollWatcherWidget} to ensure that all canvas widgets contained on 30 its canvas are within the scroll region. 31 32 Acknowledgements: Many of the ideas behind the canvas widget system 33 are derived from C{CLIG}, a Tk-based grapher for linguistic data 34 structures. For more information, see U{the CLIG 35 homepage<http://www.ags.uni-sb.de/~konrad/clig.html>}. 36 37 @group Graphical Demonstrations: rdparser, srparser, chart 38 @group Widgets: tree, cfg, plot 39 @group Abstract Widget Superclasses: CanvasWidget, AbstractContainerWidget 40 @sort: CanvasWidget, AbstractContainerWidget 41 @group Canvas Widgets: BoxWidget, BracketWidget, OvalWidget, ParenWidget, 42 ScrollWatcherWidget, SequenceWidget, SpaceWidget, StackWidget, 43 SymbolWidget, TextWidget 44 @sort: TextWidget, SymbolWidget, BoxWidget, OvalWidget, ParenWidget, 45 BracketWidget, SequenceWidget, StackWidget, SpaceWidget, 46 ScrollWatcherWidget 47 @group Tkinter Widgets: CanvasFrame, EntryDialog, ShowText 48 """ 49 from Tkinter import * 50 51 ##////////////////////////////////////////////////////// 52 ## CanvasWidget 53 ##////////////////////////////////////////////////////// 5456 """ 57 A collection of graphical elements and bindings used to display a 58 complex object on a Tkinter C{Canvas}. A canvas widget is 59 responsible for managing the C{Canvas} tags and callback bindings 60 necessary to display and interact with the object. Canvas widgets 61 are often organized into hierarchies, where parent canvas widgets 62 control aspects of their child widgets. 63 64 Each canvas widget is bound to a single C{Canvas}. This C{Canvas} 65 is specified as the first argument to the C{CanvasWidget}'s 66 constructor. 67 68 Attributes 69 ========== 70 Each canvas widget can support a variety of X{attributes}, which 71 control how the canvas widget is displayed. Some typical examples 72 attributes are C{color}, C{font}, and C{radius}. Each attribute 73 has a default value. This default value can be overridden in the 74 constructor, using keyword arguments of the form 75 C{attribute=value}: 76 77 >>> cn = CanvasText(c, 'test', color='red') 78 79 Attribute values can also be changed after a canvas widget has 80 been constructed, using the C{__setitem__} operator: 81 82 >>> cn['font'] = 'times' 83 84 The current value of an attribute value can be queried using the 85 C{__getitem__} operator: 86 87 >>> cn['color'] 88 red 89 90 For a list of the attributes supported by a type of canvas widget, 91 see its class documentation. 92 93 Interaction 94 =========== 95 The attribute C{'draggable'} controls whether the user can drag a 96 canvas widget around the canvas. By default, canvas widgets 97 are not draggable. 98 99 C{CanvasWidget} provides callback support for two types of user 100 interaction: clicking and dragging. The method C{bind_click} 101 registers a callback function that is called whenever the canvas 102 widget is clicked. The method C{bind_drag} registers a callback 103 function that is called after the canvas widget is dragged. If 104 the user clicks or drags a canvas widget with no registered 105 callback function, then the interaction event will propagate to 106 its parent. For each canvas widget, only one callback function 107 may be registered for an interaction event. Callback functions 108 can be deregistered with the C{unbind_click} and C{unbind_drag} 109 methods. 110 111 Subclassing 112 =========== 113 C{CanvasWidget} is an abstract class. Subclasses are required to 114 implement the following methods: 115 116 - C{__init__}: Builds a new canvas widget. It must perform the 117 following three tasks (in order): 118 - Create any new graphical elements. 119 - Call C{_add_child_widget} on each child widget. 120 - Call the C{CanvasWidget} constructor. 121 - C{_tags}: Returns a list of the canvas tags for all graphical 122 elements managed by this canvas widget, not including 123 graphical elements managed by its child widgets. 124 - C{_manage}: Arranges the child widgets of this canvas widget. 125 This is typically only called when the canvas widget is 126 created. 127 - C{_update}: Update this canvas widget in response to a 128 change in a single child. 129 130 For C{CanvasWidget}s with no child widgets, the default 131 definitions for C{_manage} and C{_update} may be used. 132 133 If a subclass defines any attributes, then it should implement 134 C{__getitem__} and C{__setitem__}. If either of these methods is 135 called with an unknown attribute, then they should propagate the 136 request to C{CanvasWidget}. 137 138 Most subclasses implement a number of additional methods that 139 modify the C{CanvasWidget} in some way. These methods must call 140 C{parent.update(self)} after making any changes to the canvas 141 widget's graphical elements. The canvas widget must also call 142 C{parent.update(self)} after changing any attribute value that 143 affects the shape or position of the canvas widget's graphical 144 elements. 145 146 @type __canvas: C{Tkinter.Canvas} 147 @ivar __canvas: This C{CanvasWidget}'s canvas. 148 149 @type __parent: C{CanvasWidget} or C{None} 150 @ivar __parent: This C{CanvasWidget}'s hierarchical parent widget. 151 @type __children: C{list} of C{CanvasWidget} 152 @ivar __children: This C{CanvasWidget}'s hierarchical child widgets. 153 154 @type __updating: C{boolean} 155 @ivar __updating: Is this canvas widget currently performing an 156 update? If it is, then it will ignore any new update requests 157 from child widgets. 158 159 @type __draggable: C{boolean} 160 @ivar __draggable: Is this canvas widget draggable? 161 @type __press: C{event} 162 @ivar __press: The ButtonPress event that we're currently handling. 163 @type __drag_x: C{int} 164 @ivar __drag_x: Where it's been moved to (to find dx) 165 @type __drag_y: C{int} 166 @ivar __drag_y: Where it's been moved to (to find dy) 167 @type __callbacks: C{dictionary} 168 @ivar __callbacks: Registered callbacks. Currently, four keys are 169 used: C{1}, C{2}, C{3}, and C{'drag'}. The values are 170 callback functions. Each callback function takes a single 171 argument, which is the C{CanvasWidget} that triggered the 172 callback. 173 """708 709 ##////////////////////////////////////////////////////// 710 ## Basic widgets. 711 ##////////////////////////////////////////////////////// 712175 """ 176 Create a new canvas widget. This constructor should only be 177 called by subclass constructors; and it should be called only 178 X{after} the subclass has constructed all graphical canvas 179 objects and registered all child widgets. 180 181 @param canvas: This canvas widget's canvas. 182 @type canvas: C{Tkinter.Canvas} 183 @param parent: This canvas widget's hierarchical parent. 184 @type parent: C{CanvasWidget} 185 @param attribs: The new canvas widget's attributes. 186 """ 187 if self.__class__ == CanvasWidget: 188 raise TypeError, 'CanvasWidget is an abstract base class' 189 190 if not isinstance(canvas, Canvas): 191 raise TypeError('Expected a canvas!') 192 193 self.__canvas = canvas 194 self.__parent = parent 195 196 # If the subclass constructor called _add_child_widget, then 197 # self.__children will already exist. 198 if not hasattr(self, '_CanvasWidget__children'): self.__children = [] 199 200 # Is this widget hidden? 201 self.__hidden = 0 202 203 # Update control (prevents infinite loops) 204 self.__updating = 0 205 206 # Button-press and drag callback handling. 207 self.__press = None 208 self.__drag_x = self.__drag_y = 0 209 self.__callbacks = {} 210 self.__draggable = 0 211 212 # Set up attributes. 213 for (attr, value) in attribs.items(): self[attr] = value 214 215 # Manage this canvas widget 216 self._manage() 217 218 # Register any new bindings 219 for tag in self._tags(): 220 self.__canvas.tag_bind(tag, '<ButtonPress-1>', 221 self.__press_cb) 222 self.__canvas.tag_bind(tag, '<ButtonPress-2>', 223 self.__press_cb) 224 self.__canvas.tag_bind(tag, '<ButtonPress-3>', 225 self.__press_cb)226 227 ##////////////////////////////////////////////////////// 228 ## Inherited methods. 229 ##////////////////////////////////////////////////////// 230232 """ 233 @return: A bounding box for this C{CanvasWidget}. The bounding 234 box is a tuple of four coordinates, M{(xmin, ymin, xmax, 235 ymax)}, for a rectangle which encloses all of the canvas 236 widget's graphical elements. Bounding box coordinates are 237 specified with respect to the C{Canvas}'s coordinate 238 space. 239 @rtype: C{4-tuple} of C{int}s 240 """ 241 if self.__hidden: return (0,0,0,0) 242 if len(self.tags()) == 0: raise ValueError('No tags') 243 return self.__canvas.bbox(*self.tags())244246 """ 247 @return: The width of this canvas widget's bounding box, in 248 its C{Canvas}'s coordinate space. 249 @rtype: C{int} 250 """ 251 if len(self.tags()) == 0: raise ValueError('No tags') 252 bbox = self.__canvas.bbox(*self.tags()) 253 return bbox[2]-bbox[0]254256 """ 257 @return: The height of this canvas widget's bounding box, in 258 its C{Canvas}'s coordinate space. 259 @rtype: C{int} 260 """ 261 if len(self.tags()) == 0: raise ValueError('No tags') 262 bbox = self.__canvas.bbox(*self.tags()) 263 return bbox[3]-bbox[1]264266 """ 267 @return: The hierarchical parent of this canvas widget. 268 C{self} is considered a subpart of its parent for 269 purposes of user interaction. 270 @rtype: C{CanvasWidget} or C{None} 271 """ 272 return self.__parent273275 """ 276 @return: A list of the hierarchical children of this canvas 277 widget. These children are considered part of C{self} 278 for purposes of user interaction. 279 @rtype: C{list} of C{CanvasWidget} 280 """ 281 return self.__children282284 """ 285 @return: The canvas that this canvas widget is bound to. 286 @rtype: C{Tkinter.Canvas} 287 """ 288 return self.__canvas289291 """ 292 Move this canvas widget by a given distance. In particular, 293 shift the canvas widget right by C{dx} pixels, and down by 294 C{dy} pixels. Both C{dx} and C{dy} may be negative, resulting 295 in leftward or upward movement. 296 297 @type dx: C{int} 298 @param dx: The number of pixels to move this canvas widget 299 rightwards. 300 @type dy: C{int} 301 @param dy: The number of pixels to move this canvas widget 302 downwards. 303 @rtype: C{None} 304 """ 305 if dx == dy == 0: return 306 for tag in self.tags(): 307 self.__canvas.move(tag, dx, dy) 308 if self.__parent: self.__parent.update(self)309311 """ 312 Move this canvas widget to the given location. In particular, 313 shift the canvas widget such that the corner or side of the 314 bounding box specified by C{anchor} is at location (C{x}, 315 C{y}). 316 317 @param x,y: The location that the canvas widget should be moved 318 to. 319 @param anchor: The corner or side of the canvas widget that 320 should be moved to the specified location. C{'N'} 321 specifies the top center; C{'NE'} specifies the top right 322 corner; etc. 323 """ 324 x1,y1,x2,y2 = self.bbox() 325 if anchor == 'NW': self.move(x-x1, y-y1) 326 if anchor == 'N': self.move(x-x1/2-x2/2, y-y1) 327 if anchor == 'NE': self.move(x-x2, y-y1) 328 if anchor == 'E': self.move(x-x2, y-y1/2-y2/2) 329 if anchor == 'SE': self.move(x-x2, y-y2) 330 if anchor == 'S': self.move(x-x1/2-x2/2, y-y2) 331 if anchor == 'SW': self.move(x-x1, y-y2) 332 if anchor == 'W': self.move(x-x1, y-y1/2-y2/2)333335 """ 336 Remove this C{CanvasWidget} from its C{Canvas}. After a 337 C{CanvasWidget} has been destroyed, it should not be accessed. 338 339 Note that you only need to destroy a top-level 340 C{CanvasWidget}; its child widgets will be destroyed 341 automatically. If you destroy a non-top-level 342 C{CanvasWidget}, then the entire top-level widget will be 343 destroyed. 344 345 @raise ValueError: if this C{CanvasWidget} has a parent. 346 @rtype: C{None} 347 """ 348 if self.__parent is not None: 349 self.__parent.destroy() 350 return 351 352 for tag in self.tags(): 353 self.__canvas.tag_unbind(tag, '<ButtonPress-1>') 354 self.__canvas.tag_unbind(tag, '<ButtonPress-2>') 355 self.__canvas.tag_unbind(tag, '<ButtonPress-3>') 356 self.__canvas.delete(*self.tags()) 357 self.__canvas = None358360 """ 361 Update the graphical display of this canvas widget, and all of 362 its ancestors, in response to a change in one of this canvas 363 widget's children. 364 365 @param child: The child widget that changed. 366 @type child: C{CanvasWidget} 367 """ 368 if self.__hidden or child.__hidden: return 369 # If we're already updating, then do nothing. This prevents 370 # infinite loops when _update modifies its children. 371 if self.__updating: return 372 self.__updating = 1 373 374 # Update this CanvasWidget. 375 self._update(child) 376 377 # Propagate update request to the parent. 378 if self.__parent: self.__parent.update(self) 379 380 # We're done updating. 381 self.__updating = 0382384 """ 385 Arrange this canvas widget and all of its descendants. 386 387 @rtype: C{None} 388 """ 389 if self.__hidden: return 390 for child in self.__children: child.manage() 391 self._manage()392 407409 """ 410 Set the value of the attribute C{attr} to C{value}. See the 411 class documentation for a list of attributes supported by this 412 canvas widget. 413 414 @rtype: C{None} 415 """ 416 if attr == 'draggable': 417 self.__draggable = value 418 else: 419 raise ValueError('Unknown attribute %r' % attr)420422 """ 423 @return: the value of the attribute C{attr}. See the class 424 documentation for a list of attributes supported by this 425 canvas widget. 426 @rtype: (any) 427 """ 428 if attr == 'draggable': 429 return self.__draggable 430 else: 431 raise ValueError('Unknown attribute %r' % attr)432434 """ 435 @return: a string representation of this canvas widget. 436 @rtype: C{string} 437 """ 438 return '<%s>' % self.__class__.__name__439441 """ 442 Temporarily hide this canvas widget. 443 444 @rtype: C{None} 445 """ 446 self.__hidden = 1 447 for tag in self.tags(): 448 self.__canvas.itemconfig(tag, state='hidden')449451 """ 452 Show a hidden canvas widget. 453 454 @rtype: C{None} 455 """ 456 self.__hidden = 0 457 for tag in self.tags(): 458 self.__canvas.itemconfig(tag, state='normal')459 466 467 ##////////////////////////////////////////////////////// 468 ## Callback interface 469 ##////////////////////////////////////////////////////// 470472 """ 473 Register a new callback that will be called whenever this 474 C{CanvasWidget} is clicked on. 475 476 @type callback: C{function} 477 @param callback: The callback function that will be called 478 whenever this C{CanvasWidget} is clicked. This function 479 will be called with this C{CanvasWidget} as its argument. 480 @type button: C{int} 481 @param button: Which button the user should use to click on 482 this C{CanvasWidget}. Typically, this should be 1 (left 483 button), 3 (right button), or 2 (middle button). 484 """ 485 self.__callbacks[button] = callback486488 """ 489 Register a new callback that will be called after this 490 C{CanvasWidget} is dragged. This implicitly makes this 491 C{CanvasWidget} draggable. 492 493 @type callback: C{function} 494 @param callback: The callback function that will be called 495 whenever this C{CanvasWidget} is clicked. This function 496 will be called with this C{CanvasWidget} as its argument. 497 """ 498 self.__draggable = 1 499 self.__callbacks['drag'] = callback500502 """ 503 Remove a callback that was registered with C{bind_click}. 504 505 @type button: C{int} 506 @param button: Which button the user should use to click on 507 this C{CanvasWidget}. Typically, this should be 1 (left 508 button), 3 (right button), or 2 (middle button). 509 """ 510 try: del self.__callbacks[button] 511 except: pass512514 """ 515 Remove a callback that was registered with C{bind_drag}. 516 """ 517 try: del self.__callbacks['drag'] 518 except: pass519 520 ##////////////////////////////////////////////////////// 521 ## Callback internals 522 ##////////////////////////////////////////////////////// 523525 """ 526 Handle a button-press event: 527 - record the button press event in C{self.__press} 528 - register a button-release callback. 529 - if this CanvasWidget or any of its ancestors are 530 draggable, then register the appropriate motion callback. 531 """ 532 # If we're already waiting for a button release, then ignore 533 # this new button press. 534 if (self.__canvas.bind('<ButtonRelease-1>') or 535 self.__canvas.bind('<ButtonRelease-2>') or 536 self.__canvas.bind('<ButtonRelease-3>')): 537 return 538 539 # Unbind motion (just in case; this shouldn't be necessary) 540 self.__canvas.unbind('<Motion>') 541 542 # Record the button press event. 543 self.__press = event 544 545 # If any ancestor is draggable, set up a motion callback. 546 # (Only if they pressed button number 1) 547 if event.num == 1: 548 widget = self 549 while widget is not None: 550 if widget['draggable']: 551 widget.__start_drag(event) 552 break 553 widget = widget.parent() 554 555 # Set up the button release callback. 556 self.__canvas.bind('<ButtonRelease-%d>' % event.num, 557 self.__release_cb)558560 """ 561 Begin dragging this object: 562 - register a motion callback 563 - record the drag coordinates 564 """ 565 self.__canvas.bind('<Motion>', self.__motion_cb) 566 self.__drag_x = event.x 567 self.__drag_y = event.y568570 """ 571 Handle a motion event: 572 - move this object to the new location 573 - record the new drag coordinates 574 """ 575 self.move(event.x-self.__drag_x, event.y-self.__drag_y) 576 self.__drag_x = event.x 577 self.__drag_y = event.y578580 """ 581 Handle a release callback: 582 - unregister motion & button release callbacks. 583 - decide whether they clicked, dragged, or cancelled 584 - call the appropriate handler. 585 """ 586 # Unbind the button release & motion callbacks. 587 self.__canvas.unbind('<ButtonRelease-%d>' % event.num) 588 self.__canvas.unbind('<Motion>') 589 590 # Is it a click or a drag? 591 if (event.time - self.__press.time < 100 and 592 abs(event.x-self.__press.x) + abs(event.y-self.__press.y) < 5): 593 # Move it back, if we were dragging. 594 if self.__draggable and event.num == 1: 595 self.move(self.__press.x - self.__drag_x, 596 self.__press.y - self.__drag_y) 597 self.__click(event.num) 598 elif event.num == 1: 599 self.__drag() 600 601 self.__press = None602604 """ 605 If this C{CanvasWidget} has a drag callback, then call it; 606 otherwise, find the closest ancestor with a drag callback, and 607 call it. If no ancestors have a drag callback, do nothing. 608 """ 609 if self.__draggable: 610 if self.__callbacks.has_key('drag'): 611 cb = self.__callbacks['drag'] 612 try: 613 cb(self) 614 except: 615 print 'Error in drag callback for %r' % self 616 elif self.__parent is not None: 617 self.__parent.__drag()618620 """ 621 If this C{CanvasWidget} has a drag callback, then call it; 622 otherwise, find the closest ancestor with a click callback, and 623 call it. If no ancestors have a click callback, do nothing. 624 """ 625 if self.__callbacks.has_key(button): 626 cb = self.__callbacks[button] 627 #try: 628 cb(self) 629 #except: 630 # print 'Error in click callback for %r' % self 631 # raise 632 elif self.__parent is not None: 633 self.__parent.__click(button)634 635 ##////////////////////////////////////////////////////// 636 ## Child/parent Handling 637 ##////////////////////////////////////////////////////// 638640 """ 641 Register a hierarchical child widget. The child will be 642 considered part of this canvas widget for purposes of user 643 interaction. C{_add_child_widget} has two direct effects: 644 - It sets C{child}'s parent to this canvas widget. 645 - It adds C{child} to the list of canvas widgets returned by 646 the C{child_widgets} member function. 647 648 @param child: The new child widget. C{child} must not already 649 have a parent. 650 @type child: C{CanvasWidget} 651 """ 652 if not hasattr(self, '_CanvasWidget__children'): self.__children = [] 653 if child.__parent is not None: 654 raise ValueError('%s already has a parent', child) 655 child.__parent = self 656 self.__children.append(child)657659 """ 660 Remove a hierarchical child widget. This child will no longer 661 be considered part of this canvas widget for purposes of user 662 interaction. C{_add_child_widget} has two direct effects: 663 - It sets C{child}'s parent to C{None}. 664 - It removes C{child} from the list of canvas widgets 665 returned by the C{child_widgets} member function. 666 667 @param child: The child widget to remove. C{child} must be a 668 child of this canvas widget. 669 @type child: C{CanvasWidget} 670 """ 671 self.__children.remove(child) 672 child.__parent = None673 674 ##////////////////////////////////////////////////////// 675 ## Defined by subclass 676 ##////////////////////////////////////////////////////// 677 686688 """ 689 Arrange the child widgets of this canvas widget. This method 690 is called when the canvas widget is initially created. It is 691 also called if the user calls the C{manage} method on this 692 canvas widget or any of its ancestors. 693 694 @rtype: C{None} 695 """ 696 pass697714 """ 715 A canvas widget that displays a single string of text. 716 717 Attributes: 718 - C{color}: the color of the text. 719 - C{font}: the font used to display the text. 720 - C{justify}: justification for multi-line texts. Valid values 721 are C{left}, C{center}, and C{right}. 722 - C{width}: the width of the text. If the text is wider than 723 this width, it will be line-wrapped at whitespace. 724 - C{draggable}: whether the text can be dragged by the user. 725 """779727 """ 728 Create a new text widget. 729 730 @type canvas: C{Tkinter.Canvas} 731 @param canvas: This canvas widget's canvas. 732 @type text: C{string} 733 @param text: The string of text to display. 734 @param attribs: The new canvas widget's attributes. 735 """ 736 self._text = text 737 self._tag = canvas.create_text(1, 1, text=text) 738 CanvasWidget.__init__(self, canvas, **attribs)739741 if attr in ('color', 'font', 'justify', 'width'): 742 if attr == 'color': attr = 'fill' 743 self.canvas().itemconfig(self._tag, {attr:value}) 744 else: 745 CanvasWidget.__setitem__(self, attr, value)746748 if attr == 'width': 749 return int(self.canvas().itemcget(self._tag, attr)) 750 elif attr in ('color', 'font', 'justify'): 751 if attr == 'color': attr = 'fill' 752 return self.canvas().itemcget(self._tag, attr) 753 else: 754 return CanvasWidget.__getitem__(self, attr)755 757759 """ 760 @return: The text displayed by this text widget. 761 @rtype: C{string} 762 """ 763 return self.canvas().itemcget(self._tag, 'TEXT')764766 """ 767 Change the text that is displayed by this text widget. 768 769 @type text: C{string} 770 @param text: The string of text to display. 771 @rtype: C{None} 772 """ 773 self.canvas().itemconfig(self._tag, text=text) 774 if self.parent() is not None: 775 self.parent().update(self)776781 """ 782 A canvas widget that displays special symbols, such as the 783 negation sign and the exists operator. Symbols are specified by 784 name. Currently, the following symbol names are defined: C{neg}, 785 C{disj}, C{conj}, C{lambda}, C{merge}, C{forall}, C{exists}, 786 C{subseteq}, C{subset}, C{notsubset}, C{emptyset}, C{imp}, 787 C{rightarrow}, C{equal}, C{notequal}, C{epsilon}. 788 789 Attributes: 790 - C{color}: the color of the text. 791 - C{draggable}: whether the text can be dragged by the user. 792 793 @cvar SYMBOLS: A dictionary mapping from symbols to the character 794 in the C{symbol} font used to render them. 795 """ 796 SYMBOLS = {'neg':'\330', 'disj':'\332', 'conj': '\331', 797 'lambda': '\154', 'merge': '\304', 798 'forall': '\042', 'exists': '\044', 799 'subseteq': '\315', 'subset': '\314', 800 'notsubset': '\313', 'emptyset': '\306', 801 'imp': '\336', 'rightarrow': chr(222), #'\256', 802 'equal': '\75', 'notequal': '\271', 803 'intersection': '\307', 'union': '\310', 804 'epsilon': 'e', 805 } 806872 873808 """ 809 Create a new symbol widget. 810 811 @type canvas: C{Tkinter.Canvas} 812 @param canvas: This canvas widget's canvas. 813 @type symbol: C{string} 814 @param symbol: The name of the symbol to display. 815 @param attribs: The new canvas widget's attributes. 816 """ 817 attribs['font'] = 'symbol' 818 TextWidget.__init__(self, canvas, '', **attribs) 819 self.set_symbol(symbol)820822 """ 823 @return: the name of the symbol that is displayed by this 824 symbol widget. 825 @rtype: C{string} 826 """ 827 return self._symbol828830 """ 831 Change the symbol that is displayed by this symbol widget. 832 833 @type symbol: C{string} 834 @param symbol: The name of the symbol to display. 835 """ 836 if not SymbolWidget.SYMBOLS.has_key(symbol): 837 raise ValueError('Unknown symbol: %s' % symbol) 838 self._symbol = symbol 839 self.set_text(SymbolWidget.SYMBOLS[symbol])840 843 844 # A staticmethod that displays all symbols.846 """ 847 Open a new Tkinter window that displays the entire alphabet 848 for the symbol font. This is useful for constructing the 849 L{SymbolWidget.SYMBOLS} dictionary. 850 """ 851 top = Tk() 852 def destroy(e, top=top): top.destroy() 853 top.bind('q', destroy) 854 Button(top, text='Quit', command=top.destroy).pack(side='bottom') 855 text = Text(top, font=('helvetica', -size), width=20, height=30) 856 text.pack(side='left') 857 sb=Scrollbar(top, command=text.yview) 858 text['yscrollcommand']=sb.set 859 sb.pack(side='right', fill='y') 860 text.tag_config('symbol', font=('symbol', -size)) 861 for i in range(256): 862 if i in (0,10): continue # null and newline 863 for k,v in SymbolWidget.SYMBOLS.items(): 864 if v == chr(i): 865 text.insert('end', '%-10s\t' % k) 866 break 867 else: 868 text.insert('end', '%-10d \t' % i) 869 text.insert('end', '[%s]\n' % chr(i), 'symbol') 870 top.mainloop()871 symbolsheet = staticmethod(symbolsheet)875 """ 876 An abstract class for canvas widgets that contain a single child, 877 such as C{BoxWidget} and C{OvalWidget}. Subclasses must define 878 a constructor, which should create any new graphical elements and 879 then call the C{AbstractCanvasContainer} constructor. Subclasses 880 must also define the C{_update} method and the C{_tags} method; 881 and any subclasses that define attributes should define 882 C{__setitem__} and C{__getitem__}. 883 """928885 """ 886 Create a new container widget. This constructor should only 887 be called by subclass constructors. 888 889 @type canvas: C{Tkinter.Canvas} 890 @param canvas: This canvas widget's canvas. 891 @param child: The container's child widget. C{child} must not 892 have a parent. 893 @type child: C{CanvasWidget} 894 @param attribs: The new canvas widget's attributes. 895 """ 896 self._child = child 897 self._add_child_widget(child) 898 CanvasWidget.__init__(self, canvas, **attribs)899901 self._update(self._child)902904 """ 905 @return: The child widget contained by this container widget. 906 @rtype: C{CanvasWidget} 907 """ 908 return self._child909911 """ 912 Change the child widget contained by this container widget. 913 914 @param child: The new child widget. C{child} must not have a 915 parent. 916 @type child: C{CanvasWidget} 917 @rtype: C{None} 918 """ 919 self._remove_child_widget(self._child) 920 self._add_child_widget(child) 921 self._child = child 922 self.update(child)923930 """ 931 A canvas widget that places a box around a child widget. 932 933 Attributes: 934 - C{fill}: The color used to fill the interior of the box. 935 - C{outline}: The color used to draw the outline of the box. 936 - C{width}: The width of the outline of the box. 937 - C{margin}: The number of pixels space left between the child 938 and the box. 939 - C{draggable}: whether the text can be dragged by the user. 940 """981942 """ 943 Create a new box widget. 944 945 @type canvas: C{Tkinter.Canvas} 946 @param canvas: This canvas widget's canvas. 947 @param child: The child widget. C{child} must not have a 948 parent. 949 @type child: C{CanvasWidget} 950 @param attribs: The new canvas widget's attributes. 951 """ 952 self._child = child 953 self._margin = 1 954 self._box = canvas.create_rectangle(1,1,1,1) 955 canvas.tag_lower(self._box) 956 AbstractContainerWidget.__init__(self, canvas, child, **attribs)957959 if attr == 'margin': self._margin = value 960 elif attr in ('outline', 'fill', 'width'): 961 self.canvas().itemconfig(self._box, {attr:value}) 962 else: 963 CanvasWidget.__setitem__(self, attr, value)964966 if attr == 'margin': return self._margin 967 elif attr == 'width': 968 return float(self.canvas().itemcget(self._box, attr)) 969 elif attr in ('outline', 'fill', 'width'): 970 return self.canvas().itemcget(self._box, attr) 971 else: 972 return CanvasWidget.__getitem__(self, attr)973975 (x1, y1, x2, y2) = child.bbox() 976 margin = self._margin + self['width']/2 977 self.canvas().coords(self._box, x1-margin, y1-margin, 978 x2+margin, y2+margin)979983 """ 984 A canvas widget that places a oval around a child widget. 985 986 Attributes: 987 - C{fill}: The color used to fill the interior of the oval. 988 - C{outline}: The color used to draw the outline of the oval. 989 - C{width}: The width of the outline of the oval. 990 - C{margin}: The number of pixels space left between the child 991 and the oval. 992 - C{draggable}: whether the text can be dragged by the user. 993 - C{double}: If true, then a double-oval is drawn. 994 """1086996 """ 997 Create a new oval widget. 998 999 @type canvas: C{Tkinter.Canvas} 1000 @param canvas: This canvas widget's canvas. 1001 @param child: The child widget. C{child} must not have a 1002 parent. 1003 @type child: C{CanvasWidget} 1004 @param attribs: The new canvas widget's attributes. 1005 """ 1006 self._child = child 1007 self._margin = 1 1008 self._oval = canvas.create_oval(1,1,1,1) 1009 self._circle = attribs.pop('circle', False) 1010 self._double = attribs.pop('double', False) 1011 if self._double: 1012 self._oval2 = canvas.create_oval(1,1,1,1) 1013 else: 1014 self._oval2 = None 1015 canvas.tag_lower(self._oval) 1016 AbstractContainerWidget.__init__(self, canvas, child, **attribs)10171019 c = self.canvas() 1020 if attr == 'margin': self._margin = value 1021 elif attr == 'double': 1022 if value==True and self._oval2 is None: 1023 # Copy attributes & position from self._oval. 1024 x1, y1, x2, y2 = c.bbox(self._oval) 1025 w = self['width']*2 1026 self._oval2 = c.create_oval(x1-w, y1-w, x2+w, y2+w, 1027 outline=c.itemcget(self._oval, 'outline'), 1028 width=c.itemcget(self._oval, 'width')) 1029 c.tag_lower(self._oval2) 1030 if value==False and self._oval2 is not None: 1031 c.delete(self._oval2) 1032 self._oval2 = None 1033 elif attr in ('outline', 'fill', 'width'): 1034 c.itemconfig(self._oval, {attr:value}) 1035 if self._oval2 is not None and attr!='fill': 1036 c.itemconfig(self._oval2, {attr:value}) 1037 if self._oval2 is not None and attr!='fill': 1038 self.canvas().itemconfig(self._oval2, {attr:value}) 1039 else: 1040 CanvasWidget.__setitem__(self, attr, value)10411043 if attr == 'margin': return self._margin 1044 elif attr == 'double': return self._double is not None 1045 elif attr == 'width': 1046 return float(self.canvas().itemcget(self._oval, attr)) 1047 elif attr in ('outline', 'fill', 'width'): 1048 return self.canvas().itemcget(self._oval, attr) 1049 else: 1050 return CanvasWidget.__getitem__(self, attr)1051 1052 # The ratio between inscribed & circumscribed ovals 1053 RATIO = 1.4142135623730949 10541056 R = OvalWidget.RATIO 1057 (x1, y1, x2, y2) = child.bbox() 1058 margin = self._margin 1059 1060 # If we're a circle, pretend our contents are square. 1061 if self._circle: 1062 dx, dy = abs(x1-x2), abs(y1-y2) 1063 if dx > dy: 1064 y = (y1+y2)/2 1065 y1, y2 = y-dx/2, y+dx/2 1066 elif dy > dx: 1067 x = (x1+x2)/2 1068 x1, x2 = x-dy/2, x+dy/2 1069 1070 # Find the four corners. 1071 left = int(( x1*(1+R) + x2*(1-R) ) / 2) 1072 right = left + int((x2-x1)*R) 1073 top = int(( y1*(1+R) + y2*(1-R) ) / 2) 1074 bot = top + int((y2-y1)*R) 1075 self.canvas().coords(self._oval, left-margin, top-margin, 1076 right+margin, bot+margin) 1077 if self._oval2 is not None: 1078 self.canvas().coords(self._oval2, left-margin+2, top-margin+2, 1079 right+margin-2, bot+margin-2)10801088 """ 1089 A canvas widget that places a pair of parenthases around a child 1090 widget. 1091 1092 Attributes: 1093 - C{color}: The color used to draw the parenthases. 1094 - C{width}: The width of the parenthases. 1095 - C{draggable}: whether the text can be dragged by the user. 1096 """11401098 """ 1099 Create a new parenthasis widget. 1100 1101 @type canvas: C{Tkinter.Canvas} 1102 @param canvas: This canvas widget's canvas. 1103 @param child: The child widget. C{child} must not have a 1104 parent. 1105 @type child: C{CanvasWidget} 1106 @param attribs: The new canvas widget's attributes. 1107 """ 1108 self._child = child 1109 self._oparen = canvas.create_arc(1,1,1,1, style='arc', 1110 start=90, extent=180) 1111 self._cparen = canvas.create_arc(1,1,1,1, style='arc', 1112 start=-90, extent=180) 1113 AbstractContainerWidget.__init__(self, canvas, child, **attribs)11141116 if attr == 'color': 1117 self.canvas().itemconfig(self._oparen, outline=value) 1118 self.canvas().itemconfig(self._cparen, outline=value) 1119 elif attr == 'width': 1120 self.canvas().itemconfig(self._oparen, width=value) 1121 self.canvas().itemconfig(self._cparen, width=value) 1122 else: 1123 CanvasWidget.__setitem__(self, attr, value)11241126 if attr == 'color': 1127 return self.canvas().itemcget(self._oparen, 'outline') 1128 elif attr == 'width': 1129 return self.canvas().itemcget(self._oparen, 'width') 1130 else: 1131 return CanvasWidget.__getitem__(self, attr)11321134 (x1, y1, x2, y2) = child.bbox() 1135 width = max((y2-y1)/6, 4) 1136 self.canvas().coords(self._oparen, x1-width, y1, x1+width, y2) 1137 self.canvas().coords(self._cparen, x2-width, y1, x2+width, y2)11381142 """ 1143 A canvas widget that places a pair of brackets around a child 1144 widget. 1145 1146 Attributes: 1147 - C{color}: The color used to draw the brackets. 1148 - C{width}: The width of the brackets. 1149 - C{draggable}: whether the text can be dragged by the user. 1150 """11941152 """ 1153 Create a new bracket widget. 1154 1155 @type canvas: C{Tkinter.Canvas} 1156 @param canvas: This canvas widget's canvas. 1157 @param child: The child widget. C{child} must not have a 1158 parent. 1159 @type child: C{CanvasWidget} 1160 @param attribs: The new canvas widget's attributes. 1161 """ 1162 self._child = child 1163 self._obrack = canvas.create_line(1,1,1,1,1,1,1,1) 1164 self._cbrack = canvas.create_line(1,1,1,1,1,1,1,1) 1165 AbstractContainerWidget.__init__(self, canvas, child, **attribs)11661168 if attr == 'color': 1169 self.canvas().itemconfig(self._obrack, fill=value) 1170 self.canvas().itemconfig(self._cbrack, fill=value) 1171 elif attr == 'width': 1172 self.canvas().itemconfig(self._obrack, width=value) 1173 self.canvas().itemconfig(self._cbrack, width=value) 1174 else: 1175 CanvasWidget.__setitem__(self, attr, value)11761178 if attr == 'color': 1179 return self.canvas().itemcget(self._obrack, 'outline') 1180 elif attr == 'width': 1181 return self.canvas().itemcget(self._obrack, 'width') 1182 else: 1183 return CanvasWidget.__getitem__(self, attr)11841186 (x1, y1, x2, y2) = child.bbox() 1187 width = max((y2-y1)/8, 2) 1188 self.canvas().coords(self._obrack, x1, y1, x1-width, y1, 1189 x1-width, y2, x1, y2) 1190 self.canvas().coords(self._cbrack, x2, y1, x2+width, y1, 1191 x2+width, y2, x2, y2)11921196 """ 1197 A canvas widget that keeps a list of canvas widgets in a 1198 horizontal line. 1199 1200 Attributes: 1201 - C{align}: The vertical alignment of the children. Possible 1202 values are C{'top'}, C{'center'}, and C{'bottom'}. By 1203 default, children are center-aligned. 1204 - C{space}: The amount of horizontal space to place between 1205 children. By default, one pixel of space is used. 1206 - C{ordered}: If true, then keep the children in their 1207 original order. 1208 """13511210 """ 1211 Create a new sequence widget. 1212 1213 @type canvas: C{Tkinter.Canvas} 1214 @param canvas: This canvas widget's canvas. 1215 @param children: The widgets that should be aligned 1216 horizontally. Each child must not have a parent. 1217 @type children: C{list} of C{CanvasWidget} 1218 @param attribs: The new canvas widget's attributes. 1219 """ 1220 self._align = 'center' 1221 self._space = 1 1222 self._ordered = False 1223 self._children = list(children) 1224 for child in children: self._add_child_widget(child) 1225 CanvasWidget.__init__(self, canvas, **attribs)12261228 if attr == 'align': 1229 if value not in ('top', 'bottom', 'center'): 1230 raise ValueError('Bad alignment: %r' % value) 1231 self._align = value 1232 elif attr == 'space': self._space = value 1233 elif attr == 'ordered': self._ordered = value 1234 else: CanvasWidget.__setitem__(self, attr, value)12351237 if attr == 'align': return value 1238 elif attr == 'space': return self._space 1239 elif attr == 'ordered': return self._ordered 1240 else: return CanvasWidget.__getitem__(self, attr)1241 12431245 if self._align == 'top': return top 1246 if self._align == 'bottom': return bot 1247 if self._align == 'center': return (top+bot)/212481250 # Align all children with child. 1251 (left, top, right, bot) = child.bbox() 1252 y = self._yalign(top, bot) 1253 for c in self._children: 1254 (x1, y1, x2, y2) = c.bbox() 1255 c.move(0, y-self._yalign(y1,y2)) 1256 1257 if self._ordered and len(self._children) > 1: 1258 index = self._children.index(child) 1259 1260 x = right + self._space 1261 for i in range(index+1, len(self._children)): 1262 (x1, y1, x2, y2) = self._children[i].bbox() 1263 if x > x1: 1264 self._children[i].move(x-x1, 0) 1265 x += x2-x1 + self._space 1266 1267 x = left - self._space 1268 for i in range(index-1, -1, -1): 1269 (x1, y1, x2, y2) = self._children[i].bbox() 1270 if x < x2: 1271 self._children[i].move(x-x2, 0) 1272 x -= x2-x1 + self._space12731275 if len(self._children) == 0: return 1276 child = self._children[0] 1277 1278 # Align all children with child. 1279 (left, top, right, bot) = child.bbox() 1280 y = self._yalign(top, bot) 1281 1282 index = self._children.index(child) 1283 1284 # Line up children to the right of child. 1285 x = right + self._space 1286 for i in range(index+1, len(self._children)): 1287 (x1, y1, x2, y2) = self._children[i].bbox() 1288 self._children[i].move(x-x1, y-self._yalign(y1,y2)) 1289 x += x2-x1 + self._space 1290 1291 # Line up children to the left of child. 1292 x = left - self._space 1293 for i in range(index-1, -1, -1): 1294 (x1, y1, x2, y2) = self._children[i].bbox() 1295 self._children[i].move(x-x2, y-self._yalign(y1,y2)) 1296 x -= x2-x1 + self._space1297 1300 1301 # Provide an alias for the child_widgets() member. 1302 children = CanvasWidget.child_widgets 13031305 """ 1306 Replace the child canvas widget C{oldchild} with C{newchild}. 1307 C{newchild} must not have a parent. C{oldchild}'s parent will 1308 be set to C{None}. 1309 1310 @type oldchild: C{CanvasWidget} 1311 @param oldchild: The child canvas widget to remove. 1312 @type newchild: C{CanvasWidget} 1313 @param newchild: The canvas widget that should replace 1314 C{oldchild}. 1315 """ 1316 index = self._children.index(oldchild) 1317 self._children[index] = newchild 1318 self._remove_child_widget(oldchild) 1319 self._add_child_widget(newchild) 1320 self.update(newchild)13211323 """ 1324 Remove the given child canvas widget. C{child}'s parent will 1325 be set ot None. 1326 1327 @type child: C{CanvasWidget} 1328 @param child: The child canvas widget to remove. 1329 """ 1330 index = self._children.index(child) 1331 del self._children[index] 1332 self._remove_child_widget(child) 1333 if len(self._children) > 0: 1334 self.update(self._children[0])13351337 """ 1338 Insert a child canvas widget before a given index. 1339 1340 @type child: C{CanvasWidget} 1341 @param child: The canvas widget that should be inserted. 1342 @type index: C{int} 1343 @param index: The index where the child widget should be 1344 inserted. In particular, the index of C{child} will be 1345 C{index}; and the index of any children whose indices were 1346 greater than equal to C{index} before C{child} was 1347 inserted will be incremented by one. 1348 """ 1349 self._children.insert(index, child) 1350 self._add_child_widget(child)1353 """ 1354 A canvas widget that keeps a list of canvas widgets in a vertical 1355 line. 1356 1357 Attributes: 1358 - C{align}: The horizontal alignment of the children. Possible 1359 values are C{'left'}, C{'center'}, and C{'right'}. By 1360 default, children are center-aligned. 1361 - C{space}: The amount of vertical space to place between 1362 children. By default, one pixel of space is used. 1363 - C{ordered}: If true, then keep the children in their 1364 original order. 1365 """15081367 """ 1368 Create a new stack widget. 1369 1370 @type canvas: C{Tkinter.Canvas} 1371 @param canvas: This canvas widget's canvas. 1372 @param children: The widgets that should be aligned 1373 vertically. Each child must not have a parent. 1374 @type children: C{list} of C{CanvasWidget} 1375 @param attribs: The new canvas widget's attributes. 1376 """ 1377 self._align = 'center' 1378 self._space = 1 1379 self._ordered = False 1380 self._children = list(children) 1381 for child in children: self._add_child_widget(child) 1382 CanvasWidget.__init__(self, canvas, **attribs)13831385 if attr == 'align': 1386 if value not in ('left', 'right', 'center'): 1387 raise ValueError('Bad alignment: %r' % value) 1388 self._align = value 1389 elif attr == 'space': self._space = value 1390 elif attr == 'ordered': self._ordered = value 1391 else: CanvasWidget.__setitem__(self, attr, value)13921394 if attr == 'align': return value 1395 elif attr == 'space': return self._space 1396 elif attr == 'ordered': return self._ordered 1397 else: return CanvasWidget.__getitem__(self, attr)1398 14001402 if self._align == 'left': return left 1403 if self._align == 'right': return right 1404 if self._align == 'center': return (left+right)/214051407 # Align all children with child. 1408 (left, top, right, bot) = child.bbox() 1409 x = self._xalign(left, right) 1410 for c in self._children: 1411 (x1, y1, x2, y2) = c.bbox() 1412 c.move(x-self._xalign(x1,x2), 0) 1413 1414 if self._ordered and len(self._children) > 1: 1415 index = self._children.index(child) 1416 1417 y = bot + self._space 1418 for i in range(index+1, len(self._children)): 1419 (x1, y1, x2, y2) = self._children[i].bbox() 1420 if y > y1: 1421 self._children[i].move(0, y-y1) 1422 y += y2-y1 + self._space 1423 1424 y = top - self._space 1425 for i in range(index-1, -1, -1): 1426 (x1, y1, x2, y2) = self._children[i].bbox() 1427 if y < y2: 1428 self._children[i].move(0, y-y2) 1429 y -= y2-y1 + self._space14301432 if len(self._children) == 0: return 1433 child = self._children[0] 1434 1435 # Align all children with child. 1436 (left, top, right, bot) = child.bbox() 1437 x = self._xalign(left, right) 1438 1439 index = self._children.index(child) 1440 1441 # Line up children below the child. 1442 y = bot + self._space 1443 for i in range(index+1, len(self._children)): 1444 (x1, y1, x2, y2) = self._children[i].bbox() 1445 self._children[i].move(x-self._xalign(x1,x2), y-y1) 1446 y += y2-y1 + self._space 1447 1448 # Line up children above the child. 1449 y = top - self._space 1450 for i in range(index-1, -1, -1): 1451 (x1, y1, x2, y2) = self._children[i].bbox() 1452 self._children[i].move(x-self._xalign(x1,x2), y-y2) 1453 y -= y2-y1 + self._space1454 1457 1458 # Provide an alias for the child_widgets() member. 1459 children = CanvasWidget.child_widgets 14601462 """ 1463 Replace the child canvas widget C{oldchild} with C{newchild}. 1464 C{newchild} must not have a parent. C{oldchild}'s parent will 1465 be set to C{None}. 1466 1467 @type oldchild: C{CanvasWidget} 1468 @param oldchild: The child canvas widget to remove. 1469 @type newchild: C{CanvasWidget} 1470 @param newchild: The canvas widget that should replace 1471 C{oldchild}. 1472 """ 1473 index = self._children.index(oldchild) 1474 self._children[index] = newchild 1475 self._remove_child_widget(oldchild) 1476 self._add_child_widget(newchild) 1477 self.update(newchild)14781480 """ 1481 Remove the given child canvas widget. C{child}'s parent will 1482 be set ot None. 1483 1484 @type child: C{CanvasWidget} 1485 @param child: The child canvas widget to remove. 1486 """ 1487 index = self._children.index(child) 1488 del self._children[index] 1489 self._remove_child_widget(child) 1490 if len(self._children) > 0: 1491 self.update(self._children[0])14921494 """ 1495 Insert a child canvas widget before a given index. 1496 1497 @type child: C{CanvasWidget} 1498 @param child: The canvas widget that should be inserted. 1499 @type index: C{int} 1500 @param index: The index where the child widget should be 1501 inserted. In particular, the index of C{child} will be 1502 C{index}; and the index of any children whose indices were 1503 greater than equal to C{index} before C{child} was 1504 inserted will be incremented by one. 1505 """ 1506 self._children.insert(index, child) 1507 self._add_child_widget(child)1510 """ 1511 A canvas widget that takes up space but does not display 1512 anything. C{SpaceWidget}s can be used to add space between 1513 elements. Each space widget is characterized by a width and a 1514 height. If you wish to only create horizontal space, then use a 1515 height of zero; and if you wish to only create vertical space, use 1516 a width of zero. 1517 """15621519 """ 1520 Create a new space widget. 1521 1522 @type canvas: C{Tkinter.Canvas} 1523 @param canvas: This canvas widget's canvas. 1524 @type width: C{int} 1525 @param width: The width of the new space widget. 1526 @type height: C{int} 1527 @param height: The height of the new space widget. 1528 @param attribs: The new canvas widget's attributes. 1529 """ 1530 # For some reason, 1531 if width > 4: width -= 4 1532 if height > 4: height -= 4 1533 self._tag = canvas.create_line(1, 1, width, height, fill='') 1534 CanvasWidget.__init__(self, canvas, **attribs)1535 1536 # note: width() and height() are already defined by CanvasWidget.1538 """ 1539 Change the width of this space widget. 1540 1541 @param width: The new width. 1542 @type width: C{int} 1543 @rtype: C{None} 1544 """ 1545 [x1, y1, x2, y2] = self.bbox() 1546 self.canvas().coords(self._tag, x1, y1, x1+width, y2)15471549 """ 1550 Change the height of this space widget. 1551 1552 @param height: The new height. 1553 @type height: C{int} 1554 @rtype: C{None} 1555 """ 1556 [x1, y1, x2, y2] = self.bbox() 1557 self.canvas().coords(self._tag, x1, y1, x2, y1+height)1558 15601564 """ 1565 A special canvas widget that adjusts its C{Canvas}'s scrollregion 1566 to always include the bounding boxes of all of its children. The 1567 scroll-watcher widget will only increase the size of the 1568 C{Canvas}'s scrollregion; it will never decrease it. 1569 """1633 1634 ##////////////////////////////////////////////////////// 1635 ## Canvas Frame 1636 ##////////////////////////////////////////////////////// 16371571 """ 1572 Create a new scroll-watcher widget. 1573 1574 @type canvas: C{Tkinter.Canvas} 1575 @param canvas: This canvas widget's canvas. 1576 @type children: C{list} of C{CanvasWidget} 1577 @param children: The canvas widgets watched by the 1578 scroll-watcher. The scroll-watcher will ensure that these 1579 canvas widgets are always contained in their canvas's 1580 scrollregion. 1581 @param attribs: The new canvas widget's attributes. 1582 """ 1583 for child in children: self._add_child_widget(child) 1584 CanvasWidget.__init__(self, canvas, **attribs)15851587 """ 1588 Add a new canvas widget to the scroll-watcher. The 1589 scroll-watcher will ensure that the new canvas widget is 1590 always contained in its canvas's scrollregion. 1591 1592 @param canvaswidget: The new canvas widget. 1593 @type canvaswidget: C{CanvasWidget} 1594 @rtype: C{None} 1595 """ 1596 self._add_child_widget(canvaswidget) 1597 self.update(canvaswidget)15981600 """ 1601 Remove a canvas widget from the scroll-watcher. The 1602 scroll-watcher will no longer ensure that the new canvas 1603 widget is always contained in its canvas's scrollregion. 1604 1605 @param canvaswidget: The canvas widget to remove. 1606 @type canvaswidget: C{CanvasWidget} 1607 @rtype: C{None} 1608 """ 1609 self._remove_child_widget(canvaswidget)1610 16121614 self._adjust_scrollregion()16151617 """ 1618 Adjust the scrollregion of this scroll-watcher's C{Canvas} to 1619 include the bounding boxes of all of its children. 1620 """ 1621 bbox = self.bbox() 1622 canvas = self.canvas() 1623 scrollregion = [int(n) for n in canvas['scrollregion'].split()] 1624 if len(scrollregion) != 4: return 1625 if (bbox[0] < scrollregion[0] or bbox[1] < scrollregion[1] or 1626 bbox[2] > scrollregion[2] or bbox[3] > scrollregion[3]): 1627 scrollregion = ('%d %d %d %d' % 1628 (min(bbox[0], scrollregion[0]), 1629 min(bbox[1], scrollregion[1]), 1630 max(bbox[2], scrollregion[2]), 1631 max(bbox[3], scrollregion[3]))) 1632 canvas['scrollregion'] = scrollregion1639 """ 1640 A C{Tkinter} frame containing a canvas and scrollbars. 1641 C{CanvasFrame} uses a C{ScrollWatcherWidget} to ensure that all of 1642 the canvas widgets contained on its canvas are within its 1643 scrollregion. In order for C{CanvasFrame} to make these checks, 1644 all canvas widgets must be registered with C{add_widget} when they 1645 are added to the canvas; and destroyed with C{destroy_widget} when 1646 they are no longer needed. 1647 1648 If a C{CanvasFrame} is created with no parent, then it will create 1649 its own main window, including a "Done" button and a "Print" 1650 button. 1651 """1849 1850 ##////////////////////////////////////////////////////// 1851 ## Text display 1852 ##////////////////////////////////////////////////////// 18531653 """ 1654 Create a new C{CanvasFrame}. 1655 1656 @type parent: C{Tkinter.BaseWidget} or C{Tkinter.Tk} 1657 @param parent: The parent C{Tkinter} widget. If no parent is 1658 specified, then C{CanvasFrame} will create a new main 1659 window. 1660 @param kw: Keyword arguments for the new C{Canvas}. See the 1661 documentation for C{Tkinter.Canvas} for more information. 1662 """ 1663 # If no parent was given, set up a top-level window. 1664 if parent is None: 1665 self._parent = Tk() 1666 self._parent.title('NLTK') 1667 self._parent.bind('<Control-p>', lambda e: self.print_to_file()) 1668 self._parent.bind('<Control-x>', self.destroy) 1669 self._parent.bind('<Control-q>', self.destroy) 1670 else: 1671 self._parent = parent 1672 1673 # Create a frame for the canvas & scrollbars 1674 self._frame = frame = Frame(self._parent) 1675 self._canvas = canvas = Canvas(frame, **kw) 1676 xscrollbar = Scrollbar(self._frame, orient='horizontal') 1677 yscrollbar = Scrollbar(self._frame, orient='vertical') 1678 xscrollbar['command'] = canvas.xview 1679 yscrollbar['command'] = canvas.yview 1680 canvas['xscrollcommand'] = xscrollbar.set 1681 canvas['yscrollcommand'] = yscrollbar.set 1682 yscrollbar.pack(fill='y', side='right') 1683 xscrollbar.pack(fill='x', side='bottom') 1684 canvas.pack(expand=1, fill='both', side='left') 1685 1686 # Set initial scroll region. 1687 scrollregion = '0 0 %s %s' % (canvas['width'], canvas['height']) 1688 canvas['scrollregion'] = scrollregion 1689 1690 self._scrollwatcher = ScrollWatcherWidget(canvas) 1691 1692 # If no parent was given, pack the frame, and add a menu. 1693 if parent is None: 1694 self.pack(expand=1, fill='both') 1695 self._init_menubar()1696 17081710 """ 1711 Print the contents of this C{CanvasFrame} to a postscript 1712 file. If no filename is given, then prompt the user for one. 1713 1714 @param filename: The name of the file to print the tree to. 1715 @type filename: C{string} 1716 @rtype: C{None} 1717 """ 1718 if filename is None: 1719 from tkFileDialog import asksaveasfilename 1720 ftypes = [('Postscript files', '.ps'), 1721 ('All files', '*')] 1722 filename = asksaveasfilename(filetypes=ftypes, 1723 defaultextension='.ps') 1724 if not filename: return 1725 (x0, y0, w, h) = self.scrollregion() 1726 self._canvas.postscript(file=filename, x=x0, y=y0, 1727 width=w+2, height=h+2, 1728 pagewidth=w+2, # points = 1/72 inch 1729 pageheight=h+2, # points = 1/72 inch 1730 pagex=0, pagey=0)17311733 """ 1734 @return: The current scroll region for the canvas managed by 1735 this C{CanvasFrame}. 1736 @rtype: 4-tuple of C{int} 1737 """ 1738 (x1, y1, x2, y2) = self._canvas['scrollregion'].split() 1739 return (int(x1), int(y1), int(x2), int(y2))17401742 """ 1743 @return: The canvas managed by this C{CanvasFrame}. 1744 @rtype: C{Tkinter.Canvas} 1745 """ 1746 return self._canvas17471749 """ 1750 Register a canvas widget with this C{CanvasFrame}. The 1751 C{CanvasFrame} will ensure that this canvas widget is always 1752 within the C{Canvas}'s scrollregion. If no coordinates are 1753 given for the canvas widget, then the C{CanvasFrame} will 1754 attempt to find a clear area of the canvas for it. 1755 1756 @type canvaswidget: C{CanvasWidget} 1757 @param canvaswidget: The new canvas widget. C{canvaswidget} 1758 must have been created on this C{CanvasFrame}'s canvas. 1759 @type x: C{int} 1760 @param x: The initial x coordinate for the upper left hand 1761 corner of C{canvaswidget}, in the canvas's coordinate 1762 space. 1763 @type y: C{int} 1764 @param y: The initial y coordinate for the upper left hand 1765 corner of C{canvaswidget}, in the canvas's coordinate 1766 space. 1767 """ 1768 if x is None or y is None: 1769 (x, y) = self._find_room(canvaswidget, x, y) 1770 1771 # Move to (x,y) 1772 (x1,y1,x2,y2) = canvaswidget.bbox() 1773 canvaswidget.move(x-x1,y-y1) 1774 1775 # Register with scrollwatcher. 1776 self._scrollwatcher.add_child(canvaswidget)17771779 """ 1780 Try to find a space for a given widget. 1781 """ 1782 (left, top, right, bot) = self.scrollregion() 1783 w = widget.width() 1784 h = widget.height() 1785 1786 if w >= (right-left): return (0,0) 1787 if h >= (bot-top): return (0,0) 1788 1789 # Move the widget out of the way, for now. 1790 (x1,y1,x2,y2) = widget.bbox() 1791 widget.move(left-x2-50, top-y2-50) 1792 1793 if desired_x is not None: 1794 x = desired_x 1795 for y in range(top, bot-h, (bot-top-h)/10): 1796 if not self._canvas.find_overlapping(x-5, y-5, x+w+5, y+h+5): 1797 return (x,y) 1798 1799 if desired_y is not None: 1800 y = desired_y 1801 for x in range(left, right-w, (right-left-w)/10): 1802 if not self._canvas.find_overlapping(x-5, y-5, x+w+5, y+h+5): 1803 return (x,y) 1804 1805 for y in range(top, bot-h, (bot-top-h)/10): 1806 for x in range(left, right-w, (right-left-w)/10): 1807 if not self._canvas.find_overlapping(x-5, y-5, x+w+5, y+h+5): 1808 return (x,y) 1809 return (0,0)18101812 """ 1813 Remove a canvas widget from this C{CanvasFrame}. This 1814 deregisters the canvas widget, and destroys it. 1815 """ 1816 self.remove_widget(canvaswidget) 1817 canvaswidget.destroy()1818 18221824 """ 1825 Pack this C{CanvasFrame}. See the documentation for 1826 C{Tkinter.Pack} for more information. 1827 """ 1828 self._frame.pack(cnf, **kw)1829 # Adjust to be big enough for kids? 18301832 """ 1833 Destroy this C{CanvasFrame}. If this C{CanvasFrame} created a 1834 top-level window, then this will close that window. 1835 """ 1836 if self._parent is None: return 1837 self._parent.destroy() 1838 self._parent = None18391841 """ 1842 Enter the Tkinter mainloop. This function must be called if 1843 this frame is created from a non-interactive program (e.g. 1844 from a secript); otherwise, the frame will close as soon as 1845 the script completes. 1846 """ 1847 if in_idle(): return 1848 self._parent.mainloop(*args, **kwargs)1855 """ 1856 A C{Tkinter} window used to display a text. C{ShowText} is 1857 typically used by graphical tools to display help text, or similar 1858 information. 1859 """1929 1930 ##////////////////////////////////////////////////////// 1931 ## Entry dialog 1932 ##////////////////////////////////////////////////////// 19331862 if width is None or height is None: 1863 (width, height) = self.find_dimentions(text, width, height) 1864 1865 # Create the main window. 1866 if root is None: 1867 self._top = top = Tk() 1868 else: 1869 self._top = top = Toplevel(root) 1870 top.title(title) 1871 1872 b = Button(top, text='Ok', command=self.destroy) 1873 b.pack(side='bottom') 1874 1875 tbf = Frame(top) 1876 tbf.pack(expand=1, fill='both') 1877 scrollbar = Scrollbar(tbf, orient='vertical') 1878 scrollbar.pack(side='right', fill='y') 1879 textbox = Text(tbf, wrap='word', width=width, 1880 height=height, **textbox_options) 1881 textbox.insert('end', text) 1882 textbox['state'] = 'disabled' 1883 textbox.pack(side='left', expand=1, fill='both') 1884 scrollbar['command'] = textbox.yview 1885 textbox['yscrollcommand'] = scrollbar.set 1886 1887 # Make it easy to close the window. 1888 top.bind('q', self.destroy) 1889 top.bind('x', self.destroy) 1890 top.bind('c', self.destroy) 1891 top.bind('<Return>', self.destroy) 1892 top.bind('<Escape>', self.destroy) 1893 1894 # Focus the scrollbar, so they can use up/down, etc. 1895 scrollbar.focus()18961898 lines = text.split('\n') 1899 if width is None: 1900 maxwidth = max([len(line) for line in lines]) 1901 width = min(maxwidth, 80) 1902 1903 # Now, find height. 1904 height = 0 1905 for line in lines: 1906 while len(line) > width: 1907 brk = line[:width].rfind(' ') 1908 line = line[brk:] 1909 height += 1 1910 height += 1 1911 height = min(height, 25) 1912 1913 return (width, height)1914 19191921 """ 1922 Enter the Tkinter mainloop. This function must be called if 1923 this window is created from a non-interactive program (e.g. 1924 from a secript); otherwise, the window will close as soon as 1925 the script completes. 1926 """ 1927 if in_idle(): return 1928 self._top.mainloop(*args, **kwargs)1935 """ 1936 A dialog box for entering 1937 """2003 2004 ##////////////////////////////////////////////////////// 2005 ## Colorized List 2006 ##////////////////////////////////////////////////////// 20071938 - def __init__(self, parent, original_text='', instructions='', 1939 set_callback=None, title=None):1940 self._parent = parent 1941 self._original_text = original_text 1942 self._set_callback = set_callback 1943 1944 width = max(30, len(original_text)*3/2) 1945 self._top = Toplevel(parent) 1946 1947 if title: self._top.title(title) 1948 1949 # The text entry box. 1950 entryframe = Frame(self._top) 1951 entryframe.pack(expand=1, fill='both', padx=5, pady=5,ipady=10) 1952 if instructions: 1953 l=Label(entryframe, text=instructions) 1954 l.pack(side='top', anchor='w', padx=30) 1955 self._entry = Entry(entryframe, width=width) 1956 self._entry.pack(expand=1, fill='x', padx=30) 1957 self._entry.insert(0, original_text) 1958 1959 # A divider 1960 divider = Frame(self._top, borderwidth=1, relief='sunken') 1961 divider.pack(fill='x', ipady=1, padx=10) 1962 1963 # The buttons. 1964 buttons = Frame(self._top) 1965 buttons.pack(expand=0, fill='x', padx=5, pady=5) 1966 b = Button(buttons, text='Cancel', command=self._cancel, width=8) 1967 b.pack(side='right', padx=5) 1968 b = Button(buttons, text='Ok', command=self._ok, 1969 width=8, default='active') 1970 b.pack(side='left', padx=5) 1971 b = Button(buttons, text='Apply', command=self._apply, width=8) 1972 b.pack(side='left') 1973 1974 self._top.bind('<Return>', self._ok) 1975 self._top.bind('<Control-q>', self._cancel) 1976 self._top.bind('<Escape>', self._cancel) 1977 1978 self._entry.focus()19791981 self._entry.delete(0,'end') 1982 self._entry.insert(0, self._original_text) 1983 if self._set_callback: 1984 self._set_callback(self._original_text)1985 1990 1994 19982009 """ 2010 An abstract base class for displaying a colorized list of items. 2011 Subclasses should define: 2012 - L{_init_colortags}, which sets up Text color tags that 2013 will be used by the list. 2014 - L{_item_repr}, which returns a list of (text,colortag) 2015 tuples that make up the colorized representation of the 2016 item. 2017 @note: Typically, you will want to register a callback for 2018 C{'select'} that calls L{mark} on the given item. 2019 """2264 2265 ##////////////////////////////////////////////////////// 2266 ## Improved OptionMenu 2267 ##////////////////////////////////////////////////////// 22682021 """ 2022 Construct a new list. 2023 2024 @param parent: The Tk widget that contains the colorized list 2025 @param items: The initial contents of the colorized list. 2026 @param options: 2027 """ 2028 self._parent = parent 2029 self._callbacks = {} 2030 2031 # Which items are marked? 2032 self._marks = {} 2033 2034 # Initialize the Tkinter frames. 2035 self._init_itemframe(options.copy()) 2036 2037 # Set up key & mouse bindings. 2038 self._textwidget.bind('<KeyPress>', self._keypress) 2039 self._textwidget.bind('<ButtonPress>', self._buttonpress) 2040 2041 # Fill in the given CFG's items. 2042 self._items = None 2043 self.set(items)2044 2045 #//////////////////////////////////////////////////////////// 2046 # Abstract methods 2047 #//////////////////////////////////////////////////////////// 2048 20562058 """ 2059 Return a list of (text, colortag) tuples that make up the 2060 colorized representation of the item. Colorized 2061 representations may not span multiple lines. I.e., the text 2062 strings returned may not contain newline characters. 2063 """ 2064 raise AssertionError, 'Abstract base class'2065 2066 #//////////////////////////////////////////////////////////// 2067 # Item Access 2068 #//////////////////////////////////////////////////////////// 20692071 """ 2072 @return: A list of the items contained by this list. 2073 """ 2074 if index is None: 2075 return self._items[:] 2076 else: 2077 return self._items[index]20782080 """ 2081 Modify the list of items contained by this list. 2082 """ 2083 items = list(items) 2084 if self._items == items: return 2085 self._items = list(items) 2086 2087 self._textwidget['state'] = 'normal' 2088 self._textwidget.delete('1.0', 'end') 2089 for item in items: 2090 for (text, colortag) in self._item_repr(item): 2091 assert '\n' not in text, 'item repr may not contain newline' 2092 self._textwidget.insert('end', text, colortag) 2093 self._textwidget.insert('end', '\n') 2094 # Remove the final newline 2095 self._textwidget.delete('end-1char', 'end') 2096 self._textwidget.mark_set('insert', '1.0') 2097 self._textwidget['state'] = 'disabled' 2098 # Clear all marks 2099 self._marks.clear()21002102 """ 2103 Remove highlighting from the given item; or from every item, 2104 if no item is given. 2105 @raise ValueError: If C{item} is not contained in the list. 2106 @raise KeyError: If C{item} is not marked. 2107 """ 2108 if item is None: 2109 self._marks.clear() 2110 self._textwidget.tag_remove('highlight', '1.0', 'end+1char') 2111 else: 2112 index = self._items.index(item) 2113 del self._marks[item] 2114 (start, end) = ('%d.0' % (index+1), '%d.0' % (index+2)) 2115 self._textwidget.tag_remove('highlight', start, end)21162118 """ 2119 Highlight the given item. 2120 @raise ValueError: If C{item} is not contained in the list. 2121 """ 2122 self._marks[item] = 1 2123 index = self._items.index(item) 2124 (start, end) = ('%d.0' % (index+1), '%d.0' % (index+2)) 2125 self._textwidget.tag_add('highlight', start, end)21262128 """ 2129 Remove any current highlighting, and mark the given item. 2130 @raise ValueError: If C{item} is not contained in the list. 2131 """ 2132 self.unmark() 2133 self.mark(item)21342136 """ 2137 Adjust the view such that the given item is visible. If 2138 the item is already visible, then do nothing. 2139 """ 2140 index = self._items.index(item) 2141 self._textwidget.see('%d.0' % (index+1))2142 2143 #//////////////////////////////////////////////////////////// 2144 # Callbacks 2145 #//////////////////////////////////////////////////////////// 21462148 """ 2149 Register a callback function with the list. This function 2150 will be called whenever the given event occurs. 2151 2152 @param event: The event that will trigger the callback 2153 function. Valid events are: click1, click2, click3, 2154 space, return, select, up, down, next, prior, move 2155 @param func: The function that should be called when 2156 the event occurs. C{func} will be called with a 2157 single item as its argument. (The item selected 2158 or the item moved to). 2159 """ 2160 if event == 'select': events = ['click1', 'space', 'return'] 2161 elif event == 'move': events = ['up', 'down', 'next', 'prior'] 2162 else: events = [event] 2163 2164 for e in events: 2165 self._callbacks.setdefault(e,{})[func] = 121662168 """ 2169 Deregister a callback function. If C{func} is none, then 2170 all callbacks are removed for the given event. 2171 """ 2172 if event is None: events = self._callbacks.keys() 2173 elif event == 'select': events = ['click1', 'space', 'return'] 2174 elif event == 'move': events = ['up', 'down', 'next', 'prior'] 2175 else: events = [event] 2176 2177 for e in events: 2178 if func is None: del self._callbacks[e] 2179 else: 2180 try: del self._callbacks[e][func] 2181 except: pass2182 2183 #//////////////////////////////////////////////////////////// 2184 # Tkinter Methods 2185 #//////////////////////////////////////////////////////////// 2186 2190 2194 2198 2199 #//////////////////////////////////////////////////////////// 2200 # Internal Methods 2201 #//////////////////////////////////////////////////////////// 22022204 self._itemframe = Frame(self._parent) 2205 2206 # Create the basic Text widget & scrollbar. 2207 options.setdefault('background', '#e0e0e0') 2208 self._textwidget = Text(self._itemframe, **options) 2209 self._textscroll = Scrollbar(self._itemframe, takefocus=0, 2210 orient='vertical') 2211 self._textwidget.config(yscrollcommand = self._textscroll.set) 2212 self._textscroll.config(command=self._textwidget.yview) 2213 self._textscroll.pack(side='right', fill='y') 2214 self._textwidget.pack(expand=1, fill='both', side='left') 2215 2216 # Initialize the colorization tags 2217 self._textwidget.tag_config('highlight', background='#e0ffff', 2218 border='1', relief='raised') 2219 self._init_colortags(self._textwidget, options) 2220 2221 # How do I want to mark keyboard selection? 2222 self._textwidget.tag_config('sel', foreground='') 2223 self._textwidget.tag_config('sel', foreground='', background='', 2224 border='', underline=1) 2225 self._textwidget.tag_lower('highlight', 'sel')22262228 if not self._callbacks.has_key(event): return 2229 if 0 <= itemnum < len(self._items): 2230 item = self._items[itemnum] 2231 else: 2232 item = None 2233 for cb_func in self._callbacks[event].keys(): 2234 cb_func(item)2235 22412243 if event.keysym == 'Return' or event.keysym == 'space': 2244 insert_point = self._textwidget.index('insert') 2245 itemnum = int(insert_point.split('.')[0])-1 2246 self._fire_callback(event.keysym.lower(), itemnum) 2247 return 2248 elif event.keysym == 'Down': delta='+1line' 2249 elif event.keysym == 'Up': delta='-1line' 2250 elif event.keysym == 'Next': delta='+10lines' 2251 elif event.keysym == 'Prior': delta='-10lines' 2252 else: return 'continue' 2253 2254 self._textwidget.mark_set('insert', 'insert'+delta) 2255 self._textwidget.see('insert') 2256 self._textwidget.tag_remove('sel', '1.0', 'end+1char') 2257 self._textwidget.tag_add('sel', 'insert linestart', 'insert lineend') 2258 2259 insert_point = self._textwidget.index('insert') 2260 itemnum = int(insert_point.split('.')[0])-1 2261 self._fire_callback(event.keysym.lower(), itemnum) 2262 2263 return 'break'2319 2320 ##////////////////////////////////////////////////////// 2321 ## Helpers 2322 ##////////////////////////////////////////////////////// 23232271 self._callback = options.get('command') 2272 if 'command' in options: del options['command'] 2273 2274 # Create a variable 2275 self._variable = variable = StringVar() 2276 if len(values) > 0: 2277 variable.set(values[0]) 2278 2279 kw = {"borderwidth": 2, "textvariable": variable, 2280 "indicatoron": 1, "relief": RAISED, "anchor": "c", 2281 "highlightthickness": 2} 2282 kw.update(options) 2283 Widget.__init__(self, master, "menubutton", kw) 2284 self.widgetName = 'tk_optionMenu' 2285 self._menu = Menu(self, name="menu", tearoff=0,) 2286 self.menuname = self._menu._w 2287 2288 self._values = [] 2289 for value in values: self.add(value) 2290 2291 self["menu"] = self._menu22922294 if value in self._values: return 2295 def set(value=value): self.set(value) 2296 self._menu.add_command(label=value, command=set) 2297 self._values.append(value)2298 23032305 # Might raise indexerror: pass to parent. 2306 i = self._values.index(value) 2307 del self._values[i] 2308 self._menu.delete(i, i)2309 23142316 """Destroy this widget and the associated menu.""" 2317 Menubutton.destroy(self) 2318 self._menu = None2325 """ 2326 @rtype: C{boolean} 2327 @return: true if this function is run within idle. Tkinter 2328 programs that are run in idle should never call C{Tk.mainloop}; so 2329 this function should be used to gate all calls to C{Tk.mainloop}. 2330 2331 @warning: This function works by checking C{sys.stdin}. If the 2332 user has modified C{sys.stdin}, then it may return incorrect 2333 results. 2334 """ 2335 import sys, types 2336 return (type(sys.stdin) == types.InstanceType and \ 2337 sys.stdin.__class__.__name__ == 'PyShell')2338 2339 ##////////////////////////////////////////////////////// 2340 ## Test code. 2341 ##////////////////////////////////////////////////////// 2342 2350 def color(cw): 2351 from random import randint 2352 cw['color'] = '#ff%04d' % randint(0,9999) 2353 2354 cf = CanvasFrame(closeenough=10, width=300, height=300) 2355 c = cf.canvas() 2356 ct3 = TextWidget(c, 'hiya there', draggable=1) 2357 ct2 = TextWidget(c, 'o o\n||\n___\n U', draggable=1, justify='center') 2358 co = OvalWidget(c, ct2, outline='red') 2359 ct = TextWidget(c, 'o o\n||\n\\___/', draggable=1, justify='center') 2360 cp = ParenWidget(c, ct, color='red') 2361 cb = BoxWidget(c, cp, fill='cyan', draggable=1, width=3, margin=10) 2362 equation = SequenceWidget(c, 2363 SymbolWidget(c, 'forall'), TextWidget(c, 'x'), 2364 SymbolWidget(c, 'exists'), TextWidget(c, 'y: '), 2365 TextWidget(c, 'x'), SymbolWidget(c, 'notequal'), 2366 TextWidget(c, 'y')) 2367 space = SpaceWidget(c, 0, 30) 2368 cstack = StackWidget(c, cb, ct3, space, co, equation, align='center') 2369 foo = TextWidget(c, 'try clicking\nand dragging', 2370 draggable=1, justify='center') 2371 cs = SequenceWidget(c, cstack, foo) 2372 zz = BracketWidget(c, cs, color='green4', width=3) 2373 cf.add_widget(zz, 60, 30) 2374 2375 cb.bind_click(fill) 2376 ct.bind_click(color) 2377 co.bind_click(fill) 2378 ct2.bind_click(color) 2379 ct3.bind_click(color) 2380 2381 cf.mainloop() 2382 #ShowText(None, 'title', ((('this is text'*150)+'\n')*5)) 2383 2384 if __name__ == '__main__': 2385 demo() 2386 2387 from cfg import * 2388 from chart import * 2389 from plot import * 2390 from rdparser import * 2391 from srparser import * 2392 from tree import * 2393 from dispersion import dispersion_plot 2394 from rechunkparser import RegexpChunkDemo 2395 from concordance import pos_concordance 2396 2397 # Make sure that nltk.draw.cfg and nltk.draw.tree refer to the correct 2398 # modules (and not to nltk.cfg & nltk.tree) 2399 import cfg, tree 2400
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0beta1 on Wed Aug 27 15:09:07 2008 | http://epydoc.sourceforge.net |