Multithreading with tkinter

Recently, I got stuck with very new problem (for me) of updating GUI in Tkinter when long processes are needed to be run (like running a time-consuming loop, waiting for a process to complete and return or fetching something from URL). Actually, for processes requiring a long time to complete, the Tkinter blocks other GUI events. Because of it, updates to GUI element only happen when the process returns after completing execution.

I earlier didn’t know about the ‘thread safe’ property of python Tkinter. The main caveat here is that we can’t update GUI elements from multiple threads. Once main thread initiates the mainloop(), we can never use other thread to update the GUI. However, we can easily do background processes in other threads. But, here also we need to invoke a GUI function whenever the process in the background thread stops and returns the result. But, a GUI function can only be invoked through the thread executing mainloop().

Therefore, after reading some online resources on StackOverflow and other Python blogs, I came to know about one design pattern followed to solve this problem. Instead of invoking a GUI function, whenever the result is returned we need to maintain a shared queue. The contents of queue will be shared between the thread executing mainloop() and the thread running the background process. Whenever we need to return the result after the process ends in the background thread, we need to put the result in the queue. On the other side, the thread ( executing mainloop() ) needs to periodically check the contents of the shared queue. In my case, I couldn’t understand this concept of ‘shared queue’ just by reading about it. Therefore, let’s go through a small piece of code to understand it better.

def runloop(thread_queue=None):
    '''
    After result is produced put it in queue
    '''
    result = 0
    for i in range(10000000):
         #Do something with result
    thread_queue.put(result)

class MainApp(tk.Tk):

    def __init__(self):
        ####### Do something ######
        self.myframe = tk.Frame(self)
        self.myframe.grid(row=0, column=0, sticky='nswe')
        self.mylabel = tk.Label(self.myframe) # Element to be updated 
        self.mylabel.config(text='No message')
        self.mylabel.grid(row=0, column=0)
        self.mybutton = tk.Button(
            self.myframe, 
            text='Change message',
            command=lambda: self.update_text)
        self.mybutton.grid(row=1, column=0)

    def update_text(self):
        '''
        Spawn a new thread for running long loops in background
        '''
        self.mylabel.config(text='Running loop')
        self.thread_queue = queue.Queue()
        self.new_thread = threading.Thread(
            target=runloop,
            kwargs={'thread_queue':self.new_thread})
        self.new_thread.start()
        self.after(100, self.listen_for_result)

    def listen_for_result(self):
        '''
        Check if there is something in the queue
        '''
        try:
            self.res = self.thread_queue.get(0)
            self.mylabel.config(text='Loop terminated')
        except queue.Empty:
            self.after(100, self.listen_for_result)
        
if __name__ == "__main__":
    root = tk.Tk()
    main_app = MainApp(root)
    root.mainloop()

Here, we may need to disable the button, because it may happen that clicking mybutton may result in creating multiple new threads.

Advertisements

Page Screenshots in tkinter GUI

  1. Install from PyPI :welcome_page
  2. Update Page
    update_page
  3. Install from Requirement Page
    requirement_page
  4. Install from Local Archive
    local_archive
  5. Install from PyPI
    search_packages.png

These are some of the screenshots of the GUI application developed till now. Now, in a few days, I need to fix and give a final touch to these functionalities and write test modules for this GUI application.

Further work for next week are related to making this application multithreaded, implement advanced features and improve GUI experience. It is very necessary for me to complete the basic GUI application, so that I can get user feedback when this application is released with Python 3.6 in first week of July.

Design Patterns: How to write reusable and tidy software?

Referred from : Python Unlocked 2015

Hello everyone. In this blog post I am going to tell about a important concept in software development which I came through called “Design Patterns”.

In software engineering, problems requiring similar solutions are very common. Therefore people generally tend to come up with a repeatable design specification to deal with such common problems. Studying design patterns helps one to have a basic idea of existing solutions to such problems.

Few advantages of design patterns are :

  1. They speed up the development process by providing tested and robust paradigms for solving a problem.
  2. Improves code readability for programmers
  3. Documenting the code also becomes easy as a lot of solutions are based on common design pattern. Therefore, less efforts are required to document code.

Let’s come to different design patterns used by people in software engineering. They are mostly classified as follows :

  1. Observer pattern
  2. Strategy pattern
  3. Singleton pattern
  4. Template pattern
  5. Adaptor pattern
  6. Facade pattern
  7. Flyweight pattern
  8. Command pattern
  9. Abstract factory
  10. Registry pattern
  11. State pattern

