17db96d56Sopenharmony_ciimport sys 27db96d56Sopenharmony_ciimport unittest 37db96d56Sopenharmony_ciimport tkinter 47db96d56Sopenharmony_cifrom tkinter import ttk 57db96d56Sopenharmony_cifrom test.support import requires, gc_collect 67db96d56Sopenharmony_cifrom tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest 77db96d56Sopenharmony_ci 87db96d56Sopenharmony_cirequires('gui') 97db96d56Sopenharmony_ci 107db96d56Sopenharmony_ciclass LabeledScaleTest(AbstractTkTest, unittest.TestCase): 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_ci def tearDown(self): 137db96d56Sopenharmony_ci self.root.update_idletasks() 147db96d56Sopenharmony_ci super().tearDown() 157db96d56Sopenharmony_ci 167db96d56Sopenharmony_ci def test_widget_destroy(self): 177db96d56Sopenharmony_ci # automatically created variable 187db96d56Sopenharmony_ci x = ttk.LabeledScale(self.root) 197db96d56Sopenharmony_ci var = x._variable._name 207db96d56Sopenharmony_ci x.destroy() 217db96d56Sopenharmony_ci gc_collect() # For PyPy or other GCs. 227db96d56Sopenharmony_ci self.assertRaises(tkinter.TclError, x.tk.globalgetvar, var) 237db96d56Sopenharmony_ci 247db96d56Sopenharmony_ci # manually created variable 257db96d56Sopenharmony_ci myvar = tkinter.DoubleVar(self.root) 267db96d56Sopenharmony_ci name = myvar._name 277db96d56Sopenharmony_ci x = ttk.LabeledScale(self.root, variable=myvar) 287db96d56Sopenharmony_ci x.destroy() 297db96d56Sopenharmony_ci if self.wantobjects: 307db96d56Sopenharmony_ci self.assertEqual(x.tk.globalgetvar(name), myvar.get()) 317db96d56Sopenharmony_ci else: 327db96d56Sopenharmony_ci self.assertEqual(float(x.tk.globalgetvar(name)), myvar.get()) 337db96d56Sopenharmony_ci del myvar 347db96d56Sopenharmony_ci gc_collect() # For PyPy or other GCs. 357db96d56Sopenharmony_ci self.assertRaises(tkinter.TclError, x.tk.globalgetvar, name) 367db96d56Sopenharmony_ci 377db96d56Sopenharmony_ci # checking that the tracing callback is properly removed 387db96d56Sopenharmony_ci myvar = tkinter.IntVar(self.root) 397db96d56Sopenharmony_ci # LabeledScale will start tracing myvar 407db96d56Sopenharmony_ci x = ttk.LabeledScale(self.root, variable=myvar) 417db96d56Sopenharmony_ci x.destroy() 427db96d56Sopenharmony_ci # Unless the tracing callback was removed, creating a new 437db96d56Sopenharmony_ci # LabeledScale with the same var will cause an error now. This 447db96d56Sopenharmony_ci # happens because the variable will be set to (possibly) a new 457db96d56Sopenharmony_ci # value which causes the tracing callback to be called and then 467db96d56Sopenharmony_ci # it tries calling instance attributes not yet defined. 477db96d56Sopenharmony_ci ttk.LabeledScale(self.root, variable=myvar) 487db96d56Sopenharmony_ci if hasattr(sys, 'last_type'): 497db96d56Sopenharmony_ci self.assertNotEqual(sys.last_type, tkinter.TclError) 507db96d56Sopenharmony_ci 517db96d56Sopenharmony_ci def test_initialization(self): 527db96d56Sopenharmony_ci # master passing 537db96d56Sopenharmony_ci master = tkinter.Frame(self.root) 547db96d56Sopenharmony_ci x = ttk.LabeledScale(master) 557db96d56Sopenharmony_ci self.assertEqual(x.master, master) 567db96d56Sopenharmony_ci x.destroy() 577db96d56Sopenharmony_ci 587db96d56Sopenharmony_ci # variable initialization/passing 597db96d56Sopenharmony_ci passed_expected = (('0', 0), (0, 0), (10, 10), 607db96d56Sopenharmony_ci (-1, -1), (sys.maxsize + 1, sys.maxsize + 1), 617db96d56Sopenharmony_ci (2.5, 2), ('2.5', 2)) 627db96d56Sopenharmony_ci for pair in passed_expected: 637db96d56Sopenharmony_ci x = ttk.LabeledScale(self.root, from_=pair[0]) 647db96d56Sopenharmony_ci self.assertEqual(x.value, pair[1]) 657db96d56Sopenharmony_ci x.destroy() 667db96d56Sopenharmony_ci x = ttk.LabeledScale(self.root, from_=None) 677db96d56Sopenharmony_ci self.assertRaises((ValueError, tkinter.TclError), x._variable.get) 687db96d56Sopenharmony_ci x.destroy() 697db96d56Sopenharmony_ci # variable should have its default value set to the from_ value 707db96d56Sopenharmony_ci myvar = tkinter.DoubleVar(self.root, value=20) 717db96d56Sopenharmony_ci x = ttk.LabeledScale(self.root, variable=myvar) 727db96d56Sopenharmony_ci self.assertEqual(x.value, 0) 737db96d56Sopenharmony_ci x.destroy() 747db96d56Sopenharmony_ci # check that it is really using a DoubleVar 757db96d56Sopenharmony_ci x = ttk.LabeledScale(self.root, variable=myvar, from_=0.5) 767db96d56Sopenharmony_ci self.assertEqual(x.value, 0.5) 777db96d56Sopenharmony_ci self.assertEqual(x._variable._name, myvar._name) 787db96d56Sopenharmony_ci x.destroy() 797db96d56Sopenharmony_ci 807db96d56Sopenharmony_ci # widget positionment 817db96d56Sopenharmony_ci def check_positions(scale, scale_pos, label, label_pos): 827db96d56Sopenharmony_ci self.assertEqual(scale.pack_info()['side'], scale_pos) 837db96d56Sopenharmony_ci self.assertEqual(label.place_info()['anchor'], label_pos) 847db96d56Sopenharmony_ci x = ttk.LabeledScale(self.root, compound='top') 857db96d56Sopenharmony_ci check_positions(x.scale, 'bottom', x.label, 'n') 867db96d56Sopenharmony_ci x.destroy() 877db96d56Sopenharmony_ci x = ttk.LabeledScale(self.root, compound='bottom') 887db96d56Sopenharmony_ci check_positions(x.scale, 'top', x.label, 's') 897db96d56Sopenharmony_ci x.destroy() 907db96d56Sopenharmony_ci # invert default positions 917db96d56Sopenharmony_ci x = ttk.LabeledScale(self.root, compound='unknown') 927db96d56Sopenharmony_ci check_positions(x.scale, 'top', x.label, 's') 937db96d56Sopenharmony_ci x.destroy() 947db96d56Sopenharmony_ci x = ttk.LabeledScale(self.root) # take default positions 957db96d56Sopenharmony_ci check_positions(x.scale, 'bottom', x.label, 'n') 967db96d56Sopenharmony_ci x.destroy() 977db96d56Sopenharmony_ci 987db96d56Sopenharmony_ci # extra, and invalid, kwargs 997db96d56Sopenharmony_ci self.assertRaises(tkinter.TclError, ttk.LabeledScale, master, a='b') 1007db96d56Sopenharmony_ci 1017db96d56Sopenharmony_ci 1027db96d56Sopenharmony_ci def test_horizontal_range(self): 1037db96d56Sopenharmony_ci lscale = ttk.LabeledScale(self.root, from_=0, to=10) 1047db96d56Sopenharmony_ci lscale.pack() 1057db96d56Sopenharmony_ci lscale.update() 1067db96d56Sopenharmony_ci 1077db96d56Sopenharmony_ci linfo_1 = lscale.label.place_info() 1087db96d56Sopenharmony_ci prev_xcoord = lscale.scale.coords()[0] 1097db96d56Sopenharmony_ci self.assertEqual(prev_xcoord, int(linfo_1['x'])) 1107db96d56Sopenharmony_ci # change range to: from -5 to 5. This should change the x coord of 1117db96d56Sopenharmony_ci # the scale widget, since 0 is at the middle of the new 1127db96d56Sopenharmony_ci # range. 1137db96d56Sopenharmony_ci lscale.scale.configure(from_=-5, to=5) 1147db96d56Sopenharmony_ci # The following update is needed since the test doesn't use mainloop, 1157db96d56Sopenharmony_ci # at the same time this shouldn't affect test outcome 1167db96d56Sopenharmony_ci lscale.update() 1177db96d56Sopenharmony_ci curr_xcoord = lscale.scale.coords()[0] 1187db96d56Sopenharmony_ci self.assertNotEqual(prev_xcoord, curr_xcoord) 1197db96d56Sopenharmony_ci # the label widget should have been repositioned too 1207db96d56Sopenharmony_ci linfo_2 = lscale.label.place_info() 1217db96d56Sopenharmony_ci self.assertEqual(lscale.label['text'], 0 if self.wantobjects else '0') 1227db96d56Sopenharmony_ci self.assertEqual(curr_xcoord, int(linfo_2['x'])) 1237db96d56Sopenharmony_ci # change the range back 1247db96d56Sopenharmony_ci lscale.scale.configure(from_=0, to=10) 1257db96d56Sopenharmony_ci self.assertNotEqual(prev_xcoord, curr_xcoord) 1267db96d56Sopenharmony_ci self.assertEqual(prev_xcoord, int(linfo_1['x'])) 1277db96d56Sopenharmony_ci 1287db96d56Sopenharmony_ci lscale.destroy() 1297db96d56Sopenharmony_ci 1307db96d56Sopenharmony_ci 1317db96d56Sopenharmony_ci def test_variable_change(self): 1327db96d56Sopenharmony_ci x = ttk.LabeledScale(self.root) 1337db96d56Sopenharmony_ci x.pack() 1347db96d56Sopenharmony_ci x.update() 1357db96d56Sopenharmony_ci 1367db96d56Sopenharmony_ci curr_xcoord = x.scale.coords()[0] 1377db96d56Sopenharmony_ci newval = x.value + 1 1387db96d56Sopenharmony_ci x.value = newval 1397db96d56Sopenharmony_ci # The following update is needed since the test doesn't use mainloop, 1407db96d56Sopenharmony_ci # at the same time this shouldn't affect test outcome 1417db96d56Sopenharmony_ci x.update() 1427db96d56Sopenharmony_ci self.assertEqual(x.value, newval) 1437db96d56Sopenharmony_ci self.assertEqual(x.label['text'], 1447db96d56Sopenharmony_ci newval if self.wantobjects else str(newval)) 1457db96d56Sopenharmony_ci self.assertEqual(float(x.scale.get()), newval) 1467db96d56Sopenharmony_ci self.assertGreater(x.scale.coords()[0], curr_xcoord) 1477db96d56Sopenharmony_ci self.assertEqual(x.scale.coords()[0], 1487db96d56Sopenharmony_ci int(x.label.place_info()['x'])) 1497db96d56Sopenharmony_ci 1507db96d56Sopenharmony_ci # value outside range 1517db96d56Sopenharmony_ci if self.wantobjects: 1527db96d56Sopenharmony_ci conv = lambda x: x 1537db96d56Sopenharmony_ci else: 1547db96d56Sopenharmony_ci conv = int 1557db96d56Sopenharmony_ci x.value = conv(x.scale['to']) + 1 # no changes shouldn't happen 1567db96d56Sopenharmony_ci x.update() 1577db96d56Sopenharmony_ci self.assertEqual(x.value, newval) 1587db96d56Sopenharmony_ci self.assertEqual(conv(x.label['text']), newval) 1597db96d56Sopenharmony_ci self.assertEqual(float(x.scale.get()), newval) 1607db96d56Sopenharmony_ci self.assertEqual(x.scale.coords()[0], 1617db96d56Sopenharmony_ci int(x.label.place_info()['x'])) 1627db96d56Sopenharmony_ci 1637db96d56Sopenharmony_ci # non-integer value 1647db96d56Sopenharmony_ci x.value = newval = newval + 1.5 1657db96d56Sopenharmony_ci x.update() 1667db96d56Sopenharmony_ci self.assertEqual(x.value, int(newval)) 1677db96d56Sopenharmony_ci self.assertEqual(conv(x.label['text']), int(newval)) 1687db96d56Sopenharmony_ci self.assertEqual(float(x.scale.get()), newval) 1697db96d56Sopenharmony_ci 1707db96d56Sopenharmony_ci x.destroy() 1717db96d56Sopenharmony_ci 1727db96d56Sopenharmony_ci 1737db96d56Sopenharmony_ci def test_resize(self): 1747db96d56Sopenharmony_ci x = ttk.LabeledScale(self.root) 1757db96d56Sopenharmony_ci x.pack(expand=True, fill='both') 1767db96d56Sopenharmony_ci gc_collect() # For PyPy or other GCs. 1777db96d56Sopenharmony_ci x.update() 1787db96d56Sopenharmony_ci 1797db96d56Sopenharmony_ci width, height = x.master.winfo_width(), x.master.winfo_height() 1807db96d56Sopenharmony_ci width_new, height_new = width * 2, height * 2 1817db96d56Sopenharmony_ci 1827db96d56Sopenharmony_ci x.value = 3 1837db96d56Sopenharmony_ci x.update() 1847db96d56Sopenharmony_ci x.master.wm_geometry("%dx%d" % (width_new, height_new)) 1857db96d56Sopenharmony_ci self.assertEqual(int(x.label.place_info()['x']), 1867db96d56Sopenharmony_ci x.scale.coords()[0]) 1877db96d56Sopenharmony_ci 1887db96d56Sopenharmony_ci # Reset geometry 1897db96d56Sopenharmony_ci x.master.wm_geometry("%dx%d" % (width, height)) 1907db96d56Sopenharmony_ci x.destroy() 1917db96d56Sopenharmony_ci 1927db96d56Sopenharmony_ci 1937db96d56Sopenharmony_ciclass OptionMenuTest(AbstractTkTest, unittest.TestCase): 1947db96d56Sopenharmony_ci 1957db96d56Sopenharmony_ci def setUp(self): 1967db96d56Sopenharmony_ci super().setUp() 1977db96d56Sopenharmony_ci self.textvar = tkinter.StringVar(self.root) 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_ci def tearDown(self): 2007db96d56Sopenharmony_ci del self.textvar 2017db96d56Sopenharmony_ci super().tearDown() 2027db96d56Sopenharmony_ci 2037db96d56Sopenharmony_ci 2047db96d56Sopenharmony_ci def test_widget_destroy(self): 2057db96d56Sopenharmony_ci var = tkinter.StringVar(self.root) 2067db96d56Sopenharmony_ci optmenu = ttk.OptionMenu(self.root, var) 2077db96d56Sopenharmony_ci name = var._name 2087db96d56Sopenharmony_ci optmenu.update_idletasks() 2097db96d56Sopenharmony_ci optmenu.destroy() 2107db96d56Sopenharmony_ci self.assertEqual(optmenu.tk.globalgetvar(name), var.get()) 2117db96d56Sopenharmony_ci del var 2127db96d56Sopenharmony_ci gc_collect() # For PyPy or other GCs. 2137db96d56Sopenharmony_ci self.assertRaises(tkinter.TclError, optmenu.tk.globalgetvar, name) 2147db96d56Sopenharmony_ci 2157db96d56Sopenharmony_ci 2167db96d56Sopenharmony_ci def test_initialization(self): 2177db96d56Sopenharmony_ci self.assertRaises(tkinter.TclError, 2187db96d56Sopenharmony_ci ttk.OptionMenu, self.root, self.textvar, invalid='thing') 2197db96d56Sopenharmony_ci 2207db96d56Sopenharmony_ci optmenu = ttk.OptionMenu(self.root, self.textvar, 'b', 'a', 'b') 2217db96d56Sopenharmony_ci self.assertEqual(optmenu._variable.get(), 'b') 2227db96d56Sopenharmony_ci 2237db96d56Sopenharmony_ci self.assertTrue(optmenu['menu']) 2247db96d56Sopenharmony_ci self.assertTrue(optmenu['textvariable']) 2257db96d56Sopenharmony_ci 2267db96d56Sopenharmony_ci optmenu.destroy() 2277db96d56Sopenharmony_ci 2287db96d56Sopenharmony_ci 2297db96d56Sopenharmony_ci def test_menu(self): 2307db96d56Sopenharmony_ci items = ('a', 'b', 'c') 2317db96d56Sopenharmony_ci default = 'a' 2327db96d56Sopenharmony_ci optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items) 2337db96d56Sopenharmony_ci found_default = False 2347db96d56Sopenharmony_ci for i in range(len(items)): 2357db96d56Sopenharmony_ci value = optmenu['menu'].entrycget(i, 'value') 2367db96d56Sopenharmony_ci self.assertEqual(value, items[i]) 2377db96d56Sopenharmony_ci if value == default: 2387db96d56Sopenharmony_ci found_default = True 2397db96d56Sopenharmony_ci self.assertTrue(found_default) 2407db96d56Sopenharmony_ci optmenu.destroy() 2417db96d56Sopenharmony_ci 2427db96d56Sopenharmony_ci # default shouldn't be in menu if it is not part of values 2437db96d56Sopenharmony_ci default = 'd' 2447db96d56Sopenharmony_ci optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items) 2457db96d56Sopenharmony_ci curr = None 2467db96d56Sopenharmony_ci i = 0 2477db96d56Sopenharmony_ci while True: 2487db96d56Sopenharmony_ci last, curr = curr, optmenu['menu'].entryconfigure(i, 'value') 2497db96d56Sopenharmony_ci if last == curr: 2507db96d56Sopenharmony_ci # no more menu entries 2517db96d56Sopenharmony_ci break 2527db96d56Sopenharmony_ci self.assertNotEqual(curr, default) 2537db96d56Sopenharmony_ci i += 1 2547db96d56Sopenharmony_ci self.assertEqual(i, len(items)) 2557db96d56Sopenharmony_ci 2567db96d56Sopenharmony_ci # check that variable is updated correctly 2577db96d56Sopenharmony_ci optmenu.pack() 2587db96d56Sopenharmony_ci gc_collect() # For PyPy or other GCs. 2597db96d56Sopenharmony_ci optmenu['menu'].invoke(0) 2607db96d56Sopenharmony_ci self.assertEqual(optmenu._variable.get(), items[0]) 2617db96d56Sopenharmony_ci 2627db96d56Sopenharmony_ci # changing to an invalid index shouldn't change the variable 2637db96d56Sopenharmony_ci self.assertRaises(tkinter.TclError, optmenu['menu'].invoke, -1) 2647db96d56Sopenharmony_ci self.assertEqual(optmenu._variable.get(), items[0]) 2657db96d56Sopenharmony_ci 2667db96d56Sopenharmony_ci optmenu.destroy() 2677db96d56Sopenharmony_ci 2687db96d56Sopenharmony_ci # specifying a callback 2697db96d56Sopenharmony_ci success = [] 2707db96d56Sopenharmony_ci def cb_test(item): 2717db96d56Sopenharmony_ci self.assertEqual(item, items[1]) 2727db96d56Sopenharmony_ci success.append(True) 2737db96d56Sopenharmony_ci optmenu = ttk.OptionMenu(self.root, self.textvar, 'a', command=cb_test, 2747db96d56Sopenharmony_ci *items) 2757db96d56Sopenharmony_ci optmenu['menu'].invoke(1) 2767db96d56Sopenharmony_ci if not success: 2777db96d56Sopenharmony_ci self.fail("Menu callback not invoked") 2787db96d56Sopenharmony_ci 2797db96d56Sopenharmony_ci optmenu.destroy() 2807db96d56Sopenharmony_ci 2817db96d56Sopenharmony_ci def test_unique_radiobuttons(self): 2827db96d56Sopenharmony_ci # check that radiobuttons are unique across instances (bpo25684) 2837db96d56Sopenharmony_ci items = ('a', 'b', 'c') 2847db96d56Sopenharmony_ci default = 'a' 2857db96d56Sopenharmony_ci optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items) 2867db96d56Sopenharmony_ci textvar2 = tkinter.StringVar(self.root) 2877db96d56Sopenharmony_ci optmenu2 = ttk.OptionMenu(self.root, textvar2, default, *items) 2887db96d56Sopenharmony_ci optmenu.pack() 2897db96d56Sopenharmony_ci optmenu2.pack() 2907db96d56Sopenharmony_ci optmenu['menu'].invoke(1) 2917db96d56Sopenharmony_ci optmenu2['menu'].invoke(2) 2927db96d56Sopenharmony_ci optmenu_stringvar_name = optmenu['menu'].entrycget(0, 'variable') 2937db96d56Sopenharmony_ci optmenu2_stringvar_name = optmenu2['menu'].entrycget(0, 'variable') 2947db96d56Sopenharmony_ci self.assertNotEqual(optmenu_stringvar_name, 2957db96d56Sopenharmony_ci optmenu2_stringvar_name) 2967db96d56Sopenharmony_ci self.assertEqual(self.root.tk.globalgetvar(optmenu_stringvar_name), 2977db96d56Sopenharmony_ci items[1]) 2987db96d56Sopenharmony_ci self.assertEqual(self.root.tk.globalgetvar(optmenu2_stringvar_name), 2997db96d56Sopenharmony_ci items[2]) 3007db96d56Sopenharmony_ci 3017db96d56Sopenharmony_ci optmenu.destroy() 3027db96d56Sopenharmony_ci optmenu2.destroy() 3037db96d56Sopenharmony_ci 3047db96d56Sopenharmony_ci def test_trace_variable(self): 3057db96d56Sopenharmony_ci # prior to bpo45160, tracing a variable would cause the callback to be made twice 3067db96d56Sopenharmony_ci success = [] 3077db96d56Sopenharmony_ci items = ('a', 'b', 'c') 3087db96d56Sopenharmony_ci textvar = tkinter.StringVar(self.root) 3097db96d56Sopenharmony_ci def cb_test(*args): 3107db96d56Sopenharmony_ci success.append(textvar.get()) 3117db96d56Sopenharmony_ci optmenu = ttk.OptionMenu(self.root, textvar, "a", *items) 3127db96d56Sopenharmony_ci optmenu.pack() 3137db96d56Sopenharmony_ci cb_name = textvar.trace_add("write", cb_test) 3147db96d56Sopenharmony_ci optmenu['menu'].invoke(1) 3157db96d56Sopenharmony_ci self.assertEqual(success, ['b']) 3167db96d56Sopenharmony_ci self.assertEqual(textvar.get(), 'b') 3177db96d56Sopenharmony_ci textvar.trace_remove("write", cb_name) 3187db96d56Sopenharmony_ci optmenu.destroy() 3197db96d56Sopenharmony_ci 3207db96d56Sopenharmony_ci 3217db96d56Sopenharmony_ciclass DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): 3227db96d56Sopenharmony_ci 3237db96d56Sopenharmony_ci def test_labeledscale(self): 3247db96d56Sopenharmony_ci self._test_widget(ttk.LabeledScale) 3257db96d56Sopenharmony_ci 3267db96d56Sopenharmony_ci 3277db96d56Sopenharmony_ciif __name__ == "__main__": 3287db96d56Sopenharmony_ci unittest.main() 329