Whereas the
TkLayout
package simplifies creation of the visual layout of a Tkinter GUI, the TkPane
package simplifies the creation, use, and re-use of Tkinter widgets and groups of Tkinter widgets, particularly those that are used to collect or manage data, and that need to interact with other components of the GUI.The
TkPane
package provides a TkPane
class that can be subclassed to create custom 'pane' objects. Several general-purpose panes are provided in the tkpane.lib
module. Pane objects are completely stand-alone, with no inherent dependencies on any other components of the GUI. Pane objects have a standard set of methods, however, by which other panes (or other application code) can enable or disable those panes, or clear their displays. Pane objects also have internal lists of callback functions that are automatically executed when their data are changed to become valid, when their data are changed to become invalid, or when the user leaves the pane (via a keyboard focus change or a mouse movement). Dependencies between panes are easily established with the requires()
method. For example, the statementrun_button_pane.requires(input_file_pane)
ensures that the
run_button_pane
pane will be disabled when the input_file_pane
pane contains invalid data, and will be enabled when the input_file_pane
pane contains valid data. When one pane enables another, the first pane passes its own data to the second pane.The type of inter-pane interaction that is enabled by the
requires()
method may be all that is needed in many cases. If more complex interactions are required, however, callback lists can be modified directly to enable other types of inter-pane activation and data sharing.When a pane object is instantiated, the constructor method (
__init()__
) must be passed the Tkinter widget within which the frame will be embedded. Typically that parent widget is a frame. This required argument of pane constructors is identical to the argument that must be passed to the 'build' functions of TkLayout
objects. Consequently, TkLayout
and TkPane
objects work together very well, and the combination of the two practically eliminates all of the fiddling with visual and functional aspects of a GUI when using Tkinter directly.The following example shows how these two packages can be used together to easily build a Tkinter GUI interface by populating layout elements with panes. This example uses pane classes from
tkpane.lib
.try: import Tkinter as tk except: import tkinter as tk import tkpane.lib import tklayout import time # Add a method to the AppLayout class to get a pane: the first child of # a frame's widgets. def layout_pane(self, pane_name): return self.frame_widgets(pane_name)[0] tklayout.AppLayout.pane = layout_pane # Create simple sets of data to display in the TableDisplayPane. ds1_headers = ["Title", "Author", "Published"] ds1_data = [["Kon-Tiki: Across the Pacific in a Raft", "Thor Heyerdahl", 1950], ["Mawson's Will", "Lennard Bickel", 2000], ["Southern Cross to Pole Star - Tschiffely's Ride", "A. F. Tschiffely", 1933], ["The Hitchhiker's Guide to the Galaxy", "Douglas Adams", 1979]] ds2_headers = ["row_id","row_number","long_text","some_date","some_number"] ds2_data = [ ["Row 4",4,"Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem.","1951-03-19",61.9917173461], ["Row 8",8,"Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus.","1977-07-21",34.5729855806], ["Row 12",12,"DJs flock by when MTV ax quiz prog.","1983-10-12",2.3773967111] ] def build_message_pane(parent): tkpane.lib.MessagePane(parent, "Enter user credentials and an output directory.") def build_table_pane(parent): tkpane.lib.TableDisplayPane(parent, "This is an example message to accompany the data table that is long enough that it should wrap when the window is resized to a relatively small size.", ds1_headers, ds1_data) def build_button_pane(parent): def no_action(): pass tkpane.lib.OkCancelPane(parent, no_action, no_action) # Lay out the panes lo = tklayout.AppLayout() inp_panes = lo.row_elements(["user_pane", "output_pane"], row_weight=0) app = lo.column_elements(["message_pane", inp_panes, "table_pane", "button_pane", "status_pane"], row_weights=[0,0,1,0,0]) root = tk.Tk() root.title("Demo of the TkPane Package") # Use an extra frame within the root element with padding to add extra space # around the outermost app widgets. appframe = tk.Frame(root, padx=11, pady=11) appframe.pack(expand=True, fill=tk.BOTH) lo.create_layout(appframe, app) lo.build_elements({"message_pane": build_message_pane, "user_pane": tkpane.lib.UserPane, "output_pane": tkpane.lib.OutputDirPane, "table_pane": build_table_pane, "button_pane": build_button_pane, "status_pane": tkpane.lib.StatusProgressPane }) # Get the pane objects for customization. user_pane = lo.pane("user_pane") output_pane = lo.pane("output_pane") button_pane = lo.pane("button_pane") status_pane = lo.pane("status_pane") table_pane = lo.pane("table_pane") # Require a user name and output directory to be entered for the 'OK' button # to be enabled. button_pane.requires(user_pane) button_pane.requires(output_pane) # Start the demo application with the 'OK' button disabled. tkpane.en_or_dis_able_all([button_pane]) # Make the user and output directory panes report their status. user_pane.status_reporter = status_pane output_pane.status_reporter = status_pane # Make the buttons change the data and the status bar. def ok_click(*args): status_pane.set_status("OK button clicked.") time.sleep(0.5) status_pane.set_status("Working...") for p in range(10, 110, 10): status_pane.set_value(p) root.update_idletasks() time.sleep(0.5) status_pane.set_status("Done.") table_pane.display_data(ds2_headers, ds2_data) button_pane.set_ok_action(ok_click) def cancel_click(*args): status_pane.clear([]) button_pane.set_cancel_action(cancel_click) # Bindand to the buttons. root.bind(" ", ok_click) root.bind(" ", cancel_click) # Run the application root.mainloop()
This code produces a GUI with the initial appearance shown below. The background of the output directory entry is automatically colored to indicate that it is required but does not contain valid data.
As this example illustrates, the re-usability of pane classes allows Tkinter GUIs to be created with almost no Tkinter code.
The
TkPane
package can be downloaded from the Python Package Index (PyPI), or installed with pip.pip install tkpane
The documentation for
TkPane
is available on ReadTheDocs.
No comments:
Post a Comment