Let’s have a brief overview of the above-mentioned design patterns :

  1. Observer Pattern :  The key to the observer pattern is “Spreading information to all listeners“. In other words, when we need to deal with a lot of listeners ( which always waiting for a particular event to be invoked ) we need to keep track of them and inform them about the occurence of an event ( For example, change of state of variable ). Below code snippet will help to make the situation more clear :
    class Notifier():
        """
        Provider of notifications to other objects
        """
        def __init__(self, name):
            self.name = name
            self._observers = Set()
    
        def register_observer(self, observer):
            """
            Function to attach other observers to this notifier
            """
            self._observers.add(observer)
            print("observer {0} now listening on {1}".format(observer.name, self.name))
        
        def notify_observers(self, msg):
            """
            transmit event to all interested observers
            """
            print("subject notifying observers about {}".format(msg,))
    
            for observer in self._observers:
                observer.notify(self, msg)
    
    class Observer():
        
        def __init__(self, name):
            self.name = name
    
        def start_observing(self, subject):
            """
            register for getting event for a subject
            """
            subject.register_observer(self)
    
        def notify(self, subject, msg):
            """
            notify all observers
            """
            print("{0} got msg from {1} that {2}".format(self.name, subject.name,msg))

    The above code snippet provides a very simple implementation of the Observer pattern. There is a notifier object which provides a method to register the listeners. And in the listeners ( the Observer object ) there is start_observing function to register with the notifier.

Menace of Global Variables

Hello everyone. In this week I had learnt a few things about writing beautiful and organized code. In the end of first week I started to write code. Initially my code base was very small, therefore I went on writing and writing more and more code and repeating same design patterns.

Therefore, for these problems what I learnt was code refactoring and design patterns. The first is one somewhat obvious that we need to mainatin code’s modularity and arrange related and similar pieces of code with each other in order to ensure easier debugging and extension of other features. Therefore, I refacored my code in a number of files namely :

  1. __init__.py
  2. __main__.py
  3. And other files like install_page.py, manage_installed_package.py, pip_extensions.py, utils.py and many others to be added depending on further features to be added.

In this process of code refactoring, I realised the menace of using global variables. One of the global variables was a Python dictionary, which was accessed by multiple functions. Therefore, when I grouped those functions in different files, my whole application failed. Then, I had to remove that global variable and make it a member variable of a class. In this case, correcting code was easy, but if I were to realise it a week or two later, then I think using global variables might would have wasted my whole day at that time.

Recently, I also went through a dozen design patterns in reaation to my GUI application. Therefore, my next post will be on Design Patterns.

Page Layouts and Application Flow of Logic

We have prepared some of the design layouts and application flow of logic of the ‘pip’ GUI. Some of the page layouts designed for the ‘pip’ GUI are :

1. Welcome Page

welcome_v1
Page Layout : Welcome Page

2. Configuration Page

select_venv_system
Page Layout : Configure Environment

3. Search and Install Page

install_pyPI_v1
Page Layout : ‘pip’ Search and Install

4. Install from requirements file

install_requirement_v1
Page Layout : Install From Requirement File

5. Install From Local Archive

install_local_archive_v1
Page Layout : Install From Local Archive

6. List, Update and Uninstall Package

update_package_v1
Page Layout : ‘pip’ List, Update and Uninstall

 

Now, workflow for application :

design_flow
Application Flow of Logic

Ist Design Iteration of ‘pip’ GUI

This is my first iteration of ‘pip’ GUI project. It is based on the design process explained in my last blog post. I am re-writing the steps needed for the design of an application :

  • Define the product
  • Define the target users
  • Define the user goals
  • Define the top user tasks : Focus on top six tasks
  • Define the user’s context : Know user’s context
  • Explain each top task to a friend
  • Map your natural explanation into a page flow
  • Design each page
  • Simplify and optimize the task flow and pages
  • Review the communication
  • Verify that purpose of each page and control is clear
  • Review the results

In this design iteration I have tried to follow those steps which are relevant to my application :

Product:

The product developed will be a GUI for pip to make various functionalities of pip ( a command line tool for installing Python packages) easily accessible to users. Main motivation behind the need for GUI version of Python Package Manager is :

  • Make various functionalities provided by PIP easily accessible to Windows/LINUX/Mac based users
  • Help people to focus only on fulfilling the task of installing Python packages rather than getting in unavoidable trouble of configuring various paths, versions and configurations

