FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

tk busy command · Issue #72684 · python/cpython · GitHub

Repository navigation

tk busy command #72684

Closed
Closed

Description

mannequin
BPO 28498
Nosy @ned-deily, @serhiy-storchaka, @csabella
Files
  • tk_busy.diff: Patch that add tk_busy commands to tkinter
  • tk_busy.diff: Patch for tk_busy commands against default branch
  • tk_busy.patch: Regenerated for review
  • tk_busy.patch: Regenerated for review
  • tk_busy_3.diff
  • tk_busy_4.diff
  • tk_busy_5.diff
  • tk_busy_6.diff
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/serhiy-storchaka'
    closed_at = None
    created_at = <Date 2016-10-21.17:03:43.066>
    labels = ['expert-tkinter', '3.8', 'type-feature', 'library']
    title = 'tk busy command'
    updated_at = <Date 2018-02-22.01:06:47.241>
    user = 'https://bugs.python.org/tkinter'

    bugs.python.org fields:

    activity = <Date 2018-02-22.01:06:47.241>
    actor = 'ned.deily'
    assignee = 'serhiy.storchaka'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)', 'Tkinter']
    creation = <Date 2016-10-21.17:03:43.066>
    creator = 'tkinter'
    dependencies = []
    files = ['45190', '45193', '45199', '45200', '45230', '45231', '45277', '45337']
    hgrepos = []
    issue_num = 28498
    keywords = ['patch']
    message_count = 43.0
    messages = ['279140', '279168', '279171', '279196', '279210', '279216', '279223', '279226', '279232', '279244', '279246', '279247', '279252', '279262', '279272', '279274', '279277', '279280', '279282', '279283', '279286', '279287', '279289', '279290', '279291', '279292', '279293', '279294', '279295', '279300', '279302', '279322', '279323', '279505', '279506', '279507', '279510', '279675', '279726', '279738', '279746', '279990', '312521']
    nosy_count = 6.0
    nosy_names = ['klappnase', 'ned.deily', 'serhiy.storchaka', 'tkinter', 'GNJ', 'cheryl.sabella']
    pr_nums = []
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue28498'
    versions = ['Python 3.8']

    Linked PRs

    Activity

    1. tkinter commented on Oct 21, 2016

      tkintermannequin
      MannequinAuthor

      tcl tk 8.6.6 has a new busy command. The new tkinter library doesn't provide an interface for this command.

      https://www.tcl.tk/man/tcl/TkCmd/busy.htm

      The solution is to add to the class Misc of tkinter these methods:

      def tk_busy(self, *args, **kw):
          self.tk_busy_hold(*args, **kw)
          
      def tk_buy_hold(self, cnf=None, **kw)
          self.tk.call(('tk', 'busy', 'hold', self._w) + self._options(cnf, kw))
      
      def tk_buy_configure(self, cnf=None, **kw):
          self.tk.call(('tk', 'busy', 'configure', self._w) + self._options(cnf, kw))
          
      def tk_cget(self, option):
          return self.tk.call('tk', 'busy', 'cget', self._w, option)
      
      def tk_busy_forget(self):
          self.tk_call('tk', 'busy', 'forget', self._w)
      
      def tk_busy_current(self, pattern=None):
          if pattern is None:
              self.tk.call('tk', 'busy', 'current')
          else:
              self.tk.call('tk', 'busy', 'current', pattern)
      
      def tk_busy_status(self):
          return self.tk.call('tk', 'busy', 'status', self._w)
    2. added
      stdlibStandard Library Python modules in the Lib/ directory
      on Oct 21, 2016
    3. klappnase commented on Oct 21, 2016

      klappnasemannequin
      Mannequin

      Funny thing, just today I came across the same issue.
      So far I came up with an a little bit refined version of the OP's suggestions. Until now I have tested this with Python-2.7.9 and tk-8.6.0 on debian Jessie, I think the same code should work for Python-3 , too.
      The busy_current() function here always reports only the root window (the same when called from within wish, apparently a bug in this early version of Tk-8.6) so I was not able to figure out how to use and test the "pattern" option.

          def busy(self, **kw):
              '''Shortcut for the busy_hold() command.'''
              self.tk.call(('tk', 'busy', self._w) + self._options(kw))
      
          def busy_cget(self, option):
              '''Queries the busy command configuration options for
              this window.
              The window must have been previously made busy by
              the busy_hold() command. Returns the present value
              of the specified option. Option may have
              any of the values accepted by busy_hold().'''
              return(self.tk.call('tk', 'busy', 'cget', self._w, '-'+option))
      
          def busy_configure(self, cnf=None, **kw):
              '''Queries or modifies the tk busy command configuration
              options. The window must have been previously made busy by
              busy_hold(). Option may have any of the values accepted by
              busy_hold().
              Please note that the option database is referenced by the
              window. For example, if a Frame widget is to be made busy,
              the busy cursor can be specified for it by :
                  w.option_add("*Frame.BusyCursor", "gumby")'''
              if kw:
                  cnf = _cnfmerge((cnf, kw))
              elif cnf:
                  cnf = _cnfmerge(cnf)
              if cnf is None:
                  return(self._getconfigure(
                              'tk', 'busy', 'configure', self._w))
              if type(cnf) is StringType:
                  return(self._getconfigure1(
                              'tk', 'busy', 'configure', self._w, '-'+cnf))
              self.tk.call((
                  'tk', 'busy', 'configure', self._w) + self._options(cnf))
          busy_config = busy_configure
      
          def busy_current(self, pattern=None):
              '''Returns the widget objects of all widgets that are
              currently busy.
              If a pattern is given, only the path names of busy widgets
              matching PATTERN are returned. '''
              return([self._nametowidget(x) for x in
                      self.tk.splitlist(self.tk.call(
                         'tk', 'busy', 'current', self._w, pattern))])
      
          def busy_forget(self):
              '''Releases resources allocated by the busy() command for
              this window, including the transparent window. User events will
              again be received by the window. Resources are also released
              when the window is destroyed. The window must have been
              specified in the busy_hold() operation, otherwise an
              exception is raised.'''
              self.tk.call('tk', 'busy', 'forget', self._w)
      
          def busy_hold(self, **kw):
              '''Makes this window (and its descendants in the Tk window
              hierarchy) appear busy. A transparent window is put in front
              of the specified window. This transparent window is mapped
              the next time idle tasks are processed, and the specified
              window and its descendants will be blocked from user
              interactions. Normally update() should be called immediately
              afterward to insure that the hold operation is in effect before
              the application starts its processing. The following
              configuration options are valid:
                  -cursor cursorName
                      Specifies the cursor to be displayed when the widget
                      is made busy. CursorName can be in any form accepted
                      by Tk_GetCursor. The default cursor is "wait" on
                      Windows and "watch" on other platforms.'''
              self.tk.call((
                      'tk', 'busy', 'hold', self._w) + self._options(kw))
      
          def busy_status(self):
              '''Returns the busy status of this window.
              If the window presently can not receive user interactions,
              True is returned, otherwise False.'''
              return((self.tk.getboolean(self.tk.call(
                      'tk', 'busy', 'status', self._w)) and True) or False)
    4. klappnase commented on Oct 21, 2016

      klappnasemannequin
      Mannequin

      Oops, just made a quick test with Python3, and found that I had missed that types.StringType is no longer present. So to be compatible with Python3 the busy_configure() func ought to look like:

          def busy_configure(self, cnf=None, **kw):
              if kw:
                  cnf = _cnfmerge((cnf, kw))
              elif cnf:
                  cnf = _cnfmerge(cnf)
              if cnf is None:
                  return(self._getconfigure(
                              'tk', 'busy', 'configure', self._w))
              if isinstance(cnf, str):
                  return(self._getconfigure1(
                              'tk', 'busy', 'configure', self._w, '-'+cnf))
              self.tk.call((
                  'tk', 'busy', 'configure', self._w) + self._options(cnf))
    5. tkinter commented on Oct 22, 2016

      tkintermannequin
      MannequinAuthor

      Maybe it's better to add also these methods:
      busy = tk_busy
      busy_cget = tk_busy_cget
      busy_configure = tk_busy_configure
      busy_current = tk_busy_current
      busy_forget = tk_busy_forget
      busy_hold = tk_busy_hold
      busy_status = tk_busy_status

      Many other methods in tkinter module follow the same pattern. For example:

          iconbitmap = wm_iconbitmap
          iconify = wm_iconify
          group = wm_group
          geometry = wm_geometry
          focusmodel = wm_focusmodel
          frame = wm_frame
    6. klappnase commented on Oct 22, 2016

      klappnasemannequin
      Mannequin

      Ok, I investigated this a little further. First I noticed another bug with the code from my first post, the "self._w" must be omitted from the call to busy_current(), so the func should look like:

          def busy_current(self, pattern=None):
              return([self._nametowidget(x) for x in
                      self.tk.splitlist(self.tk.call(
                         'tk', 'busy', 'current', pattern))])

      I did then some more testing, the code now seems to work flawlessly both with Python-3.5.2 on windows 10 and with Python 2.7 on debian Jessie. So I finally prepared a patch (against the __init__.py file from the 3.5.2 windows installer). Following Miguel's suggestion I also added aliases prefixed with tk_ to the various busy_... methods.
      Since I am not familiar with Python's "official" test mechanisms, for now I wrote a simple script that does a number of calls to the tk_busy_... functions to test if everything works as expected:

      try:
      import Tkinter
      except:
      import tkinter as Tkinter
      #Tkinter.wantobjects = False

      root = Tkinter.Tk()
      f = Tkinter.Frame(root, name='f')
      f.pack(fill='both', expand=1)
      b=Tkinter.Button(f, name='b', text='hi', command=root.bell)
      b.pack(padx=100, pady=100)
      
      top = Tkinter.Toplevel(root, name='top')
      
      def test1():
          root.tk_busy()
      def test2():
          root.tk_busy_forget()
      def test3():
          root.tk_busy_hold(cursor='gumby')
      def test4():
          root.tk_busy_forget()
      def test5():
          root.tk_busy_hold()
          top.tk_busy(cursor='gumby')
          print(root.tk_busy_current())
          print(root.tk_busy_current(pattern='*t*'))
      def test6():
          print(root.tk_busy_current())
      def test7():
          root.tk_busy_configure(cursor='gumby')
      def test8():
          print(root.tk_busy_configure())
          print(root.tk_busy_configure('cursor'))
          print(root.tk_busy_cget('cursor'))
      def test9():
          print(root.tk_busy_status())
      def test10():
          root.tk_busy_forget()
          print(root.tk_busy_status())
          print(root.tk_busy_current())
      
      delay = 0
      for test in (test1, test2, test3, test4, test5, test6, test7,
                      test8, test9, test10):
          delay += 1000
          root.after(delay, test)
      
      root.mainloop()
    7. serhiy-storchaka commented on Oct 22, 2016

      Member

      Could you provide a patch against the default branch? See https://docs.python.org/devguide/ for help. The patch should include not just changes to the tkinter module, but tests for new methods (add new class in Lib/tkinter/test/test_tkinter/test_widgets.py). Unfortunately there is no appropriate place for documenting this feature in the module documentation, but new methods should have docstrings. Would be nice to add an entry in Doc/whatsnew/3.7.rst.

    8. tkinter commented on Oct 22, 2016

      tkintermannequin
      MannequinAuthor

      Thanks klappnase for your collaboration.

      I dont understand this function:
      def busy_status(self):
      '''Returns the busy status of this window.
      If the window presently can not receive user interactions,
      True is returned, otherwise False.'''
      return((self.tk.getboolean(self.tk.call(
      'tk', 'busy', 'status', self._w)) and True) or False)

      This pattern is not used in other functions that make use of self.tk.getboolean. These functions simply returns the value of self.tk.getboolean directly.

      The code of your function busy_configure() is very similar to Misc._configure(). I think that you are duplicating code. Other functions related to configuration like pack_configure() and place_configure() simply use self._options(). For example:
      def pack_configure(self, cnf={}, **kw):
      self.tk.call(
      ('pack', 'configure', self._w)
      + self._options(cnf, kw))

          def place_configure(self, cnf={}, **kw):
              self.tk.call(
                    ('place', 'configure', self._w)
                    + self._options(cnf, kw))

      I think that my proposal can do the job well. It follows the same pattern than the other functions:
      def tk_busy_configure(self, cnf=None, **kw):
      self.tk.call(('tk', 'busy', 'configure', self._w) + self._options(cnf, kw))

      But I am not totally sure whether it's better to call directly Misc._configure or Misc._options in this situation.

      Also if we follow the naming convention used in tkinter, it seems that we have to define first tk_busy_configure and then make this assignation:
      busy_configure = tk_busy_configure

    9. tkinter commented on Oct 22, 2016

      tkintermannequin
      MannequinAuthor

      Misc._configure is only used when the first Tcl command is the name of the widget.

      Very probably my proposal for tk_busy_configure is a better candidate because it follows the conventions used in tkinter (it's similar to pack_configure and place_configure):
      def tk_busy_configure(self, cnf=None, **kw):
      self.tk.call(('tk', 'busy', 'configure', self._w) + self._options(cnf, kw))

    10. klappnase commented on Oct 22, 2016

      klappnasemannequin
      Mannequin

      @miguel
      About tk_busy_configure():
      I strongly suggest that my version of tk_busy_configure() is better, since it behaves exactly like the usual configure() methods in Tkinter (which includes e.g. Canvas.itemconfigure() or Text.tag_configure()), i.e. you can not only change the values of the configuration options, but also query available options and their default values. I think *this* follows the usual Tkinter conventions.
      As you pointed out in your last post, I could not use _configure() directly for this, but had to "duplicate" the code with a slight modification, because of the order of arguments for tk_busy_configure().
      The reason that this construct is not used for pack_configure() is simply that widget.pack_configure() does not return anything if called without arguments (in fact it appears to be the very same as widget.pack()).

      About busy_status():
      the construct I use here is to work around the broken _getboolean() which does not always return True or False, but often returns None instead of False (if wantobjects==True). Therefore I used (unlike most Tkinter methods) tkapp.getboolean() directly, however quite a while ago I noticed that this was broken, too, and sometimes returned 0 or 1 instead of True or False. However I admit that I did not test right now if this is still the case, in fact I just copy'n'pasted it from code I already use and that works perfectly well (BTW, I suggested the same method to fix these issue with _getboolean() here some time ago, and of course I agree that it would be preferrable to fix _getboolean() and possibly tkapp.getboolean() in the first place).

      @serhiy
      Thanks for the link, I did not find the source tree on the new python web site (I admit I did not look too hard :) .
      I now added a patch against the default branch'es __init__.py . Doc strings are (still :) included. I also changed the function names according to Miguel's suggestion.
      I'll see if I find the time to add a proper test class one of these days (you guys make it really hard for outsiders to help out ;)

    11. tkinter commented on Oct 23, 2016

      tkintermannequin
      MannequinAuthor

      Hi klappnase,
      you are right with the function tk_busy_configure(). Maybe there is a little bit of code duplicated. I think that it's better to directly change the Tkinter function _configure() to make it more general:
      def _configure(self, cmd, cnf, kw):
      """Internal function."""
      if kw:
      cnf = _cnfmerge((cnf, kw))
      elif cnf:
      cnf = _cnfmerge(cnf)
      if cnf is None:
      return self._getconfigure(cmd)
      if isinstance(cnf, str):
      return self._getconfigure1(cmd + ('-'+cnf,))
      self.tk.call(cmd + self._options(cnf))

      I think that it's interesting to do this change because the function is more general and maybe can be used again in the future for new features in Tcl Tk. This way, we avoid code duplication (Dont Repeat Yourself is one of the philosophes of Python). This is the new version of tk_busy_configure using the mentioned change:
      def tk_busy_configure(self, cnf=None, **kw):
      return self._configure(('tk', 'busy', 'configure', self._w), cnf, kw)

      It's more concise.
      I disagree with tk_busy_status(). It's better to be more predictable an return the same than the other methods that uses getboolean(). If there is a bug, it's better to solve that bug. Could you please guive me an code example that replicates the bug?

      The _getboolean function is implemented in _tkinter.c. This is the implementation:
          static PyObject *
          Tkapp_GetBoolean (self, args)
               PyObject *self;
               PyObject *args;
          {
            char *s;
            int v;
        if (!PyArg_Parse (args, "s", &s))
          return NULL;
        if (Tcl_GetBoolean (Tkapp_Interp (self), s, &v) == TCL_ERROR)
          return Tkinter_Error (self);
        return Py_BuildValue ("i", v);
      }
      

      A priori , I can't appreciate any bug in this function. If there is some bug, it's in another place of the C code.

    12. 32 remaining items

    13. klappnase commented on Oct 26, 2016

      klappnasemannequin
      Mannequin

      This is something entirely different, since the commands you list here in tk do not accept keyword arguments at all.

    14. tkinter commented on Oct 29, 2016

      tkintermannequin
      MannequinAuthor

      Why dont we do the job well from the beginning and refactor _configure() and adapt other dependent code? It's not so complicated to change the dependent code. Many people around the world use Tkinter.

    15. serhiy-storchaka commented on Oct 30, 2016

      Member

      Added a number of style comments on Rietveld. I believe klappnase could address them, but since there are too little time to beta3 and I have a weak hope to push this in 3.6, I addressed them myself. Rewritten docstrings and test.

      Ned, is it good to add this feature in 3.6? The patch just adds a couple of new methods, it doesn't affect existing programs.

    16. ned-deily commented on Oct 30, 2016

      Member

      With ActiveState 8.6.4.1 (the most recent version available) on macOS:

      ======================================================================
      ERROR: test_tk_busy (tkinter.test.test_tkinter.test_misc.MiscTest)
      ----------------------------------------------------------------------

      Traceback (most recent call last):
        File "/py/dev/36/root/fwd_macports/Library/Frameworks/pytest_10.12.framework/Versions/3.6/lib/python3.6/tkinter/test/test_tkinter/test_misc.py", line 33, in test_tk_busy
          f.tk_busy_hold(cursor='gumby')
        File "/py/dev/36/root/fwd_macports/Library/Frameworks/pytest_10.12.framework/Versions/3.6/lib/python3.6/tkinter/__init__.py", line 849, in tk_busy_hold
          self.tk.call('tk', 'busy', 'hold', self._w, *self._options(kw))
      _tkinter.TclError: unknown option "-cursor"

    17. serhiy-storchaka commented on Oct 30, 2016

      Member

      Ah, yes, this feature is not supported on OSX/Aqua.

    18. serhiy-storchaka commented on Nov 3, 2016

      Member

      Updated patch skips tests with the cursor option on OSX/Aqua.

    19. csabella commented on Feb 22, 2018

      Contributor

      There was a lot of work put into this patch, but I don't think it's been committed yet. Are any of the original authors interested in converting this to a Github pull request on the master branch? Thanks!

    20. transferred this issue fromon Apr 10, 2022
    21. added a commit that references this issue on Aug 6, 2023
    22. added
      3.13only security fixes
      and removed on Aug 6, 2023
    23. added a commit that references this issue on Aug 19, 2023
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Labels

    3.13only security fixesstdlibStandard Library Python modules in the Lib/ directorytopic-tkintertype-featureA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL