1import sys 2import unittest 3import Tkinter as tkinter 4import ttk 5from test.test_support import requires, run_unittest, swap_attr 6from test_ttk.support import AbstractTkTest, destroy_default_root 7 8requires('gui') 9 10class LabeledScaleTest(AbstractTkTest, unittest.TestCase): 11 12 def tearDown(self): 13 self.root.update_idletasks() 14 super(LabeledScaleTest, self).tearDown() 15 16 def test_widget_destroy(self): 17 # automatically created variable 18 x = ttk.LabeledScale(self.root) 19 var = x._variable._name 20 x.destroy() 21 self.assertRaises(tkinter.TclError, x.tk.globalgetvar, var) 22 23 # manually created variable 24 myvar = tkinter.DoubleVar(self.root) 25 name = myvar._name 26 x = ttk.LabeledScale(self.root, variable=myvar) 27 x.destroy() 28 if self.wantobjects: 29 self.assertEqual(x.tk.globalgetvar(name), myvar.get()) 30 else: 31 self.assertEqual(float(x.tk.globalgetvar(name)), myvar.get()) 32 del myvar 33 self.assertRaises(tkinter.TclError, x.tk.globalgetvar, name) 34 35 # checking that the tracing callback is properly removed 36 myvar = tkinter.IntVar(self.root) 37 # LabeledScale will start tracing myvar 38 x = ttk.LabeledScale(self.root, variable=myvar) 39 x.destroy() 40 # Unless the tracing callback was removed, creating a new 41 # LabeledScale with the same var will cause an error now. This 42 # happens because the variable will be set to (possibly) a new 43 # value which causes the tracing callback to be called and then 44 # it tries calling instance attributes not yet defined. 45 ttk.LabeledScale(self.root, variable=myvar) 46 if hasattr(sys, 'last_type'): 47 self.assertNotEqual(sys.last_type, tkinter.TclError) 48 49 50 def test_initialization_no_master(self): 51 # no master passing 52 with swap_attr(tkinter, '_default_root', None), \ 53 swap_attr(tkinter, '_support_default_root', True): 54 try: 55 x = ttk.LabeledScale() 56 self.assertIsNotNone(tkinter._default_root) 57 self.assertEqual(x.master, tkinter._default_root) 58 self.assertEqual(x.tk, tkinter._default_root.tk) 59 x.destroy() 60 finally: 61 destroy_default_root() 62 63 def test_initialization(self): 64 # master passing 65 master = tkinter.Frame(self.root) 66 x = ttk.LabeledScale(master) 67 self.assertEqual(x.master, master) 68 x.destroy() 69 70 # variable initialization/passing 71 passed_expected = (('0', 0), (0, 0), (10, 10), 72 (-1, -1), (sys.maxint + 1, sys.maxint + 1)) 73 if self.wantobjects: 74 passed_expected += ((2.5, 2),) 75 for pair in passed_expected: 76 x = ttk.LabeledScale(self.root, from_=pair[0]) 77 self.assertEqual(x.value, pair[1]) 78 x.destroy() 79 x = ttk.LabeledScale(self.root, from_='2.5') 80 self.assertRaises(ValueError, x._variable.get) 81 x.destroy() 82 x = ttk.LabeledScale(self.root, from_=None) 83 self.assertRaises(ValueError, x._variable.get) 84 x.destroy() 85 # variable should have its default value set to the from_ value 86 myvar = tkinter.DoubleVar(self.root, value=20) 87 x = ttk.LabeledScale(self.root, variable=myvar) 88 self.assertEqual(x.value, 0) 89 x.destroy() 90 # check that it is really using a DoubleVar 91 x = ttk.LabeledScale(self.root, variable=myvar, from_=0.5) 92 self.assertEqual(x.value, 0.5) 93 self.assertEqual(x._variable._name, myvar._name) 94 x.destroy() 95 96 # widget positionment 97 def check_positions(scale, scale_pos, label, label_pos): 98 self.assertEqual(scale.pack_info()['side'], scale_pos) 99 self.assertEqual(label.place_info()['anchor'], label_pos) 100 x = ttk.LabeledScale(self.root, compound='top') 101 check_positions(x.scale, 'bottom', x.label, 'n') 102 x.destroy() 103 x = ttk.LabeledScale(self.root, compound='bottom') 104 check_positions(x.scale, 'top', x.label, 's') 105 x.destroy() 106 # invert default positions 107 x = ttk.LabeledScale(self.root, compound='unknown') 108 check_positions(x.scale, 'top', x.label, 's') 109 x.destroy() 110 x = ttk.LabeledScale(self.root) # take default positions 111 check_positions(x.scale, 'bottom', x.label, 'n') 112 x.destroy() 113 114 # extra, and invalid, kwargs 115 self.assertRaises(tkinter.TclError, ttk.LabeledScale, master, a='b') 116 117 118 def test_horizontal_range(self): 119 lscale = ttk.LabeledScale(self.root, from_=0, to=10) 120 lscale.pack() 121 lscale.wait_visibility() 122 lscale.update() 123 124 linfo_1 = lscale.label.place_info() 125 prev_xcoord = lscale.scale.coords()[0] 126 self.assertEqual(prev_xcoord, int(linfo_1['x'])) 127 # change range to: from -5 to 5. This should change the x coord of 128 # the scale widget, since 0 is at the middle of the new 129 # range. 130 lscale.scale.configure(from_=-5, to=5) 131 # The following update is needed since the test doesn't use mainloop, 132 # at the same time this shouldn't affect test outcome 133 lscale.update() 134 curr_xcoord = lscale.scale.coords()[0] 135 self.assertNotEqual(prev_xcoord, curr_xcoord) 136 # the label widget should have been repositioned too 137 linfo_2 = lscale.label.place_info() 138 self.assertEqual(lscale.label['text'], 0 if self.wantobjects else '0') 139 self.assertEqual(curr_xcoord, int(linfo_2['x'])) 140 # change the range back 141 lscale.scale.configure(from_=0, to=10) 142 self.assertNotEqual(prev_xcoord, curr_xcoord) 143 self.assertEqual(prev_xcoord, int(linfo_1['x'])) 144 145 lscale.destroy() 146 147 148 def test_variable_change(self): 149 x = ttk.LabeledScale(self.root) 150 x.pack() 151 x.wait_visibility() 152 x.update() 153 154 curr_xcoord = x.scale.coords()[0] 155 newval = x.value + 1 156 x.value = newval 157 # The following update is needed since the test doesn't use mainloop, 158 # at the same time this shouldn't affect test outcome 159 x.update() 160 self.assertEqual(x.label['text'], 161 newval if self.wantobjects else str(newval)) 162 self.assertGreater(x.scale.coords()[0], curr_xcoord) 163 self.assertEqual(x.scale.coords()[0], 164 int(x.label.place_info()['x'])) 165 166 # value outside range 167 if self.wantobjects: 168 conv = lambda x: x 169 else: 170 conv = int 171 x.value = conv(x.scale['to']) + 1 # no changes shouldn't happen 172 x.update() 173 self.assertEqual(conv(x.label['text']), newval) 174 self.assertEqual(x.scale.coords()[0], 175 int(x.label.place_info()['x'])) 176 177 x.destroy() 178 179 180 def test_resize(self): 181 x = ttk.LabeledScale(self.root) 182 x.pack(expand=True, fill='both') 183 x.wait_visibility() 184 x.update() 185 186 width, height = x.master.winfo_width(), x.master.winfo_height() 187 width_new, height_new = width * 2, height * 2 188 189 x.value = 3 190 x.update() 191 x.master.wm_geometry("%dx%d" % (width_new, height_new)) 192 self.assertEqual(int(x.label.place_info()['x']), 193 x.scale.coords()[0]) 194 195 # Reset geometry 196 x.master.wm_geometry("%dx%d" % (width, height)) 197 x.destroy() 198 199 200class OptionMenuTest(AbstractTkTest, unittest.TestCase): 201 202 def setUp(self): 203 super(OptionMenuTest, self).setUp() 204 self.textvar = tkinter.StringVar(self.root) 205 206 def tearDown(self): 207 del self.textvar 208 super(OptionMenuTest, self).tearDown() 209 210 211 def test_widget_destroy(self): 212 var = tkinter.StringVar(self.root) 213 optmenu = ttk.OptionMenu(self.root, var) 214 name = var._name 215 optmenu.update_idletasks() 216 optmenu.destroy() 217 self.assertEqual(optmenu.tk.globalgetvar(name), var.get()) 218 del var 219 self.assertRaises(tkinter.TclError, optmenu.tk.globalgetvar, name) 220 221 222 def test_initialization(self): 223 self.assertRaises(tkinter.TclError, 224 ttk.OptionMenu, self.root, self.textvar, invalid='thing') 225 226 optmenu = ttk.OptionMenu(self.root, self.textvar, 'b', 'a', 'b') 227 self.assertEqual(optmenu._variable.get(), 'b') 228 229 self.assertTrue(optmenu['menu']) 230 self.assertTrue(optmenu['textvariable']) 231 232 optmenu.destroy() 233 234 235 def test_menu(self): 236 items = ('a', 'b', 'c') 237 default = 'a' 238 optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items) 239 found_default = False 240 for i in range(len(items)): 241 value = optmenu['menu'].entrycget(i, 'value') 242 self.assertEqual(value, items[i]) 243 if value == default: 244 found_default = True 245 self.assertTrue(found_default) 246 optmenu.destroy() 247 248 # default shouldn't be in menu if it is not part of values 249 default = 'd' 250 optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items) 251 curr = None 252 i = 0 253 while True: 254 last, curr = curr, optmenu['menu'].entryconfigure(i, 'value') 255 if last == curr: 256 # no more menu entries 257 break 258 self.assertNotEqual(curr, default) 259 i += 1 260 self.assertEqual(i, len(items)) 261 262 # check that variable is updated correctly 263 optmenu.pack() 264 optmenu.wait_visibility() 265 optmenu['menu'].invoke(0) 266 self.assertEqual(optmenu._variable.get(), items[0]) 267 268 # changing to an invalid index shouldn't change the variable 269 self.assertRaises(tkinter.TclError, optmenu['menu'].invoke, -1) 270 self.assertEqual(optmenu._variable.get(), items[0]) 271 272 optmenu.destroy() 273 274 # specifying a callback 275 success = [] 276 def cb_test(item): 277 self.assertEqual(item, items[1]) 278 success.append(True) 279 optmenu = ttk.OptionMenu(self.root, self.textvar, 'a', command=cb_test, 280 *items) 281 optmenu['menu'].invoke(1) 282 if not success: 283 self.fail("Menu callback not invoked") 284 285 optmenu.destroy() 286 287 288tests_gui = (LabeledScaleTest, OptionMenuTest) 289 290if __name__ == "__main__": 291 run_unittest(*tests_gui) 292