1import unittest 2import Tkinter as tkinter 3from Tkinter import TclError 4import ttk 5from test.test_support import requires, run_unittest, have_unicode, u 6import sys 7 8from test_functions import MockTclObj 9from support import (AbstractTkTest, tcl_version, get_tk_patchlevel, 10 simulate_mouse_click) 11from widget_tests import (add_standard_options, noconv, noconv_meth, 12 AbstractWidgetTest, StandardOptionsTests, 13 IntegerSizeTests, PixelSizeTests, 14 setUpModule) 15 16requires('gui') 17 18 19class StandardTtkOptionsTests(StandardOptionsTests): 20 21 def test_class(self): 22 widget = self.create() 23 self.assertEqual(widget['class'], '') 24 errmsg='attempt to change read-only option' 25 if get_tk_patchlevel() < (8, 6, 0, 'beta', 3): 26 errmsg='Attempt to change read-only option' 27 self.checkInvalidParam(widget, 'class', 'Foo', errmsg=errmsg) 28 widget2 = self.create(class_='Foo') 29 self.assertEqual(widget2['class'], 'Foo') 30 31 def test_padding(self): 32 widget = self.create() 33 self.checkParam(widget, 'padding', 0, expected=('0',)) 34 self.checkParam(widget, 'padding', 5, expected=('5',)) 35 self.checkParam(widget, 'padding', (5, 6), expected=('5', '6')) 36 self.checkParam(widget, 'padding', (5, 6, 7), 37 expected=('5', '6', '7')) 38 self.checkParam(widget, 'padding', (5, 6, 7, 8), 39 expected=('5', '6', '7', '8')) 40 self.checkParam(widget, 'padding', ('5p', '6p', '7p', '8p')) 41 self.checkParam(widget, 'padding', (), expected='') 42 43 def test_style(self): 44 widget = self.create() 45 self.assertEqual(widget['style'], '') 46 errmsg = 'Layout Foo not found' 47 if hasattr(self, 'default_orient'): 48 errmsg = ('Layout %s.Foo not found' % 49 getattr(self, 'default_orient').title()) 50 self.checkInvalidParam(widget, 'style', 'Foo', 51 errmsg=errmsg) 52 widget2 = self.create(class_='Foo') 53 self.assertEqual(widget2['class'], 'Foo') 54 # XXX 55 pass 56 57 58class WidgetTest(AbstractTkTest, unittest.TestCase): 59 """Tests methods available in every ttk widget.""" 60 61 def setUp(self): 62 super(WidgetTest, self).setUp() 63 self.widget = ttk.Button(self.root, width=0, text="Text") 64 self.widget.pack() 65 self.widget.wait_visibility() 66 67 68 def test_identify(self): 69 self.widget.update_idletasks() 70 self.assertEqual(self.widget.identify( 71 self.widget.winfo_width() // 2, 72 self.widget.winfo_height() // 2 73 ), "label") 74 self.assertEqual(self.widget.identify(-1, -1), "") 75 76 self.assertRaises(tkinter.TclError, self.widget.identify, None, 5) 77 self.assertRaises(tkinter.TclError, self.widget.identify, 5, None) 78 self.assertRaises(tkinter.TclError, self.widget.identify, 5, '') 79 80 81 def test_widget_state(self): 82 # XXX not sure about the portability of all these tests 83 self.assertEqual(self.widget.state(), ()) 84 self.assertEqual(self.widget.instate(['!disabled']), True) 85 86 # changing from !disabled to disabled 87 self.assertEqual(self.widget.state(['disabled']), ('!disabled', )) 88 # no state change 89 self.assertEqual(self.widget.state(['disabled']), ()) 90 # change back to !disable but also active 91 self.assertEqual(self.widget.state(['!disabled', 'active']), 92 ('!active', 'disabled')) 93 # no state changes, again 94 self.assertEqual(self.widget.state(['!disabled', 'active']), ()) 95 self.assertEqual(self.widget.state(['active', '!disabled']), ()) 96 97 def test_cb(arg1, **kw): 98 return arg1, kw 99 self.assertEqual(self.widget.instate(['!disabled'], 100 test_cb, "hi", **{"msg": "there"}), 101 ('hi', {'msg': 'there'})) 102 103 # attempt to set invalid statespec 104 currstate = self.widget.state() 105 self.assertRaises(tkinter.TclError, self.widget.instate, 106 ['badstate']) 107 self.assertRaises(tkinter.TclError, self.widget.instate, 108 ['disabled', 'badstate']) 109 # verify that widget didn't change its state 110 self.assertEqual(currstate, self.widget.state()) 111 112 # ensuring that passing None as state doesn't modify current state 113 self.widget.state(['active', '!disabled']) 114 self.assertEqual(self.widget.state(), ('active', )) 115 116 117class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests): 118 _conv_pixels = noconv_meth 119 120 121@add_standard_options(StandardTtkOptionsTests) 122class FrameTest(AbstractToplevelTest, unittest.TestCase): 123 OPTIONS = ( 124 'borderwidth', 'class', 'cursor', 'height', 125 'padding', 'relief', 'style', 'takefocus', 126 'width', 127 ) 128 129 def create(self, **kwargs): 130 return ttk.Frame(self.root, **kwargs) 131 132 133@add_standard_options(StandardTtkOptionsTests) 134class LabelFrameTest(AbstractToplevelTest, unittest.TestCase): 135 OPTIONS = ( 136 'borderwidth', 'class', 'cursor', 'height', 137 'labelanchor', 'labelwidget', 138 'padding', 'relief', 'style', 'takefocus', 139 'text', 'underline', 'width', 140 ) 141 142 def create(self, **kwargs): 143 return ttk.LabelFrame(self.root, **kwargs) 144 145 def test_labelanchor(self): 146 widget = self.create() 147 self.checkEnumParam(widget, 'labelanchor', 148 'e', 'en', 'es', 'n', 'ne', 'nw', 's', 'se', 'sw', 'w', 'wn', 'ws', 149 errmsg='Bad label anchor specification {}') 150 self.checkInvalidParam(widget, 'labelanchor', 'center') 151 152 def test_labelwidget(self): 153 widget = self.create() 154 label = ttk.Label(self.root, text='Mupp', name='foo') 155 self.checkParam(widget, 'labelwidget', label, expected='.foo') 156 label.destroy() 157 158 159class AbstractLabelTest(AbstractWidgetTest): 160 161 def checkImageParam(self, widget, name): 162 image = tkinter.PhotoImage(master=self.root, name='image1') 163 image2 = tkinter.PhotoImage(master=self.root, name='image2') 164 self.checkParam(widget, name, image, expected=('image1',)) 165 self.checkParam(widget, name, 'image1', expected=('image1',)) 166 self.checkParam(widget, name, (image,), expected=('image1',)) 167 self.checkParam(widget, name, (image, 'active', image2), 168 expected=('image1', 'active', 'image2')) 169 self.checkParam(widget, name, 'image1 active image2', 170 expected=('image1', 'active', 'image2')) 171 self.checkInvalidParam(widget, name, 'spam', 172 errmsg='image "spam" doesn\'t exist') 173 174 def test_compound(self): 175 widget = self.create() 176 self.checkEnumParam(widget, 'compound', 177 'none', 'text', 'image', 'center', 178 'top', 'bottom', 'left', 'right') 179 180 def test_state(self): 181 widget = self.create() 182 self.checkParams(widget, 'state', 'active', 'disabled', 'normal') 183 184 def test_width(self): 185 widget = self.create() 186 self.checkParams(widget, 'width', 402, -402, 0) 187 188 189@add_standard_options(StandardTtkOptionsTests) 190class LabelTest(AbstractLabelTest, unittest.TestCase): 191 OPTIONS = ( 192 'anchor', 'background', 'borderwidth', 193 'class', 'compound', 'cursor', 'font', 'foreground', 194 'image', 'justify', 'padding', 'relief', 'state', 'style', 195 'takefocus', 'text', 'textvariable', 196 'underline', 'width', 'wraplength', 197 ) 198 _conv_pixels = noconv_meth 199 200 def create(self, **kwargs): 201 return ttk.Label(self.root, **kwargs) 202 203 def test_font(self): 204 widget = self.create() 205 self.checkParam(widget, 'font', 206 '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') 207 208 209@add_standard_options(StandardTtkOptionsTests) 210class ButtonTest(AbstractLabelTest, unittest.TestCase): 211 OPTIONS = ( 212 'class', 'command', 'compound', 'cursor', 'default', 213 'image', 'padding', 'state', 'style', 214 'takefocus', 'text', 'textvariable', 215 'underline', 'width', 216 ) 217 218 def create(self, **kwargs): 219 return ttk.Button(self.root, **kwargs) 220 221 def test_default(self): 222 widget = self.create() 223 self.checkEnumParam(widget, 'default', 'normal', 'active', 'disabled') 224 225 def test_invoke(self): 226 success = [] 227 btn = ttk.Button(self.root, command=lambda: success.append(1)) 228 btn.invoke() 229 self.assertTrue(success) 230 231 232@add_standard_options(StandardTtkOptionsTests) 233class CheckbuttonTest(AbstractLabelTest, unittest.TestCase): 234 OPTIONS = ( 235 'class', 'command', 'compound', 'cursor', 236 'image', 237 'offvalue', 'onvalue', 238 'padding', 'state', 'style', 239 'takefocus', 'text', 'textvariable', 240 'underline', 'variable', 'width', 241 ) 242 243 def create(self, **kwargs): 244 return ttk.Checkbutton(self.root, **kwargs) 245 246 def test_offvalue(self): 247 widget = self.create() 248 self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string') 249 250 def test_onvalue(self): 251 widget = self.create() 252 self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string') 253 254 def test_invoke(self): 255 success = [] 256 def cb_test(): 257 success.append(1) 258 return "cb test called" 259 260 cbtn = ttk.Checkbutton(self.root, command=cb_test) 261 # the variable automatically created by ttk.Checkbutton is actually 262 # undefined till we invoke the Checkbutton 263 self.assertEqual(cbtn.state(), ('alternate', )) 264 self.assertRaises(tkinter.TclError, cbtn.tk.globalgetvar, 265 cbtn['variable']) 266 267 res = cbtn.invoke() 268 self.assertEqual(res, "cb test called") 269 self.assertEqual(cbtn['onvalue'], 270 cbtn.tk.globalgetvar(cbtn['variable'])) 271 self.assertTrue(success) 272 273 cbtn['command'] = '' 274 res = cbtn.invoke() 275 self.assertFalse(str(res)) 276 self.assertLessEqual(len(success), 1) 277 self.assertEqual(cbtn['offvalue'], 278 cbtn.tk.globalgetvar(cbtn['variable'])) 279 280 281@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) 282class EntryTest(AbstractWidgetTest, unittest.TestCase): 283 OPTIONS = ( 284 'background', 'class', 'cursor', 285 'exportselection', 'font', 'foreground', 286 'invalidcommand', 'justify', 287 'show', 'state', 'style', 'takefocus', 'textvariable', 288 'validate', 'validatecommand', 'width', 'xscrollcommand', 289 ) 290 291 def setUp(self): 292 super(EntryTest, self).setUp() 293 self.entry = self.create() 294 295 def create(self, **kwargs): 296 return ttk.Entry(self.root, **kwargs) 297 298 def test_invalidcommand(self): 299 widget = self.create() 300 self.checkCommandParam(widget, 'invalidcommand') 301 302 def test_show(self): 303 widget = self.create() 304 self.checkParam(widget, 'show', '*') 305 self.checkParam(widget, 'show', '') 306 self.checkParam(widget, 'show', ' ') 307 308 def test_state(self): 309 widget = self.create() 310 self.checkParams(widget, 'state', 311 'disabled', 'normal', 'readonly') 312 313 def test_validate(self): 314 widget = self.create() 315 self.checkEnumParam(widget, 'validate', 316 'all', 'key', 'focus', 'focusin', 'focusout', 'none') 317 318 def test_validatecommand(self): 319 widget = self.create() 320 self.checkCommandParam(widget, 'validatecommand') 321 322 323 def test_bbox(self): 324 self.assertIsBoundingBox(self.entry.bbox(0)) 325 self.assertRaises(tkinter.TclError, self.entry.bbox, 'noindex') 326 self.assertRaises(tkinter.TclError, self.entry.bbox, None) 327 328 329 def test_identify(self): 330 self.entry.pack() 331 self.entry.wait_visibility() 332 self.entry.update_idletasks() 333 334 self.assertEqual(self.entry.identify(5, 5), "textarea") 335 self.assertEqual(self.entry.identify(-1, -1), "") 336 337 self.assertRaises(tkinter.TclError, self.entry.identify, None, 5) 338 self.assertRaises(tkinter.TclError, self.entry.identify, 5, None) 339 self.assertRaises(tkinter.TclError, self.entry.identify, 5, '') 340 341 342 def test_validation_options(self): 343 success = [] 344 test_invalid = lambda: success.append(True) 345 346 self.entry['validate'] = 'none' 347 self.entry['validatecommand'] = lambda: False 348 349 self.entry['invalidcommand'] = test_invalid 350 self.entry.validate() 351 self.assertTrue(success) 352 353 self.entry['invalidcommand'] = '' 354 self.entry.validate() 355 self.assertEqual(len(success), 1) 356 357 self.entry['invalidcommand'] = test_invalid 358 self.entry['validatecommand'] = lambda: True 359 self.entry.validate() 360 self.assertEqual(len(success), 1) 361 362 self.entry['validatecommand'] = '' 363 self.entry.validate() 364 self.assertEqual(len(success), 1) 365 366 self.entry['validatecommand'] = True 367 self.assertRaises(tkinter.TclError, self.entry.validate) 368 369 370 def test_validation(self): 371 validation = [] 372 def validate(to_insert): 373 if not 'a' <= to_insert.lower() <= 'z': 374 validation.append(False) 375 return False 376 validation.append(True) 377 return True 378 379 self.entry['validate'] = 'key' 380 self.entry['validatecommand'] = self.entry.register(validate), '%S' 381 382 self.entry.insert('end', 1) 383 self.entry.insert('end', 'a') 384 self.assertEqual(validation, [False, True]) 385 self.assertEqual(self.entry.get(), 'a') 386 387 388 def test_revalidation(self): 389 def validate(content): 390 for letter in content: 391 if not 'a' <= letter.lower() <= 'z': 392 return False 393 return True 394 395 self.entry['validatecommand'] = self.entry.register(validate), '%P' 396 397 self.entry.insert('end', 'avocado') 398 self.assertEqual(self.entry.validate(), True) 399 self.assertEqual(self.entry.state(), ()) 400 401 self.entry.delete(0, 'end') 402 self.assertEqual(self.entry.get(), '') 403 404 self.entry.insert('end', 'a1b') 405 self.assertEqual(self.entry.validate(), False) 406 self.assertEqual(self.entry.state(), ('invalid', )) 407 408 self.entry.delete(1) 409 self.assertEqual(self.entry.validate(), True) 410 self.assertEqual(self.entry.state(), ()) 411 412 413@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) 414class ComboboxTest(EntryTest, unittest.TestCase): 415 OPTIONS = ( 416 'background', 'class', 'cursor', 'exportselection', 417 'font', 'foreground', 'height', 'invalidcommand', 418 'justify', 'postcommand', 'show', 'state', 'style', 419 'takefocus', 'textvariable', 420 'validate', 'validatecommand', 'values', 421 'width', 'xscrollcommand', 422 ) 423 424 def setUp(self): 425 super(ComboboxTest, self).setUp() 426 self.combo = self.create() 427 428 def create(self, **kwargs): 429 return ttk.Combobox(self.root, **kwargs) 430 431 def test_height(self): 432 widget = self.create() 433 self.checkParams(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i') 434 435 def _show_drop_down_listbox(self): 436 width = self.combo.winfo_width() 437 self.combo.event_generate('<ButtonPress-1>', x=width - 5, y=5) 438 self.combo.event_generate('<ButtonRelease-1>', x=width - 5, y=5) 439 self.combo.update_idletasks() 440 441 442 def test_virtual_event(self): 443 success = [] 444 445 self.combo['values'] = [1] 446 self.combo.bind('<<ComboboxSelected>>', 447 lambda evt: success.append(True)) 448 self.combo.pack() 449 self.combo.wait_visibility() 450 451 height = self.combo.winfo_height() 452 self._show_drop_down_listbox() 453 self.combo.update() 454 self.combo.event_generate('<Return>') 455 self.combo.update() 456 457 self.assertTrue(success) 458 459 460 def test_postcommand(self): 461 success = [] 462 463 self.combo['postcommand'] = lambda: success.append(True) 464 self.combo.pack() 465 self.combo.wait_visibility() 466 467 self._show_drop_down_listbox() 468 self.assertTrue(success) 469 470 # testing postcommand removal 471 self.combo['postcommand'] = '' 472 self._show_drop_down_listbox() 473 self.assertEqual(len(success), 1) 474 475 476 def test_values(self): 477 def check_get_current(getval, currval): 478 self.assertEqual(self.combo.get(), getval) 479 self.assertEqual(self.combo.current(), currval) 480 481 self.assertEqual(self.combo['values'], 482 () if tcl_version < (8, 5) else '') 483 check_get_current('', -1) 484 485 self.checkParam(self.combo, 'values', 'mon tue wed thur', 486 expected=('mon', 'tue', 'wed', 'thur')) 487 self.checkParam(self.combo, 'values', ('mon', 'tue', 'wed', 'thur')) 488 self.checkParam(self.combo, 'values', (42, 3.14, '', 'any string')) 489 self.checkParam(self.combo, 'values', () if tcl_version < (8, 5) else '') 490 491 self.combo['values'] = ['a', 1, 'c'] 492 493 self.combo.set('c') 494 check_get_current('c', 2) 495 496 self.combo.current(0) 497 check_get_current('a', 0) 498 499 self.combo.set('d') 500 check_get_current('d', -1) 501 502 # testing values with empty string 503 self.combo.set('') 504 self.combo['values'] = (1, 2, '', 3) 505 check_get_current('', 2) 506 507 # testing values with empty string set through configure 508 self.combo.configure(values=[1, '', 2]) 509 self.assertEqual(self.combo['values'], 510 ('1', '', '2') if self.wantobjects else 511 '1 {} 2') 512 513 # testing values with spaces 514 self.combo['values'] = ['a b', 'a\tb', 'a\nb'] 515 self.assertEqual(self.combo['values'], 516 ('a b', 'a\tb', 'a\nb') if self.wantobjects else 517 '{a b} {a\tb} {a\nb}') 518 519 # testing values with special characters 520 self.combo['values'] = [r'a\tb', '"a"', '} {'] 521 self.assertEqual(self.combo['values'], 522 (r'a\tb', '"a"', '} {') if self.wantobjects else 523 r'a\\tb {"a"} \}\ \{') 524 525 # out of range 526 self.assertRaises(tkinter.TclError, self.combo.current, 527 len(self.combo['values'])) 528 # it expects an integer (or something that can be converted to int) 529 self.assertRaises(tkinter.TclError, self.combo.current, '') 530 531 # testing creating combobox with empty string in values 532 combo2 = ttk.Combobox(self.root, values=[1, 2, '']) 533 self.assertEqual(combo2['values'], 534 ('1', '2', '') if self.wantobjects else '1 2 {}') 535 combo2.destroy() 536 537 538@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) 539class PanedWindowTest(AbstractWidgetTest, unittest.TestCase): 540 OPTIONS = ( 541 'class', 'cursor', 'height', 542 'orient', 'style', 'takefocus', 'width', 543 ) 544 545 def setUp(self): 546 super(PanedWindowTest, self).setUp() 547 self.paned = self.create() 548 549 def create(self, **kwargs): 550 return ttk.PanedWindow(self.root, **kwargs) 551 552 def test_orient(self): 553 widget = self.create() 554 self.assertEqual(str(widget['orient']), 'vertical') 555 errmsg='attempt to change read-only option' 556 if get_tk_patchlevel() < (8, 6, 0, 'beta', 3): 557 errmsg='Attempt to change read-only option' 558 self.checkInvalidParam(widget, 'orient', 'horizontal', 559 errmsg=errmsg) 560 widget2 = self.create(orient='horizontal') 561 self.assertEqual(str(widget2['orient']), 'horizontal') 562 563 def test_add(self): 564 # attempt to add a child that is not a direct child of the paned window 565 label = ttk.Label(self.paned) 566 child = ttk.Label(label) 567 self.assertRaises(tkinter.TclError, self.paned.add, child) 568 label.destroy() 569 child.destroy() 570 # another attempt 571 label = ttk.Label(self.root) 572 child = ttk.Label(label) 573 self.assertRaises(tkinter.TclError, self.paned.add, child) 574 child.destroy() 575 label.destroy() 576 577 good_child = ttk.Label(self.root) 578 self.paned.add(good_child) 579 # re-adding a child is not accepted 580 self.assertRaises(tkinter.TclError, self.paned.add, good_child) 581 582 other_child = ttk.Label(self.paned) 583 self.paned.add(other_child) 584 self.assertEqual(self.paned.pane(0), self.paned.pane(1)) 585 self.assertRaises(tkinter.TclError, self.paned.pane, 2) 586 good_child.destroy() 587 other_child.destroy() 588 self.assertRaises(tkinter.TclError, self.paned.pane, 0) 589 590 591 def test_forget(self): 592 self.assertRaises(tkinter.TclError, self.paned.forget, None) 593 self.assertRaises(tkinter.TclError, self.paned.forget, 0) 594 595 self.paned.add(ttk.Label(self.root)) 596 self.paned.forget(0) 597 self.assertRaises(tkinter.TclError, self.paned.forget, 0) 598 599 600 def test_insert(self): 601 self.assertRaises(tkinter.TclError, self.paned.insert, None, 0) 602 self.assertRaises(tkinter.TclError, self.paned.insert, 0, None) 603 self.assertRaises(tkinter.TclError, self.paned.insert, 0, 0) 604 605 child = ttk.Label(self.root) 606 child2 = ttk.Label(self.root) 607 child3 = ttk.Label(self.root) 608 609 self.assertRaises(tkinter.TclError, self.paned.insert, 0, child) 610 611 self.paned.insert('end', child2) 612 self.paned.insert(0, child) 613 self.assertEqual(self.paned.panes(), (str(child), str(child2))) 614 615 self.paned.insert(0, child2) 616 self.assertEqual(self.paned.panes(), (str(child2), str(child))) 617 618 self.paned.insert('end', child3) 619 self.assertEqual(self.paned.panes(), 620 (str(child2), str(child), str(child3))) 621 622 # reinserting a child should move it to its current position 623 panes = self.paned.panes() 624 self.paned.insert('end', child3) 625 self.assertEqual(panes, self.paned.panes()) 626 627 # moving child3 to child2 position should result in child2 ending up 628 # in previous child position and child ending up in previous child3 629 # position 630 self.paned.insert(child2, child3) 631 self.assertEqual(self.paned.panes(), 632 (str(child3), str(child2), str(child))) 633 634 635 def test_pane(self): 636 self.assertRaises(tkinter.TclError, self.paned.pane, 0) 637 638 child = ttk.Label(self.root) 639 self.paned.add(child) 640 self.assertIsInstance(self.paned.pane(0), dict) 641 self.assertEqual(self.paned.pane(0, weight=None), 642 0 if self.wantobjects else '0') 643 # newer form for querying a single option 644 self.assertEqual(self.paned.pane(0, 'weight'), 645 0 if self.wantobjects else '0') 646 self.assertEqual(self.paned.pane(0), self.paned.pane(str(child))) 647 648 self.assertRaises(tkinter.TclError, self.paned.pane, 0, 649 badoption='somevalue') 650 651 652 def test_sashpos(self): 653 self.assertRaises(tkinter.TclError, self.paned.sashpos, None) 654 self.assertRaises(tkinter.TclError, self.paned.sashpos, '') 655 self.assertRaises(tkinter.TclError, self.paned.sashpos, 0) 656 657 child = ttk.Label(self.paned, text='a') 658 self.paned.add(child, weight=1) 659 self.assertRaises(tkinter.TclError, self.paned.sashpos, 0) 660 child2 = ttk.Label(self.paned, text='b') 661 self.paned.add(child2) 662 self.assertRaises(tkinter.TclError, self.paned.sashpos, 1) 663 664 self.paned.pack(expand=True, fill='both') 665 self.paned.wait_visibility() 666 667 curr_pos = self.paned.sashpos(0) 668 self.paned.sashpos(0, 1000) 669 self.assertNotEqual(curr_pos, self.paned.sashpos(0)) 670 self.assertIsInstance(self.paned.sashpos(0), int) 671 672 673@add_standard_options(StandardTtkOptionsTests) 674class RadiobuttonTest(AbstractLabelTest, unittest.TestCase): 675 OPTIONS = ( 676 'class', 'command', 'compound', 'cursor', 677 'image', 678 'padding', 'state', 'style', 679 'takefocus', 'text', 'textvariable', 680 'underline', 'value', 'variable', 'width', 681 ) 682 683 def create(self, **kwargs): 684 return ttk.Radiobutton(self.root, **kwargs) 685 686 def test_value(self): 687 widget = self.create() 688 self.checkParams(widget, 'value', 1, 2.3, '', 'any string') 689 690 def test_invoke(self): 691 success = [] 692 def cb_test(): 693 success.append(1) 694 return "cb test called" 695 696 myvar = tkinter.IntVar(self.root) 697 cbtn = ttk.Radiobutton(self.root, command=cb_test, 698 variable=myvar, value=0) 699 cbtn2 = ttk.Radiobutton(self.root, command=cb_test, 700 variable=myvar, value=1) 701 702 if self.wantobjects: 703 conv = lambda x: x 704 else: 705 conv = int 706 707 res = cbtn.invoke() 708 self.assertEqual(res, "cb test called") 709 self.assertEqual(conv(cbtn['value']), myvar.get()) 710 self.assertEqual(myvar.get(), 711 conv(cbtn.tk.globalgetvar(cbtn['variable']))) 712 self.assertTrue(success) 713 714 cbtn2['command'] = '' 715 res = cbtn2.invoke() 716 self.assertEqual(str(res), '') 717 self.assertLessEqual(len(success), 1) 718 self.assertEqual(conv(cbtn2['value']), myvar.get()) 719 self.assertEqual(myvar.get(), 720 conv(cbtn.tk.globalgetvar(cbtn['variable']))) 721 722 self.assertEqual(str(cbtn['variable']), str(cbtn2['variable'])) 723 724 725class MenubuttonTest(AbstractLabelTest, unittest.TestCase): 726 OPTIONS = ( 727 'class', 'compound', 'cursor', 'direction', 728 'image', 'menu', 'padding', 'state', 'style', 729 'takefocus', 'text', 'textvariable', 730 'underline', 'width', 731 ) 732 733 def create(self, **kwargs): 734 return ttk.Menubutton(self.root, **kwargs) 735 736 def test_direction(self): 737 widget = self.create() 738 self.checkEnumParam(widget, 'direction', 739 'above', 'below', 'left', 'right', 'flush') 740 741 def test_menu(self): 742 widget = self.create() 743 menu = tkinter.Menu(widget, name='menu') 744 self.checkParam(widget, 'menu', menu, conv=str) 745 menu.destroy() 746 747 748@add_standard_options(StandardTtkOptionsTests) 749class ScaleTest(AbstractWidgetTest, unittest.TestCase): 750 OPTIONS = ( 751 'class', 'command', 'cursor', 'from', 'length', 752 'orient', 'style', 'takefocus', 'to', 'value', 'variable', 753 ) 754 _conv_pixels = noconv_meth 755 default_orient = 'horizontal' 756 757 def setUp(self): 758 super(ScaleTest, self).setUp() 759 self.scale = self.create() 760 self.scale.pack() 761 self.scale.update() 762 763 def create(self, **kwargs): 764 return ttk.Scale(self.root, **kwargs) 765 766 def test_from(self): 767 widget = self.create() 768 self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=False) 769 770 def test_length(self): 771 widget = self.create() 772 self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i') 773 774 def test_to(self): 775 widget = self.create() 776 self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10, conv=False) 777 778 def test_value(self): 779 widget = self.create() 780 self.checkFloatParam(widget, 'value', 300, 14.9, 15.1, -10, conv=False) 781 782 def test_custom_event(self): 783 failure = [1, 1, 1] # will need to be empty 784 785 funcid = self.scale.bind('<<RangeChanged>>', lambda evt: failure.pop()) 786 787 self.scale['from'] = 10 788 self.scale['from_'] = 10 789 self.scale['to'] = 3 790 791 self.assertFalse(failure) 792 793 failure = [1, 1, 1] 794 self.scale.configure(from_=2, to=5) 795 self.scale.configure(from_=0, to=-2) 796 self.scale.configure(to=10) 797 798 self.assertFalse(failure) 799 800 801 def test_get(self): 802 if self.wantobjects: 803 conv = lambda x: x 804 else: 805 conv = float 806 807 scale_width = self.scale.winfo_width() 808 self.assertEqual(self.scale.get(scale_width, 0), self.scale['to']) 809 810 self.assertEqual(conv(self.scale.get(0, 0)), conv(self.scale['from'])) 811 self.assertEqual(self.scale.get(), self.scale['value']) 812 self.scale['value'] = 30 813 self.assertEqual(self.scale.get(), self.scale['value']) 814 815 self.assertRaises(tkinter.TclError, self.scale.get, '', 0) 816 self.assertRaises(tkinter.TclError, self.scale.get, 0, '') 817 818 819 def test_set(self): 820 if self.wantobjects: 821 conv = lambda x: x 822 else: 823 conv = float 824 825 # set restricts the max/min values according to the current range 826 max = conv(self.scale['to']) 827 new_max = max + 10 828 self.scale.set(new_max) 829 self.assertEqual(conv(self.scale.get()), max) 830 min = conv(self.scale['from']) 831 self.scale.set(min - 1) 832 self.assertEqual(conv(self.scale.get()), min) 833 834 # changing directly the variable doesn't impose this limitation tho 835 var = tkinter.DoubleVar(self.root) 836 self.scale['variable'] = var 837 var.set(max + 5) 838 self.assertEqual(conv(self.scale.get()), var.get()) 839 self.assertEqual(conv(self.scale.get()), max + 5) 840 del var 841 842 # the same happens with the value option 843 self.scale['value'] = max + 10 844 self.assertEqual(conv(self.scale.get()), max + 10) 845 self.assertEqual(conv(self.scale.get()), conv(self.scale['value'])) 846 847 # nevertheless, note that the max/min values we can get specifying 848 # x, y coords are the ones according to the current range 849 self.assertEqual(conv(self.scale.get(0, 0)), min) 850 self.assertEqual(conv(self.scale.get(self.scale.winfo_width(), 0)), max) 851 852 self.assertRaises(tkinter.TclError, self.scale.set, None) 853 854 855@add_standard_options(StandardTtkOptionsTests) 856class ProgressbarTest(AbstractWidgetTest, unittest.TestCase): 857 OPTIONS = ( 858 'class', 'cursor', 'orient', 'length', 859 'mode', 'maximum', 'phase', 860 'style', 'takefocus', 'value', 'variable', 861 ) 862 _conv_pixels = noconv_meth 863 default_orient = 'horizontal' 864 865 def create(self, **kwargs): 866 return ttk.Progressbar(self.root, **kwargs) 867 868 def test_length(self): 869 widget = self.create() 870 self.checkPixelsParam(widget, 'length', 100.1, 56.7, '2i') 871 872 def test_maximum(self): 873 widget = self.create() 874 self.checkFloatParam(widget, 'maximum', 150.2, 77.7, 0, -10, conv=False) 875 876 def test_mode(self): 877 widget = self.create() 878 self.checkEnumParam(widget, 'mode', 'determinate', 'indeterminate') 879 880 def test_phase(self): 881 # XXX 882 pass 883 884 def test_value(self): 885 widget = self.create() 886 self.checkFloatParam(widget, 'value', 150.2, 77.7, 0, -10, 887 conv=False) 888 889 890@unittest.skipIf(sys.platform == 'darwin', 891 'ttk.Scrollbar is special on MacOSX') 892@add_standard_options(StandardTtkOptionsTests) 893class ScrollbarTest(AbstractWidgetTest, unittest.TestCase): 894 OPTIONS = ( 895 'class', 'command', 'cursor', 'orient', 'style', 'takefocus', 896 ) 897 default_orient = 'vertical' 898 899 def create(self, **kwargs): 900 return ttk.Scrollbar(self.root, **kwargs) 901 902 903@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) 904class NotebookTest(AbstractWidgetTest, unittest.TestCase): 905 OPTIONS = ( 906 'class', 'cursor', 'height', 'padding', 'style', 'takefocus', 'width', 907 ) 908 909 def setUp(self): 910 super(NotebookTest, self).setUp() 911 self.nb = self.create(padding=0) 912 self.child1 = ttk.Label(self.root) 913 self.child2 = ttk.Label(self.root) 914 self.nb.add(self.child1, text='a') 915 self.nb.add(self.child2, text='b') 916 917 def create(self, **kwargs): 918 return ttk.Notebook(self.root, **kwargs) 919 920 def test_tab_identifiers(self): 921 self.nb.forget(0) 922 self.nb.hide(self.child2) 923 self.assertRaises(tkinter.TclError, self.nb.tab, self.child1) 924 self.assertEqual(self.nb.index('end'), 1) 925 self.nb.add(self.child2) 926 self.assertEqual(self.nb.index('end'), 1) 927 self.nb.select(self.child2) 928 929 self.assertTrue(self.nb.tab('current')) 930 self.nb.add(self.child1, text='a') 931 932 self.nb.pack() 933 self.nb.wait_visibility() 934 if sys.platform == 'darwin': 935 tb_idx = "@20,5" 936 else: 937 tb_idx = "@5,5" 938 self.assertEqual(self.nb.tab(tb_idx), self.nb.tab('current')) 939 940 for i in range(5, 100, 5): 941 try: 942 if self.nb.tab('@%d, 5' % i, text=None) == 'a': 943 break 944 except tkinter.TclError: 945 pass 946 947 else: 948 self.fail("Tab with text 'a' not found") 949 950 951 def test_add_and_hidden(self): 952 self.assertRaises(tkinter.TclError, self.nb.hide, -1) 953 self.assertRaises(tkinter.TclError, self.nb.hide, 'hi') 954 self.assertRaises(tkinter.TclError, self.nb.hide, None) 955 self.assertRaises(tkinter.TclError, self.nb.add, None) 956 self.assertRaises(tkinter.TclError, self.nb.add, ttk.Label(self.root), 957 unknown='option') 958 959 tabs = self.nb.tabs() 960 self.nb.hide(self.child1) 961 self.nb.add(self.child1) 962 self.assertEqual(self.nb.tabs(), tabs) 963 964 child = ttk.Label(self.root) 965 self.nb.add(child, text='c') 966 tabs = self.nb.tabs() 967 968 curr = self.nb.index('current') 969 # verify that the tab gets readded at its previous position 970 child2_index = self.nb.index(self.child2) 971 self.nb.hide(self.child2) 972 self.nb.add(self.child2) 973 self.assertEqual(self.nb.tabs(), tabs) 974 self.assertEqual(self.nb.index(self.child2), child2_index) 975 self.assertEqual(str(self.child2), self.nb.tabs()[child2_index]) 976 # but the tab next to it (not hidden) is the one selected now 977 self.assertEqual(self.nb.index('current'), curr + 1) 978 979 980 def test_forget(self): 981 self.assertRaises(tkinter.TclError, self.nb.forget, -1) 982 self.assertRaises(tkinter.TclError, self.nb.forget, 'hi') 983 self.assertRaises(tkinter.TclError, self.nb.forget, None) 984 985 tabs = self.nb.tabs() 986 child1_index = self.nb.index(self.child1) 987 self.nb.forget(self.child1) 988 self.assertNotIn(str(self.child1), self.nb.tabs()) 989 self.assertEqual(len(tabs) - 1, len(self.nb.tabs())) 990 991 self.nb.add(self.child1) 992 self.assertEqual(self.nb.index(self.child1), 1) 993 self.assertNotEqual(child1_index, self.nb.index(self.child1)) 994 995 996 def test_index(self): 997 self.assertRaises(tkinter.TclError, self.nb.index, -1) 998 self.assertRaises(tkinter.TclError, self.nb.index, None) 999 1000 self.assertIsInstance(self.nb.index('end'), int) 1001 self.assertEqual(self.nb.index(self.child1), 0) 1002 self.assertEqual(self.nb.index(self.child2), 1) 1003 self.assertEqual(self.nb.index('end'), 2) 1004 1005 1006 def test_insert(self): 1007 # moving tabs 1008 tabs = self.nb.tabs() 1009 self.nb.insert(1, tabs[0]) 1010 self.assertEqual(self.nb.tabs(), (tabs[1], tabs[0])) 1011 self.nb.insert(self.child1, self.child2) 1012 self.assertEqual(self.nb.tabs(), tabs) 1013 self.nb.insert('end', self.child1) 1014 self.assertEqual(self.nb.tabs(), (tabs[1], tabs[0])) 1015 self.nb.insert('end', 0) 1016 self.assertEqual(self.nb.tabs(), tabs) 1017 # bad moves 1018 self.assertRaises(tkinter.TclError, self.nb.insert, 2, tabs[0]) 1019 self.assertRaises(tkinter.TclError, self.nb.insert, -1, tabs[0]) 1020 1021 # new tab 1022 child3 = ttk.Label(self.root) 1023 self.nb.insert(1, child3) 1024 self.assertEqual(self.nb.tabs(), (tabs[0], str(child3), tabs[1])) 1025 self.nb.forget(child3) 1026 self.assertEqual(self.nb.tabs(), tabs) 1027 self.nb.insert(self.child1, child3) 1028 self.assertEqual(self.nb.tabs(), (str(child3), ) + tabs) 1029 self.nb.forget(child3) 1030 self.assertRaises(tkinter.TclError, self.nb.insert, 2, child3) 1031 self.assertRaises(tkinter.TclError, self.nb.insert, -1, child3) 1032 1033 # bad inserts 1034 self.assertRaises(tkinter.TclError, self.nb.insert, 'end', None) 1035 self.assertRaises(tkinter.TclError, self.nb.insert, None, 0) 1036 self.assertRaises(tkinter.TclError, self.nb.insert, None, None) 1037 1038 1039 def test_select(self): 1040 self.nb.pack() 1041 self.nb.wait_visibility() 1042 1043 success = [] 1044 tab_changed = [] 1045 1046 self.child1.bind('<Unmap>', lambda evt: success.append(True)) 1047 self.nb.bind('<<NotebookTabChanged>>', 1048 lambda evt: tab_changed.append(True)) 1049 1050 self.assertEqual(self.nb.select(), str(self.child1)) 1051 self.nb.select(self.child2) 1052 self.assertTrue(success) 1053 self.assertEqual(self.nb.select(), str(self.child2)) 1054 1055 self.nb.update() 1056 self.assertTrue(tab_changed) 1057 1058 1059 def test_tab(self): 1060 self.assertRaises(tkinter.TclError, self.nb.tab, -1) 1061 self.assertRaises(tkinter.TclError, self.nb.tab, 'notab') 1062 self.assertRaises(tkinter.TclError, self.nb.tab, None) 1063 1064 self.assertIsInstance(self.nb.tab(self.child1), dict) 1065 self.assertEqual(self.nb.tab(self.child1, text=None), 'a') 1066 # newer form for querying a single option 1067 self.assertEqual(self.nb.tab(self.child1, 'text'), 'a') 1068 self.nb.tab(self.child1, text='abc') 1069 self.assertEqual(self.nb.tab(self.child1, text=None), 'abc') 1070 self.assertEqual(self.nb.tab(self.child1, 'text'), 'abc') 1071 1072 1073 def test_tabs(self): 1074 self.assertEqual(len(self.nb.tabs()), 2) 1075 1076 self.nb.forget(self.child1) 1077 self.nb.forget(self.child2) 1078 1079 self.assertEqual(self.nb.tabs(), ()) 1080 1081 1082 def test_traversal(self): 1083 self.nb.pack() 1084 self.nb.wait_visibility() 1085 1086 self.nb.select(0) 1087 1088 simulate_mouse_click(self.nb, 5, 5) 1089 self.nb.focus_force() 1090 self.nb.event_generate('<Control-Tab>') 1091 self.assertEqual(self.nb.select(), str(self.child2)) 1092 self.nb.focus_force() 1093 self.nb.event_generate('<Shift-Control-Tab>') 1094 self.assertEqual(self.nb.select(), str(self.child1)) 1095 self.nb.focus_force() 1096 self.nb.event_generate('<Shift-Control-Tab>') 1097 self.assertEqual(self.nb.select(), str(self.child2)) 1098 1099 self.nb.tab(self.child1, text='a', underline=0) 1100 self.nb.enable_traversal() 1101 self.nb.focus_force() 1102 simulate_mouse_click(self.nb, 5, 5) 1103 if sys.platform == 'darwin': 1104 self.nb.event_generate('<Option-a>') 1105 else: 1106 self.nb.event_generate('<Alt-a>') 1107 self.assertEqual(self.nb.select(), str(self.child1)) 1108 1109 1110@add_standard_options(StandardTtkOptionsTests) 1111class TreeviewTest(AbstractWidgetTest, unittest.TestCase): 1112 OPTIONS = ( 1113 'class', 'columns', 'cursor', 'displaycolumns', 1114 'height', 'padding', 'selectmode', 'show', 1115 'style', 'takefocus', 'xscrollcommand', 'yscrollcommand', 1116 ) 1117 1118 def setUp(self): 1119 super(TreeviewTest, self).setUp() 1120 self.tv = self.create(padding=0) 1121 1122 def create(self, **kwargs): 1123 return ttk.Treeview(self.root, **kwargs) 1124 1125 def test_columns(self): 1126 widget = self.create() 1127 self.checkParam(widget, 'columns', 'a b c', 1128 expected=('a', 'b', 'c')) 1129 self.checkParam(widget, 'columns', ('a', 'b', 'c')) 1130 self.checkParam(widget, 'columns', () if tcl_version < (8, 5) else '') 1131 1132 def test_displaycolumns(self): 1133 widget = self.create() 1134 widget['columns'] = ('a', 'b', 'c') 1135 self.checkParam(widget, 'displaycolumns', 'b a c', 1136 expected=('b', 'a', 'c')) 1137 self.checkParam(widget, 'displaycolumns', ('b', 'a', 'c')) 1138 self.checkParam(widget, 'displaycolumns', '#all', 1139 expected=('#all',)) 1140 self.checkParam(widget, 'displaycolumns', (2, 1, 0)) 1141 self.checkInvalidParam(widget, 'displaycolumns', ('a', 'b', 'd'), 1142 errmsg='Invalid column index d') 1143 self.checkInvalidParam(widget, 'displaycolumns', (1, 2, 3), 1144 errmsg='Column index 3 out of bounds') 1145 self.checkInvalidParam(widget, 'displaycolumns', (1, -2), 1146 errmsg='Column index -2 out of bounds') 1147 1148 def test_height(self): 1149 widget = self.create() 1150 self.checkPixelsParam(widget, 'height', 100, -100, 0, '3c', conv=False) 1151 self.checkPixelsParam(widget, 'height', 101.2, 102.6, conv=noconv) 1152 1153 def test_selectmode(self): 1154 widget = self.create() 1155 self.checkEnumParam(widget, 'selectmode', 1156 'none', 'browse', 'extended') 1157 1158 def test_show(self): 1159 widget = self.create() 1160 self.checkParam(widget, 'show', 'tree headings', 1161 expected=('tree', 'headings')) 1162 self.checkParam(widget, 'show', ('tree', 'headings')) 1163 self.checkParam(widget, 'show', ('headings', 'tree')) 1164 self.checkParam(widget, 'show', 'tree', expected=('tree',)) 1165 self.checkParam(widget, 'show', 'headings', expected=('headings',)) 1166 1167 def test_bbox(self): 1168 self.tv.pack() 1169 self.assertEqual(self.tv.bbox(''), '') 1170 self.tv.wait_visibility() 1171 self.tv.update() 1172 1173 item_id = self.tv.insert('', 'end') 1174 children = self.tv.get_children() 1175 self.assertTrue(children) 1176 1177 bbox = self.tv.bbox(children[0]) 1178 self.assertIsBoundingBox(bbox) 1179 1180 # compare width in bboxes 1181 self.tv['columns'] = ['test'] 1182 self.tv.column('test', width=50) 1183 bbox_column0 = self.tv.bbox(children[0], 0) 1184 root_width = self.tv.column('#0', width=None) 1185 if not self.wantobjects: 1186 root_width = int(root_width) 1187 self.assertEqual(bbox_column0[0], bbox[0] + root_width) 1188 1189 # verify that bbox of a closed item is the empty string 1190 child1 = self.tv.insert(item_id, 'end') 1191 self.assertEqual(self.tv.bbox(child1), '') 1192 1193 1194 def test_children(self): 1195 # no children yet, should get an empty tuple 1196 self.assertEqual(self.tv.get_children(), ()) 1197 1198 item_id = self.tv.insert('', 'end') 1199 self.assertIsInstance(self.tv.get_children(), tuple) 1200 self.assertEqual(self.tv.get_children()[0], item_id) 1201 1202 # add item_id and child3 as children of child2 1203 child2 = self.tv.insert('', 'end') 1204 child3 = self.tv.insert('', 'end') 1205 self.tv.set_children(child2, item_id, child3) 1206 self.assertEqual(self.tv.get_children(child2), (item_id, child3)) 1207 1208 # child3 has child2 as parent, thus trying to set child2 as a children 1209 # of child3 should result in an error 1210 self.assertRaises(tkinter.TclError, 1211 self.tv.set_children, child3, child2) 1212 1213 # remove child2 children 1214 self.tv.set_children(child2) 1215 self.assertEqual(self.tv.get_children(child2), ()) 1216 1217 # remove root's children 1218 self.tv.set_children('') 1219 self.assertEqual(self.tv.get_children(), ()) 1220 1221 1222 def test_column(self): 1223 # return a dict with all options/values 1224 self.assertIsInstance(self.tv.column('#0'), dict) 1225 # return a single value of the given option 1226 if self.wantobjects: 1227 self.assertIsInstance(self.tv.column('#0', width=None), int) 1228 # set a new value for an option 1229 self.tv.column('#0', width=10) 1230 # testing new way to get option value 1231 self.assertEqual(self.tv.column('#0', 'width'), 1232 10 if self.wantobjects else '10') 1233 self.assertEqual(self.tv.column('#0', width=None), 1234 10 if self.wantobjects else '10') 1235 # check read-only option 1236 self.assertRaises(tkinter.TclError, self.tv.column, '#0', id='X') 1237 1238 self.assertRaises(tkinter.TclError, self.tv.column, 'invalid') 1239 invalid_kws = [ 1240 {'unknown_option': 'some value'}, {'stretch': 'wrong'}, 1241 {'anchor': 'wrong'}, {'width': 'wrong'}, {'minwidth': 'wrong'} 1242 ] 1243 for kw in invalid_kws: 1244 self.assertRaises(tkinter.TclError, self.tv.column, '#0', 1245 **kw) 1246 1247 1248 def test_delete(self): 1249 self.assertRaises(tkinter.TclError, self.tv.delete, '#0') 1250 1251 item_id = self.tv.insert('', 'end') 1252 item2 = self.tv.insert(item_id, 'end') 1253 self.assertEqual(self.tv.get_children(), (item_id, )) 1254 self.assertEqual(self.tv.get_children(item_id), (item2, )) 1255 1256 self.tv.delete(item_id) 1257 self.assertFalse(self.tv.get_children()) 1258 1259 # reattach should fail 1260 self.assertRaises(tkinter.TclError, 1261 self.tv.reattach, item_id, '', 'end') 1262 1263 # test multiple item delete 1264 item1 = self.tv.insert('', 'end') 1265 item2 = self.tv.insert('', 'end') 1266 self.assertEqual(self.tv.get_children(), (item1, item2)) 1267 1268 self.tv.delete(item1, item2) 1269 self.assertFalse(self.tv.get_children()) 1270 1271 1272 def test_detach_reattach(self): 1273 item_id = self.tv.insert('', 'end') 1274 item2 = self.tv.insert(item_id, 'end') 1275 1276 # calling detach without items is valid, although it does nothing 1277 prev = self.tv.get_children() 1278 self.tv.detach() # this should do nothing 1279 self.assertEqual(prev, self.tv.get_children()) 1280 1281 self.assertEqual(self.tv.get_children(), (item_id, )) 1282 self.assertEqual(self.tv.get_children(item_id), (item2, )) 1283 1284 # detach item with children 1285 self.tv.detach(item_id) 1286 self.assertFalse(self.tv.get_children()) 1287 1288 # reattach item with children 1289 self.tv.reattach(item_id, '', 'end') 1290 self.assertEqual(self.tv.get_children(), (item_id, )) 1291 self.assertEqual(self.tv.get_children(item_id), (item2, )) 1292 1293 # move a children to the root 1294 self.tv.move(item2, '', 'end') 1295 self.assertEqual(self.tv.get_children(), (item_id, item2)) 1296 self.assertEqual(self.tv.get_children(item_id), ()) 1297 1298 # bad values 1299 self.assertRaises(tkinter.TclError, 1300 self.tv.reattach, 'nonexistent', '', 'end') 1301 self.assertRaises(tkinter.TclError, 1302 self.tv.detach, 'nonexistent') 1303 self.assertRaises(tkinter.TclError, 1304 self.tv.reattach, item2, 'otherparent', 'end') 1305 self.assertRaises(tkinter.TclError, 1306 self.tv.reattach, item2, '', 'invalid') 1307 1308 # multiple detach 1309 self.tv.detach(item_id, item2) 1310 self.assertEqual(self.tv.get_children(), ()) 1311 self.assertEqual(self.tv.get_children(item_id), ()) 1312 1313 1314 def test_exists(self): 1315 self.assertEqual(self.tv.exists('something'), False) 1316 self.assertEqual(self.tv.exists(''), True) 1317 self.assertEqual(self.tv.exists({}), False) 1318 1319 # the following will make a tk.call equivalent to 1320 # tk.call(treeview, "exists") which should result in an error 1321 # in the tcl interpreter since tk requires an item. 1322 self.assertRaises(tkinter.TclError, self.tv.exists, None) 1323 1324 1325 def test_focus(self): 1326 # nothing is focused right now 1327 self.assertEqual(self.tv.focus(), '') 1328 1329 item1 = self.tv.insert('', 'end') 1330 self.tv.focus(item1) 1331 self.assertEqual(self.tv.focus(), item1) 1332 1333 self.tv.delete(item1) 1334 self.assertEqual(self.tv.focus(), '') 1335 1336 # try focusing inexistent item 1337 self.assertRaises(tkinter.TclError, self.tv.focus, 'hi') 1338 1339 1340 def test_heading(self): 1341 # check a dict is returned 1342 self.assertIsInstance(self.tv.heading('#0'), dict) 1343 1344 # check a value is returned 1345 self.tv.heading('#0', text='hi') 1346 self.assertEqual(self.tv.heading('#0', 'text'), 'hi') 1347 self.assertEqual(self.tv.heading('#0', text=None), 'hi') 1348 1349 # invalid option 1350 self.assertRaises(tkinter.TclError, self.tv.heading, '#0', 1351 background=None) 1352 # invalid value 1353 self.assertRaises(tkinter.TclError, self.tv.heading, '#0', 1354 anchor=1) 1355 1356 def test_heading_callback(self): 1357 def simulate_heading_click(x, y): 1358 simulate_mouse_click(self.tv, x, y) 1359 self.tv.update() 1360 1361 success = [] # no success for now 1362 1363 self.tv.pack() 1364 self.tv.wait_visibility() 1365 self.tv.heading('#0', command=lambda: success.append(True)) 1366 self.tv.column('#0', width=100) 1367 self.tv.update() 1368 1369 # assuming that the coords (5, 5) fall into heading #0 1370 simulate_heading_click(5, 5) 1371 if not success: 1372 self.fail("The command associated to the treeview heading wasn't " 1373 "invoked.") 1374 1375 success = [] 1376 commands = self.tv.master._tclCommands 1377 self.tv.heading('#0', command=str(self.tv.heading('#0', command=None))) 1378 self.assertEqual(commands, self.tv.master._tclCommands) 1379 simulate_heading_click(5, 5) 1380 if not success: 1381 self.fail("The command associated to the treeview heading wasn't " 1382 "invoked.") 1383 1384 # XXX The following raises an error in a tcl interpreter, but not in 1385 # Python 1386 #self.tv.heading('#0', command='I dont exist') 1387 #simulate_heading_click(5, 5) 1388 1389 1390 def test_index(self): 1391 # item 'what' doesn't exist 1392 self.assertRaises(tkinter.TclError, self.tv.index, 'what') 1393 1394 self.assertEqual(self.tv.index(''), 0) 1395 1396 item1 = self.tv.insert('', 'end') 1397 item2 = self.tv.insert('', 'end') 1398 c1 = self.tv.insert(item1, 'end') 1399 c2 = self.tv.insert(item1, 'end') 1400 self.assertEqual(self.tv.index(item1), 0) 1401 self.assertEqual(self.tv.index(c1), 0) 1402 self.assertEqual(self.tv.index(c2), 1) 1403 self.assertEqual(self.tv.index(item2), 1) 1404 1405 self.tv.move(item2, '', 0) 1406 self.assertEqual(self.tv.index(item2), 0) 1407 self.assertEqual(self.tv.index(item1), 1) 1408 1409 # check that index still works even after its parent and siblings 1410 # have been detached 1411 self.tv.detach(item1) 1412 self.assertEqual(self.tv.index(c2), 1) 1413 self.tv.detach(c1) 1414 self.assertEqual(self.tv.index(c2), 0) 1415 1416 # but it fails after item has been deleted 1417 self.tv.delete(item1) 1418 self.assertRaises(tkinter.TclError, self.tv.index, c2) 1419 1420 1421 def test_insert_item(self): 1422 # parent 'none' doesn't exist 1423 self.assertRaises(tkinter.TclError, self.tv.insert, 'none', 'end') 1424 1425 # open values 1426 self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', 1427 open='') 1428 self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', 1429 open='please') 1430 self.assertFalse(self.tv.delete(self.tv.insert('', 'end', open=True))) 1431 self.assertFalse(self.tv.delete(self.tv.insert('', 'end', open=False))) 1432 1433 # invalid index 1434 self.assertRaises(tkinter.TclError, self.tv.insert, '', 'middle') 1435 1436 # trying to duplicate item id is invalid 1437 itemid = self.tv.insert('', 'end', 'first-item') 1438 self.assertEqual(itemid, 'first-item') 1439 self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', 1440 'first-item') 1441 self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', 1442 MockTclObj('first-item')) 1443 1444 # unicode values 1445 value = u'\xe1ba' 1446 item = self.tv.insert('', 'end', values=(value, )) 1447 self.assertEqual(self.tv.item(item, 'values'), 1448 (value,) if self.wantobjects else value) 1449 self.assertEqual(self.tv.item(item, values=None), 1450 (value,) if self.wantobjects else value) 1451 1452 self.tv.item(item, values=self.root.splitlist(self.tv.item(item, values=None))) 1453 self.assertEqual(self.tv.item(item, values=None), 1454 (value,) if self.wantobjects else value) 1455 1456 self.assertIsInstance(self.tv.item(item), dict) 1457 1458 # erase item values 1459 self.tv.item(item, values='') 1460 self.assertFalse(self.tv.item(item, values=None)) 1461 1462 # item tags 1463 item = self.tv.insert('', 'end', tags=[1, 2, value]) 1464 self.assertEqual(self.tv.item(item, tags=None), 1465 ('1', '2', value) if self.wantobjects else 1466 '1 2 %s' % value) 1467 self.tv.item(item, tags=[]) 1468 self.assertFalse(self.tv.item(item, tags=None)) 1469 self.tv.item(item, tags=(1, 2)) 1470 self.assertEqual(self.tv.item(item, tags=None), 1471 ('1', '2') if self.wantobjects else '1 2') 1472 1473 # values with spaces 1474 item = self.tv.insert('', 'end', values=('a b c', 1475 '%s %s' % (value, value))) 1476 self.assertEqual(self.tv.item(item, values=None), 1477 ('a b c', '%s %s' % (value, value)) if self.wantobjects else 1478 '{a b c} {%s %s}' % (value, value)) 1479 1480 # text 1481 self.assertEqual(self.tv.item( 1482 self.tv.insert('', 'end', text="Label here"), text=None), 1483 "Label here") 1484 self.assertEqual(self.tv.item( 1485 self.tv.insert('', 'end', text=value), text=None), 1486 value) 1487 1488 # test for values which are not None 1489 itemid = self.tv.insert('', 'end', 0) 1490 self.assertEqual(itemid, '0') 1491 itemid = self.tv.insert('', 'end', 0.0) 1492 self.assertEqual(itemid, '0.0') 1493 # this is because False resolves to 0 and element with 0 iid is already present 1494 self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', False) 1495 self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', '') 1496 1497 1498 def test_selection(self): 1499 # item 'none' doesn't exist 1500 self.assertRaises(tkinter.TclError, self.tv.selection_set, 'none') 1501 self.assertRaises(tkinter.TclError, self.tv.selection_add, 'none') 1502 self.assertRaises(tkinter.TclError, self.tv.selection_remove, 'none') 1503 self.assertRaises(tkinter.TclError, self.tv.selection_toggle, 'none') 1504 1505 item1 = self.tv.insert('', 'end') 1506 item2 = self.tv.insert('', 'end') 1507 c1 = self.tv.insert(item1, 'end') 1508 c2 = self.tv.insert(item1, 'end') 1509 c3 = self.tv.insert(item1, 'end') 1510 self.assertEqual(self.tv.selection(), ()) 1511 1512 self.tv.selection_set((c1, item2)) 1513 self.assertEqual(self.tv.selection(), (c1, item2)) 1514 self.tv.selection_set(c2) 1515 self.assertEqual(self.tv.selection(), (c2,)) 1516 1517 self.tv.selection_add((c1, item2)) 1518 self.assertEqual(self.tv.selection(), (c1, c2, item2)) 1519 self.tv.selection_add(item1) 1520 self.assertEqual(self.tv.selection(), (item1, c1, c2, item2)) 1521 1522 self.tv.selection_remove((item1, c3)) 1523 self.assertEqual(self.tv.selection(), (c1, c2, item2)) 1524 self.tv.selection_remove(c2) 1525 self.assertEqual(self.tv.selection(), (c1, item2)) 1526 1527 self.tv.selection_toggle((c1, c3)) 1528 self.assertEqual(self.tv.selection(), (c3, item2)) 1529 self.tv.selection_toggle(item2) 1530 self.assertEqual(self.tv.selection(), (c3,)) 1531 1532 self.tv.insert('', 'end', id='with spaces') 1533 self.tv.selection_set('with spaces') 1534 self.assertEqual(self.tv.selection(), ('with spaces',)) 1535 1536 self.tv.insert('', 'end', id='{brace') 1537 self.tv.selection_set('{brace') 1538 self.assertEqual(self.tv.selection(), ('{brace',)) 1539 1540 if have_unicode: 1541 self.tv.insert('', 'end', id=u(r'unicode\u20ac')) 1542 self.tv.selection_set(u(r'unicode\u20ac')) 1543 self.assertEqual(self.tv.selection(), (u(r'unicode\u20ac'),)) 1544 1545 self.tv.insert('', 'end', id='bytes\xe2\x82\xac') 1546 self.tv.selection_set('bytes\xe2\x82\xac') 1547 self.assertEqual(self.tv.selection(), 1548 (u(r'bytes\u20ac') if have_unicode else 1549 'bytes\xe2\x82\xac',)) 1550 1551 1552 def test_set(self): 1553 self.tv['columns'] = ['A', 'B'] 1554 item = self.tv.insert('', 'end', values=['a', 'b']) 1555 self.assertEqual(self.tv.set(item), {'A': 'a', 'B': 'b'}) 1556 1557 self.tv.set(item, 'B', 'a') 1558 self.assertEqual(self.tv.item(item, values=None), 1559 ('a', 'a') if self.wantobjects else 'a a') 1560 1561 self.tv['columns'] = ['B'] 1562 self.assertEqual(self.tv.set(item), {'B': 'a'}) 1563 1564 self.tv.set(item, 'B', 'b') 1565 self.assertEqual(self.tv.set(item, column='B'), 'b') 1566 self.assertEqual(self.tv.item(item, values=None), 1567 ('b', 'a') if self.wantobjects else 'b a') 1568 1569 self.tv.set(item, 'B', 123) 1570 self.assertEqual(self.tv.set(item, 'B'), 1571 123 if self.wantobjects else '123') 1572 self.assertEqual(self.tv.item(item, values=None), 1573 (123, 'a') if self.wantobjects else '123 a') 1574 self.assertEqual(self.tv.set(item), 1575 {'B': 123} if self.wantobjects else {'B': '123'}) 1576 1577 # inexistent column 1578 self.assertRaises(tkinter.TclError, self.tv.set, item, 'A') 1579 self.assertRaises(tkinter.TclError, self.tv.set, item, 'A', 'b') 1580 1581 # inexistent item 1582 self.assertRaises(tkinter.TclError, self.tv.set, 'notme') 1583 1584 1585 def test_tag_bind(self): 1586 events = [] 1587 item1 = self.tv.insert('', 'end', tags=['call']) 1588 item2 = self.tv.insert('', 'end', tags=['call']) 1589 self.tv.tag_bind('call', '<ButtonPress-1>', 1590 lambda evt: events.append(1)) 1591 self.tv.tag_bind('call', '<ButtonRelease-1>', 1592 lambda evt: events.append(2)) 1593 1594 self.tv.pack() 1595 self.tv.wait_visibility() 1596 self.tv.update() 1597 1598 pos_y = set() 1599 found = set() 1600 for i in range(0, 100, 10): 1601 if len(found) == 2: # item1 and item2 already found 1602 break 1603 item_id = self.tv.identify_row(i) 1604 if item_id and item_id not in found: 1605 pos_y.add(i) 1606 found.add(item_id) 1607 1608 self.assertEqual(len(pos_y), 2) # item1 and item2 y pos 1609 for y in pos_y: 1610 simulate_mouse_click(self.tv, 0, y) 1611 1612 # by now there should be 4 things in the events list, since each 1613 # item had a bind for two events that were simulated above 1614 self.assertEqual(len(events), 4) 1615 for evt in zip(events[::2], events[1::2]): 1616 self.assertEqual(evt, (1, 2)) 1617 1618 1619 def test_tag_configure(self): 1620 # Just testing parameter passing for now 1621 self.assertRaises(TypeError, self.tv.tag_configure) 1622 self.assertRaises(tkinter.TclError, self.tv.tag_configure, 1623 'test', sky='blue') 1624 self.tv.tag_configure('test', foreground='blue') 1625 self.assertEqual(str(self.tv.tag_configure('test', 'foreground')), 1626 'blue') 1627 self.assertEqual(str(self.tv.tag_configure('test', foreground=None)), 1628 'blue') 1629 self.assertIsInstance(self.tv.tag_configure('test'), dict) 1630 1631 def test_tag_has(self): 1632 item1 = self.tv.insert('', 'end', text='Item 1', tags=['tag1']) 1633 item2 = self.tv.insert('', 'end', text='Item 2', tags=['tag2']) 1634 self.assertRaises(TypeError, self.tv.tag_has) 1635 self.assertRaises(TclError, self.tv.tag_has, 'tag1', 'non-existing') 1636 self.assertTrue(self.tv.tag_has('tag1', item1)) 1637 self.assertFalse(self.tv.tag_has('tag1', item2)) 1638 self.assertFalse(self.tv.tag_has('tag2', item1)) 1639 self.assertTrue(self.tv.tag_has('tag2', item2)) 1640 self.assertFalse(self.tv.tag_has('tag3', item1)) 1641 self.assertFalse(self.tv.tag_has('tag3', item2)) 1642 self.assertEqual(self.tv.tag_has('tag1'), (item1,)) 1643 self.assertEqual(self.tv.tag_has('tag2'), (item2,)) 1644 self.assertEqual(self.tv.tag_has('tag3'), ()) 1645 1646 1647@add_standard_options(StandardTtkOptionsTests) 1648class SeparatorTest(AbstractWidgetTest, unittest.TestCase): 1649 OPTIONS = ( 1650 'class', 'cursor', 'orient', 'style', 'takefocus', 1651 # 'state'? 1652 ) 1653 default_orient = 'horizontal' 1654 1655 def create(self, **kwargs): 1656 return ttk.Separator(self.root, **kwargs) 1657 1658 1659@add_standard_options(StandardTtkOptionsTests) 1660class SizegripTest(AbstractWidgetTest, unittest.TestCase): 1661 OPTIONS = ( 1662 'class', 'cursor', 'style', 'takefocus', 1663 # 'state'? 1664 ) 1665 1666 def create(self, **kwargs): 1667 return ttk.Sizegrip(self.root, **kwargs) 1668 1669 1670tests_gui = ( 1671 ButtonTest, CheckbuttonTest, ComboboxTest, EntryTest, 1672 FrameTest, LabelFrameTest, LabelTest, MenubuttonTest, 1673 NotebookTest, PanedWindowTest, ProgressbarTest, 1674 RadiobuttonTest, ScaleTest, ScrollbarTest, SeparatorTest, 1675 SizegripTest, TreeviewTest, WidgetTest, 1676 ) 1677 1678tests_gui = ( 1679 TreeviewTest, 1680 ) 1681 1682if __name__ == "__main__": 1683 run_unittest(*tests_gui) 1684