Target Users:

  1. Windows Users ( who have difficulty using command prompt )
  2. In case of LINUX or MacOS, people who have little or no experience with Python packages
  3. Users who maintain multiple versions of Python in their system
  4. Users who need to manage Python packages in virtualenv ( Last priority )

User Goals:

  1. Avoid command line to manage ( i.e. install/update/uninstall) Python packages
  2. Manage packages for different versions of Python installed in the system

User Tasks:

  1. Search, select version and install package ( including dependencies : first tell user about total download size including dependencies )
  2. Check for new updates and install them.
  3. Uninstall a package
  4. Support different installation methods :
    1. Requirements.txt files
    2. .whl files
    3. From local archives
  5. Manage packages in virtual environment

My next blog post provides a peek of GUI layout and application flow of logic.

My First GSoC Post : Notes on process of designing a GUI application

Notes on UI Principles

  • Don’t design like a programmer

    Link : http://www.uxdesignedge.com/2010/03/dont-design-like-a-programmer/

    This post explains the process of UI design in three parts :

    1. General mistakes made by programmers like using variable names as control labels, letting variable types determine control types, exposing raw and unformatted data, forcing user to enter data in specific format ( i.e. exposing representation invariants) and overusing messages.Three types of issues are pointed out :
      1. Simplicity Issues : Most common and probable cases should be optimized and easily accessible. User should be asked only what is extremely necessary to fulfill the task. It is better to ask for input values which users can provide easily and confidently.
      2. Life Cycle Issues : Initial UI state shouldn’t be blank as it will confuse the user about where to start from. All options and fields shouldn’t be disclosed at once. We should use progressive disclosure to hide infrequently used settings. Data structures shouldn’t be mapped directly to a UI element, as there may be case that some fields are a part of single object, but they don’t necessarily have to be provided by the user at the same time.
      3. Efficiency Issues : Frequent actions should be minimized. Reasonable values can be assumed for frequently used options or user’s history can be saved for frequently used options. Unexpected input should be handled properly.
    2. Second post explains the some key points related to solving above mentioned problems :
      1. Identify target users for improving user experience. Understand their goals and preferences. Identify use cases.
      2. UI should be self explanatory. There should not be any need for documentation.
      3. UI’s should be task centric, not feature centric.

      Basic design process :

      • Define the product
      • Define the target users
      • Define the user goals
      • Define the top user tasks : Focus on top six tasks
      • Define the user’s context : Know user’s context
      • Explain each top task to a friend
      • Map your natural explanation into a page flow
      • Design each page
      • Simplify and optimize the task flow and pages
      • Review the communication
      • Verify that purpose of each page and control is clear
      • Review the results
    3. Third post is a worked out example of above steps for a simple product. It may act as a reference.
  • User Interface Design for Programmers by Joel Spolsky

    This book contains one of the excellent ideas of UI design explained with very simple and practical examples.

    Most of the chapters after very good and contain illustrative discussions which conclude with axioms like :

    1. “ A user interface is well designed when the program model conforms to the user model. “
    2. “ Users will assume the simplest model possible. ”
    3. “ Every time you provide an option, you’re asking the user to make a decision.” : They will have to stop and think. In general number of decisions to be taken by user should be minimum.
    4. Use real metaphors for objects to relate them with reality.
    5. UI design should be consistent. UI designers shouldn’t use their creativity to make an UI which works in totally different way than other programs intended for same purpose.
    6. And many others …
  • Designing Interfaces by Jenifer Tidwell

    It explains UI design in technical depth and explains some concepts like affordances, visual hierarchy, navigational distance and use of color. In addition to it, use case of almost all UI elements like selector, pagination, cancellability, button groups, geometry managers etc. are thoroughly explained. Most importantly almost all chapters are followed by a Patterns section which includes all requirements to be achieved by a good software. I think this is one of the best resources to learn UI design in a technical manner. This book explains almost everything from organizing the content, navigation, organizing a page, using different UI elements to fulfill tasks, handling “verbs” of a interface ( i.e how to present actions and commands), discussing cognitive effects of data representation ( information graphics ) and finally tells how to use graphic design patterns to improve aesthetics and look & feel of UI.

  • A Collection of many UI design resources :

    https://whitneyhess.com/blog/2009/06/30/so-you-wanna-be-a-user-experience-designer-step-1-resources/

  • UX Design Concepts:

    http://www.usability.gov/what-and-why/user-experience.html