Managing user preferences

A very common theme in several GUI programs involves letting the user set the program's preferences.

For example, what if we want users to be able to customize the chessboard colors? What if we want users to select colors and, once selected, it is saved as a user preference and it is loaded the next time the program is run? Let's implement this as a feature.

Python offers a standard module called configparser that lets us save user preferences. Let's see the configparser module in action.

To begin with, import the ConfigParser class from the configparser module in the configurations.py file, as follows (see 4.07 preferenceswindow.py):

from configparser import ConfigParser

The configparser module uses the .ini files to store and read the configuration values. The file consists of one or more named sections. These sections contain individual options with names and values.

To illustrate this, let's create a file called chess_options.ini in the project's root folder (see 4.07). The file looks like this:

[chess_colors]
board_color_1 = #DDB88C
board_color_2 = #A66D4F
highlight_color = #2EF70D

The first line of the file enclosed in square brackets ([chess_colors] in our example) is called a section. A .ini file can have multiple sections. This file has a single section. Each section can have multiple key-value options, as specified in the example.

We can read these values in our program by using the getter methods, as follows (see 4.07configurations.py):

config = ConfigParser()
config.read('chess_options.ini')
BOARD_COLOR_1 = config.get('chess_colors', 'board_color_1',
fallback="#DDB88C")
BOARD_COLOR_2 = config.get('chess_colors', 'board_color_2', fallback =
"#A66D4F")
HIGHLIGHT_COLOR =config.get('chess_colors', 'highlight_color', fallback
= "#2EF70D")

The preceding code replaces the three color constants that we defined earlier in the code.

Now, if you change the options in the .ini file, the color of the chessboard changes accordingly. However, we cannot expect end users to be conversant with editing the .ini files. Therefore, we will let them choose the colors using the color chooser module of Tkinter. A color that a user chooses gets reflected in the .ini file and consequently on the chessboard.

When a user clicks on the Edit | Preference menu item, we want to open a transient window with three different buttons to choose two chessboard colors and one highlight color. Clicking on a single button opens a color select window, as shown in the following screenshot:

We created this transient window in a new file called preferenceswindow.py (see 4.07.py). We will not discuss the code that creates this window, as this should be an easy task for you now.

Note that this window is converted into a transient window with respect to the top-level window by using the following code:

self.pref_window.transient(self.parent)

As a reminder, a transient window is one that always stays at the top of its parent window. It gets minimized when its parent window is minimized. For a quick refresher on transient windows, refer to Chapter 2, Making a Text Editor,—2.06.py.
As we have created the window in preferencewindow.py, we'll import it into the View class as follows (see 2.07view.py):

import preferenceswindow

Then, command bind the preference menu by using the following two methods:

def on_preference_menu_clicked(self):
self.show_prefereces_window()

def show_prefereces_window(self):
preferenceswindow.PreferencesWindow(self)

When a user clicks on the Cancel button, we simply want the settings window to close. To do this, use the following code (see 4.07preferencewindow.py):

def on_cancel_button_clicked(self):
self.pref_window.destroy()

When a user changes the colors and clicks on the Save button, the method calls the set_new_values() method, which first writes the new values to the .ini file and then returns the values to the View class to update the chessboard immediately:

def set_new_values(self):
color_1 = self.board_color_1.get()
color_2 = self.board_color_2.get()
highlight_color = self.highlight_color.get()
config = ConfigParser()
config.read('chess_options.ini')
config.set('chess_colors', 'board_color_1',color_1)
config.set('chess_colors', 'board_color_2',color_2)
config.set('chess_colors', 'highlight_color', highlight_color)
configurations.BOARD_COLOR_1 = self.board_color_1.get()
configurations.BOARD_COLOR_2 = self.board_color_2.get()
configurations.HIGHLIGHT_COLOR = self.highlight_color.get()
with open('chess_options.ini', 'w') as config_file:
config.write(config_file)

When the preceding code writes the new values to the .ini file, call the reload_colors() method from the View class to update the chessboard's color immediately. If you do not do this, the color change will take place the next time the chess program is run (see 4.07view.py):

def reload_colors(self, color_1, color_2, highlight_color):
self.board_color_1 = color_1
self.board_color_2 = color_2
self.highlight_color = highlight_color
self.draw_board()
self.draw_all_pieces()

Having changed these attributes, we call draw_board() and draw_all_pieces() to repaint the chessboard in the newly defined colors. (see 4.07view.py).

This concludes the iteration. The users of the program can change the colors to match their preferences, and the program will remember the chosen values.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.113.163