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