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