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