• R/O
  • SSH

tkpane: Commit

Default repository for tkpane.py.


Commit MetaInfo

Revisão35d6d2356679455911125cb370c445028a25c993 (tree)
Hora2018-02-22 13:14:46
AutorDreas Nielsen <dreas.nielsen@gmai...>
CommiterDreas Nielsen

Mensagem de Log

Added 'set_key()' methods to lib where missing, and added 'build_ui()' method.

Mudança Sumário

Diff

diff -r 06822cf5eee9 -r 35d6d2356679 CHANGELOG.rst
--- a/CHANGELOG.rst Wed Feb 21 13:06:03 2018 -0800
+++ b/CHANGELOG.rst Wed Feb 21 20:14:46 2018 -0800
@@ -4,11 +4,12 @@
44 ========== ======= =================================================================================
55 Date Version Revision
66 ========== ======= =================================================================================
7+2018-02-21 0.14.0 Modified internal callback methods, corrected Python 3 compatibility in status reporting, added 'set_key()' methods in tkpane.lib where missing, and added 'build_ui()'.
78 2018-02-19 0.11.0 Added TableSelectPane to lib.
8-2018-02-10 0.10.0 Backwards-incompatible changed to 'clear_data()'; added 'clear_own()'. Added generic panes to lib.
9+2018-02-10 0.10.0 Backwards-incompatible changes to 'clear_data()'; added 'clear_own()'. Added generic panes to lib.
910 2018-02-09 0.9.2 Modified 'clear_data()' to call the 'on_clear' callbacks only if any of the pane's own valid data are cleared.
1011 2018-02-08 0.9.0 Added 'focus()', 'can_use(), and 'all_data()' methods.
11-2018-02-04 0.8.1 Added the 'set()' method.
12+2018-02-04 0.8.1 Added the 'set_data()' method.
1213 2018-02-03 0.8.0 Revised action callback mechanism, added default and custom styling, added EntryPane to lib.
1314 2018-01-29 0.5.0 Working TkPane and 9 general-purpose panes in tkpane.lib.
1415 ========== ======= =================================================================================
diff -r 06822cf5eee9 -r 35d6d2356679 doc/source/conf.py
--- a/doc/source/conf.py Wed Feb 21 13:06:03 2018 -0800
+++ b/doc/source/conf.py Wed Feb 21 20:14:46 2018 -0800
@@ -55,9 +55,9 @@
5555 # built documents.
5656 #
5757 # The short X.Y version.
58-version = u'0.12.1'
58+version = u'0.14.1'
5959 # The full version, including alpha/beta/rc tags.
60-release = u'0.12.1'
60+release = u'0.14.1'
6161
6262 # The language for content autogenerated by Sphinx. Refer to documentation
6363 # for a list of supported languages.
diff -r 06822cf5eee9 -r 35d6d2356679 doc/source/index.rst
--- a/doc/source/index.rst Wed Feb 21 13:06:03 2018 -0800
+++ b/doc/source/index.rst Wed Feb 21 20:14:46 2018 -0800
@@ -380,6 +380,10 @@
380380 behavior of this method, however, and the arguments that it takes,
381381 can be overridden in each subclass.
382382
383+set_key(key_name) [or set_keys(key_name1, key_name2, ...)]
384+ Changes the key (or keys) used to identify data items managed by
385+ this pane in its internal data dictionary.
386+
383387 valid_data()
384388 Returns a Boolean indicating whether or not valid data have been
385389 entered into the pane. This method must be overridden by subclasses
@@ -419,12 +423,12 @@
419423 Action Method Handling Classes
420424 --------------------------------------------------------------
421425
422-Every callback function used by a pane must be wrapped in one of the
423-following Handler classes. This conversion of callback functions to
424-Handler objects is performed automatically by the ``requires()`` method
425-of the ``TkPane`` class. If items are to be added to the callback
426-lists directly by the UI implementer, these Handler classes must be
427-used.
426+Every callback function used by a pane must be wrapped in one of the
427+following callback handler (CbHandler) classes. This conversion of
428+callback functions to CbHandler objects is performed automatically by the
429+``requires()`` method of the ``TkPane`` class. If items are to be
430+added to the callback lists directly by the UI implementer, these
431+CbHandler classes must be used.
428432
429433 .. autoclass:: CbHandler
430434 :members:
@@ -439,6 +443,19 @@
439443 :members:
440444
441445
446+Functions
447+--------------------------------------------------------------
448+
449+Several functions in the ``tkpane`` package simplify the initialization
450+of a UI or the integration of the ``tkpane`` and ``tklayout`` libraries.
451+
452+.. autofunction:: enable_or_disable_all
453+
454+.. autofunction:: layout_panes
455+
456+.. autofunction:: build_ui
457+
458+
442459 The Pane Library
443460 --------------------------------------------------------------
444461
@@ -594,42 +611,19 @@
594611
595612 The first three of these are illustrated in the following code, which
596613 creates a simple pane containing a Tkinter Entry widget. This is
597-actually a slightly modified version of the ``EntryPane`` class from
614+a slightly modified version of the ``EntryPane`` class from
598615 ``tkpane.lib``.
599616
600617 .. code-block:: python
601- :linenos:
602618
603- import tkpane
604- try:
605- import ttk
606- except:
607- from tkinter import ttk
608-
609-
610619 class EntryPane(tkpane.TkPane):
611- """Display a Tkinter Entry widget.
612-
613- Data keys managed by this pane: "entry".
614- Name used by this pane: user-defined on initialization.
615-
616- Overridden methods:
617- * entry_widgets
618- * valid_data
619- * save_data
620- * clear_pane
621- * enable_pane
622- * disable_pane
623- * focus
624- """
625-
626- def __init__(self, parent, pane_name, prompt):
627- tkpane.TkPane.__init__(self, parent, pane_name, config_opts={"padx": 7, "pady":7}, grid_opts={})
628- self.datakeylist = ["entry"]
620+ def __init__(self, parent, pane_name, prompt, key_name=None):
621+ tkpane.TkPane.__init__(self, parent, pane_name, {}, {})
622+ self.datakeyname = "entry" if key_name is None else key_name
623+ self.datakeylist = [self.datakeyname]
629624 self.prompt = ttk.Label(self, text=prompt, width=max(12, len(prompt)), anchor=tk.E)
630625 self.entry_var = tk.StringVar()
631- self.entry_var.trace("w", self.check_entrychange)
632- self.entrywidget = tk.Entry(self, textvariable=self.entry_var)
626+ self.entrywidget = ttk.Entry(self, textvariable=self.entry_var, exportselection=False)
633627 self.prompt.grid(row=0, column=0, padx=3, pady=3, sticky=tk.EW)
634628 self.entrywidget.grid(row=0, column=1, padx=3, pady=3, sticky=tk.EW)
635629 self.rowconfigure(0, weight=1)
@@ -637,6 +631,7 @@
637631 self.columnconfigure(1, weight=1)
638632 parent.rowconfigure(0, weight=1)
639633 parent.columnconfigure(0, weight=1)
634+ self.entry_var.trace("w", self.check_entrychange)
640635
641636 #---------------------------------------------------------------------------
642637 # Overrides of class methods.
@@ -656,7 +651,7 @@
656651 if text == "":
657652 self.clear_own()
658653 else:
659- self.datadict["entry"] = text
654+ self.datadict[self.datakeyname] = text
660655 else:
661656 self.clear_own()
662657
@@ -664,48 +659,73 @@
664659 self.entry_var.set("")
665660
666661 def enable_pane(self):
667- self.entrywidget.configure(state=tk.NORMAL)
662+ self._enablewidgets([self.prompt, self.entrywidget])
668663
669664 def disable_pane(self):
670- self.entrywidget.configure(state="readonly")
665+ self._disablewidgets([self.prompt, self.entrywidget])
666+
667+ def set_style(self, ttk_style):
668+ self._setstyle([self.prompt, self.entrywidget], ttk_style)
671669
672670 def focus(self):
671+ """Set the focus to the entry."""
673672 self.entrywidget.focus_set()
674-
673+
674+ def set_data(self, data):
675+ """Update the pane's data dictionary with the provided data.
676+
677+ Special key supported: 'prompt' changes the pane's prompt.
678+ """
679+ spkey = "prompt"
680+ if spkey in data:
681+ self.prompt.configure(text=data[spkey])
682+ self.set_allbut(data, [spkey])
683+
675684 #---------------------------------------------------------------------------
676685 # Custom methods.
677686 #...........................................................................
678687
679688 def check_entrychange(self, *args):
680689 self.handle_change_validity(self.valid_data(None), self.entrywidget)
690+
691+ def set_key(self, key_name):
692+ """Change the name of the data key used for the entered data.
693+
694+ :param key_name: New name for the data key.
695+
696+ This method allows the name of the data key to be customized to
697+ eliminate conflicts with other EntryPane objects on the same UI.
698+ """
699+ if self.datakeyname in self.datadict:
700+ self.datadict[key_name] = self.datadict[self.datakeyname]
701+ del self.datadict[self.datakeyname]
702+ self.datakeyname = key_name
703+ self.datakeylist = [key_name]
681704
682705
683706 The arguments for the ``__init__`` constructor method for this class are:
684707
685-* parent: The Tkinter widget that will be the parent for this pane.
708+* *parent:* The Tkinter widget that will be the parent for this pane.
686709 All ``TkPane`` subclasses must take this argument and pass it on to
687710 the ``TkPane`` class's own constructor method.
688-* pane_name: A text string used to identify the pane in
711+* *pane_name:* A text string used to identify the pane in
689712 automatically-generated status messages. Some ``TkPane`` subclasses
690713 may assign this themselves, but in this case it is provided by the
691714 user in case multiple ``EntryPane`` objects are used, and they are
692715 to be distinguished in status messages.
693-* prompt: This is the text that will be displayed in a Tkinter Label
716+* *prompt:* This is the text that will be displayed in a Tkinter Label
694717 widget adjacent to the Entry widget.
695-
696-The ``__init__`` method arguments for other panes, including most of
697-those in ``tkpane.lib``, are simpler, and consist only of the parent
698-widget.
718+* *key_name:* A substitute for the default data key name of "entry".
699719
700720 The ``__init__`` method for a custom pane must call the constructor
701721 method for the ``TkPane`` class itself. The arguments for this call are:
702722
703-* parent: The Tkinter widget that will be the parent for this pane.
704-* pane_name: A text string used to identify the pane in status messages.
705-* config_opts: A dictionary of Tkinter configuration option that will
723+* *parent:* The Tkinter widget that will be the parent for this pane.
724+* *pane_name:* A text string used to identify the pane in status messages.
725+* *config_opts:* A dictionary of Tkinter configuration option that will
706726 be applied to the Frame widget that encloses this pane's widgets.
707727 This argument is optional.
708-* grid_opts: A dictionary of Tkinter options for the ``grid()``
728+* *grid_opts:* A dictionary of Tkinter options for the ``grid()``
709729 geometry manager that will be applied to this pane's frame when it
710730 is placed within its parent. By default, a pane's frame is made
711731 sticky to the N, S, E, and W, and made resizeable in both vertical
@@ -802,13 +822,6 @@
802822 import tklayout
803823
804824
805- # Add a method to the tklayout AppLayout class to get a pane: the first
806- # child of a frame's widgets.
807- def layout_pane(self, pane_name):
808- return self.frame_widgets(pane_name)[0]
809- tklayout.AppLayout.pane = layout_pane
810-
811-
812825 class MemDb(object):
813826 # An in-memory SQLite database for a single data table named "src".
814827 def __init__(self):
@@ -817,7 +830,7 @@
817830 self.column_names = None
818831 self.tablename = "src"
819832 def quote_str(self, str):
820- # Add single quotes around a string.
833+ """Add single quotes around a string."""
821834 if len(str) == 0:
822835 return "''"
823836 if len(str) == 1:
@@ -881,13 +894,19 @@
881894 # Create a context for variables to be shared.
882895 sharedvars = {}
883896
897+ #-------------- Model -----------------
898+ # Create the database connection for the CSV file and
899+ # put it in the shared context.
900+ sharedvars["db"] = MemDb()
901+
902+ #-------------- View -----------------
884903 # Lay out the panes.
885- lo = tklayout.AppLayout()
904+ layout = tklayout.AppLayout()
886905 # A row with 1) a listbox to select column headers, and
887906 # 2) a table display for the table.
888- displays = lo.row_elements(["headerlist", "table"], column_weights=[1,2])
907+ displays = layout.row_elements(["headerlist", "table"], column_weights=[1,2])
889908 # A prompt for an input file above the listbox and table.
890- app = lo.column_elements(["infile_pane", displays], row_weights=[0,1])
909+ app = layout.column_elements(["infile_pane", displays], row_weights=[0,1])
891910
892911 root = tk.Tk()
893912 root.title("CSV File Explorer")
@@ -897,47 +916,38 @@
897916 appframe = tk.Frame(root, padx=11, pady=11)
898917 appframe.pack(expand=True, fill=tk.BOTH)
899918
900- # Create the frames that implement the layout.
901- lo.create_layout(appframe, app)
902-
903- # Use the pane class constructors to populate each UI element in the layout.
904- lo.build_elements({"infile_pane": lambda p: tkpane.lib.InputFilePane(p,
905- optiondict={"filetypes": (("CSV files", "*.csv"),)}),
906- "headerlist": lambda p: tkpane.lib.ListboxPane(p,
907- "headers", [], width=10),
908- "table": lambda p: tkpane.lib.TableDisplayPane(p,
909- message="Mouse over the table to refresh.")
910- })
911-
912- # Get references to the actual pane objects so that they can be customized.
913- infile_pane = lo.pane("infile_pane")
914- headerlist = lo.pane("headerlist")
915- table = lo.pane("table")
919+ panes = tkpane.build_ui(layout, appframe, app, {
920+ "infile_pane": lambda p: tkpane.lib.InputFilePane(p,
921+ optiondict={"filetypes": (("CSV files", "*.csv"),)}),
922+ "headerlist": lambda p: tkpane.lib.ListboxPane(p,
923+ "headers", [], width=10),
924+ "table": lambda p: tkpane.lib.TableDisplayPane(p,
925+ message="Mouse over the table to refresh.")
926+ })
916927
917- # Set dependencies.
918- headerlist.requires(infile_pane)
919- table.requires(headerlist, enable_on_other_exit_only=True, clear_on_disable=True)
920-
921- # Set custom callbacks to populate the listbox and table display.
922- headerlist.on_enable.append(tkpane.PaneAllDataHandler(set_listbox_contents))
923- table.on_enable.append(tkpane.PaneAllDataHandler(populate_table))
928+ # Set dependencies among panes.
929+ panes.headerlist.requires(panes.infile_pane)
930+ panes.table.requires(panes.headerlist, enable_on_other_exit_only=True, clear_on_disable=True)
924931
925- # Create the database connection for the CSV file and put it in
926- # the shared context.
927- sharedvars["db"] = MemDb()
928-
932+ #-------------- Controller -----------------
933+ # Set custom callbacks to populate the listbox and table display.
934+ panes.headerlist.on_enable.append(tkpane.PaneAllDataHandler(set_listbox_contents))
935+ panes.table.on_enable.append(tkpane.PaneAllDataHandler(populate_table))
936+
929937 # Give the shared variable context to the listbox and table panes
930- # so they can access those data without using globals.
931- # (This tests/demonstrates persistence of non-pane-specific data
932- # in the data dictionaries of these panes.)
933- headerlist.set_data(sharedvars)
934- table.set_data(sharedvars)
938+ # so they (their controller functions) can access the data (model).
939+ panes.headerlist.set_data(sharedvars)
940+ panes.table.set_data(sharedvars)
935941
936- # Run the app.
942+ #-------------- Run -----------------
937943 root.mainloop()
938944
945+
939946 main()
940947
948+As this example illustrates, if suitable pane classes are available,
949+a Tkinter UI can be assembled, and its elements linked together,
950+without any direct use of Tkinter objects or methods.
941951
942952
943953 Notes
@@ -950,15 +960,29 @@
950960
951961 .. note::
952962
953- The background color is not getting refreshed on themed (ttk)
954- widgets.
963+ The 'invalid' background color is not getting properly set on
964+ themed (ttk) widgets with some versions of Linux.
955965
956-2. The ``status_reporter`` attribute of a pane, if used, must be set
966+2. Every pane that manages data must have a dictionary key (or keys)
967+ to identify the data value(s). Every pane class in ``tkpane.lib``
968+ has a default name (or names) for these data key(s). When multiple
969+ panes of the same class are on the same UI, their data key names
970+ will coincide, and this may be a conflict if any other pane (or
971+ application code) uses the data dictionary from more than one of
972+ those panes. Each pane class therefore has a ``set_key()`` or
973+ ``set_keys()`` method that allows the data key(s) to be changed.
974+ Some pane classes also accept a new data key name as an
975+ initialization parameter. If the data keys of any pane must be
976+ changed when the UI is created, those changes must be made *before*
977+ any dependencies are established with the ``requires()`` or
978+ ``can_use()`` methods.
979+
980+3. The ``status_reporter`` attribute of a pane, if used, must be set
957981 to an object (e.g., another pane) that has a ``set_status()`` method
958982 and, if needed, a ``clear_status()`` method. The ``StatusProgressPane``
959983 and ``TextPane`` classes in ``tkpane.lib`` have these methods.
960984
961-3. The ``progress_reporter`` attribute of a pane, if used, must be set
985+4. The ``progress_reporter`` attribute of a pane, if used, must be set
962986 to an object (e.g., another pane) that has the following methods:
963987
964988 * ``set_determinate()``: Sets the progress bar to alter the progress
@@ -987,17 +1011,25 @@
9871011
9881012
9891013
1014+Related Software
1015+=================================================
9901016
991-.. include:: ../../CHANGELOG.rst
992-
993-
994-
1017+**TkLayout** (`code <https://pypi.org/project/tklayout/>`_ and `documentation <http://tklayout.readthedocs.io/en/latest/>`_)
1018+ The TkLayout Python package simplifies the construction of a Tkinter
1019+ interface by allowing the developer to describe the structure of the
1020+ UI from the inside out, as successive nestings of rows and
1021+ columns of elements, and then to create all of the Tkinter frames
1022+ to implement this structure with one command. Although ``tklayout``
1023+ and ``tkpane`` can be used entierly independently, they work together
1024+ well because panes can easily be used to fill the UI elements defined
1025+ in the layout. Examples 1 and 3 both show the use of ``tklayout``
1026+ with ``tkpane``.
9951027
9961028
9971029 Copyright and License
9981030 ================================================================
9991031
1000-Copyright :raw-html:`&copy;` 2018, R.Dreas Nielsen
1032+**Copyright** :raw-html:`&copy;` **2018, R.Dreas Nielsen**
10011033
10021034 This program is free software: you can redistribute it and/or modify it
10031035 under the terms of the GNU General Public License as published by the Free
@@ -1018,6 +1050,12 @@
10181050
10191051
10201052
1053+.. include:: ../../CHANGELOG.rst
1054+
1055+
1056+
1057+
1058+
10211059 Index
10221060 ==================
10231061
diff -r 06822cf5eee9 -r 35d6d2356679 setup.py
--- a/setup.py Wed Feb 21 13:06:03 2018 -0800
+++ b/setup.py Wed Feb 21 20:14:46 2018 -0800
@@ -2,7 +2,7 @@
22
33 setup(name='tkpane',
44 packages=['tkpane'],
5- version='0.12.1',
5+ version='0.14.1',
66 description="Encapsulates Tkinter UI elements in 'panes' that can be combined into an overall UI, integrating them by specifying callback functions and data keys.",
77 author='Dreas Nielsen',
88 author_email='dreas.nielsen@gmail.com',
diff -r 06822cf5eee9 -r 35d6d2356679 test/test_read_csv.py
--- a/test/test_read_csv.py Wed Feb 21 13:06:03 2018 -0800
+++ b/test/test_read_csv.py Wed Feb 21 20:14:46 2018 -0800
@@ -27,13 +27,6 @@
2727 import tklayout
2828
2929
30-# Add a method to the tklayout AppLayout class to get a pane: the first
31-# child of a frame's widgets.
32-def layout_pane(self, pane_name):
33- return self.frame_widgets(pane_name)[0]
34-tklayout.AppLayout.pane = layout_pane
35-
36-
3730 class MemDb(object):
3831 # An in-memory SQLite database for a single data table named "src".
3932 def __init__(self):
@@ -106,13 +99,19 @@
10699 # Create a context for variables to be shared.
107100 sharedvars = {}
108101
102+ #-------------- Model -----------------
103+ # Create the database connection for the CSV file and
104+ # put it in the shared context.
105+ sharedvars["db"] = MemDb()
106+
107+ #-------------- View -----------------
109108 # Lay out the panes.
110- lo = tklayout.AppLayout()
109+ layout = tklayout.AppLayout()
111110 # A row with 1) a listbox to select column headers, and
112111 # 2) a table display for the table.
113- displays = lo.row_elements(["headerlist", "table"], column_weights=[1,2])
112+ displays = layout.row_elements(["headerlist", "table"], column_weights=[1,2])
114113 # A prompt for an input file above the listbox and table.
115- app = lo.column_elements(["infile_pane", displays], row_weights=[0,1])
114+ app = layout.column_elements(["infile_pane", displays], row_weights=[0,1])
116115
117116 root = tk.Tk()
118117 root.title("CSV File Explorer")
@@ -122,43 +121,30 @@
122121 appframe = tk.Frame(root, padx=11, pady=11)
123122 appframe.pack(expand=True, fill=tk.BOTH)
124123
125- # Create the frames that implement the layout.
126- lo.create_layout(appframe, app)
127-
128- # Use the pane class constructors to populate each UI element in the layout.
129- lo.build_elements({"infile_pane": lambda p: tkpane.lib.InputFilePane(p,
130- optiondict={"filetypes": (("CSV files", "*.csv"),)}),
131- "headerlist": lambda p: tkpane.lib.ListboxPane(p,
132- "headers", [], width=10),
133- "table": lambda p: tkpane.lib.TableDisplayPane(p,
134- message="Mouse over the table to refresh.")
135- })
136-
137- # Get references to the actual pane objects so that they can be customized.
138- infile_pane = lo.pane("infile_pane")
139- headerlist = lo.pane("headerlist")
140- table = lo.pane("table")
124+ panes = tkpane.build_ui(layout, appframe, app, {
125+ "infile_pane": lambda p: tkpane.lib.InputFilePane(p,
126+ optiondict={"filetypes": (("CSV files", "*.csv"),)}),
127+ "headerlist": lambda p: tkpane.lib.ListboxPane(p,
128+ "headers", [], width=10),
129+ "table": lambda p: tkpane.lib.TableDisplayPane(p,
130+ message="Mouse over the table to refresh.")
131+ })
141132
142- # Set dependencies.
143- headerlist.requires(infile_pane)
144- table.requires(headerlist, enable_on_other_exit_only=True, clear_on_disable=True)
145-
146- # Set custom callbacks to populate the listbox and table display.
147- headerlist.on_enable.append(tkpane.PaneAllDataHandler(set_listbox_contents))
148- table.on_enable.append(tkpane.PaneAllDataHandler(populate_table))
133+ # Set dependencies among panes.
134+ panes.headerlist.requires(panes.infile_pane)
135+ panes.table.requires(panes.headerlist, enable_on_other_exit_only=True, clear_on_disable=True)
149136
150- # Create the database connection for the CSV file and put it in
151- # the shared context.
152- sharedvars["db"] = MemDb()
153-
137+ #-------------- Controller -----------------
138+ # Set custom callbacks to populate the listbox and table display.
139+ panes.headerlist.on_enable.append(tkpane.PaneAllDataHandler(set_listbox_contents))
140+ panes.table.on_enable.append(tkpane.PaneAllDataHandler(populate_table))
141+
154142 # Give the shared variable context to the listbox and table panes
155- # so they can access those data without using globals.
156- # (This tests/demonstrates persistence of non-pane-specific data
157- # in the data dictionaries of these panes.)
158- headerlist.set_data(sharedvars)
159- table.set_data(sharedvars)
143+ # so they (their controller functions) can access the data (model).
144+ panes.headerlist.set_data(sharedvars)
145+ panes.table.set_data(sharedvars)
160146
161- # Run the app.
147+ #-------------- Run -----------------
162148 root.mainloop()
163149
164150
diff -r 06822cf5eee9 -r 35d6d2356679 tkpane/lib.py
--- a/tkpane/lib.py Wed Feb 21 13:06:03 2018 -0800
+++ b/tkpane/lib.py Wed Feb 21 20:14:46 2018 -0800
@@ -24,7 +24,7 @@
2424 for creation of other custom pane classes.
2525 """
2626
27-__version__ = "0.7.0"
27+__version__ = "0.8.0"
2828
2929
3030 try:
@@ -244,7 +244,9 @@
244244 self.user_validator = None
245245 self.user_label = ttk.Label(self, text='User name:', width=10, anchor=tk.E)
246246 self.user_var = tk.StringVar()
247- self.datakeylist = ["name", "password"]
247+ self.userkeyname = "name"
248+ self.passkeyname = "password"
249+ self.datakeylist = [self.userkeyname, self.passkeyname]
248250 self.datadict = {}
249251 self.previous_values = {}
250252 self.user_display = ttk.Entry(self, textvariable=self.user_var)
@@ -315,6 +317,24 @@
315317 # Custom methods.
316318 #...........................................................................
317319
320+ def set_keys(self, user_key_name, password_key_name):
321+ """Change the names of the data keys used for the entered data.
322+
323+ :param user_key_name: New name for the key for the user's name.
324+ :param password_key_name: New name for the key for the user's password.
325+
326+ This method allows the name of the data key to be customized to
327+ eliminate conflicts with other UserPane objects on the same UI.
328+ """
329+ if self.userkeyname in self.datadict:
330+ self.datadict[user_key_name] = self.datadict[self.userkeyname]
331+ del self.datadict[self.userkeyname]
332+ self.userkeyname = user_key_name
333+ if self.passkeyname in self.datadict:
334+ self.datadict[password_key_name] = self.datadict[self.passkeyname]
335+ self.passkeyname = password_key_name
336+ self.userkeylist = [user_key_name, password_key_name]
337+
318338 def set_user(self):
319339 # Open a dialog box to prompt for the user's name and password.
320340 dlg = self.GetUserDialog(self)
@@ -368,7 +388,9 @@
368388 self.user_var.trace("w", self.check_namechange)
369389 self.pw_var = tk.StringVar()
370390 self.pw_var.trace("w", self.check_pwchange)
371- self.datakeylist = ["name", "password"]
391+ self.userkeyname = "name"
392+ self.passkeyname = "password"
393+ self.datakeylist = [self.userkeyname, self.passkeyname]
372394 self.user_display = ttk.Entry(self, textvariable=self.user_var)
373395 self.pw_display = ttk.Entry(self, textvariable=self.pw_var, show="*")
374396 self.user_label.grid(row=0, column=0, padx=6, pady=3, sticky=tk.EW)
@@ -447,6 +469,24 @@
447469 # Custom methods.
448470 #...........................................................................
449471
472+ def set_keys(self, user_key_name, password_key_name):
473+ """Change the names of the data keys used for the entered data.
474+
475+ :param user_key_name: New name for the key for the user's name.
476+ :param password_key_name: New name for the key for the user's password.
477+
478+ This method allows the name of the data key to be customized to
479+ eliminate conflicts with other UserPasswordPane objects on the same UI.
480+ """
481+ if self.userkeyname in self.datadict:
482+ self.datadict[user_key_name] = self.datadict[self.userkeyname]
483+ del self.datadict[self.userkeyname]
484+ self.userkeyname = user_key_name
485+ if self.passkeyname in self.datadict:
486+ self.datadict[password_key_name] = self.datadict[self.passkeyname]
487+ self.passkeyname = password_key_name
488+ self.userkeylist = [user_key_name, password_key_name]
489+
450490 def check_namechange(self, *args):
451491 self.handle_change_validity(self.valid_data(None), self.user_display)
452492
@@ -482,12 +522,12 @@
482522 * focus
483523 * set_data
484524 """
485- datakey = u"output_dir"
486525
487526 def __init__(self, parent, optiondict=None):
488527 tkpane.TkPane.__init__(self, parent, "Output directory", frame_config_opts(), frame_grid_opts())
489528 # Customize attributes
490529 self.optiondict = {} if optiondict is None else optiondict
530+ self.datakey = "output_dir"
491531 self.datakeylist = [self.datakey]
492532 # Create, configure, and place widgets.
493533 self.dir_label = tk.Label(self, text='Output directory:', width=18, anchor=tk.E)
@@ -571,6 +611,20 @@
571611 # Custom methods.
572612 #...........................................................................
573613
614+ def set_key(self, key_name):
615+ """Change the name of the data key used for the entered data.
616+
617+ :param key_name: New name for the data key.
618+
619+ This method allows the name of the data key to be customized to
620+ eliminate conflicts with other OutputDirPane objects on the same UI.
621+ """
622+ if self.datakeyname in self.datadict:
623+ self.datadict[key_name] = self.datadict[self.datakeyname]
624+ del self.datadict[self.datakeyname]
625+ self.datakeyname = key_name
626+ self.datakeylist = [key_name]
627+
574628 def check_entrychange(self, *args):
575629 self.handle_change_validity(self.valid_data(None), self.dir_display)
576630
@@ -603,12 +657,11 @@
603657 * focus
604658 * set_data
605659 """
606- datakey = "output_filename"
607-
608660 def __init__(self, parent, optiondict=None):
609661 tkpane.TkPane.__init__(self, parent, "Output filename", frame_config_opts(), frame_grid_opts())
610662 # Customize attributes
611663 self.optiondict = {} if optiondict is None else optiondict
664+ self.datakey = "output_filename"
612665 self.datakeylist = [self.datakey]
613666 # Create, configure, and place widgets.
614667 self.dir_label = ttk.Label(self, text='Output file:', width=12, anchor=tk.E)
@@ -696,6 +749,20 @@
696749 # Custom methods.
697750 #...........................................................................
698751
752+ def set_key(self, key_name):
753+ """Change the name of the data key used for the entered data.
754+
755+ :param key_name: New name for the data key.
756+
757+ This method allows the name of the data key to be customized to
758+ eliminate conflicts with other OutputFilePane objects on the same UI.
759+ """
760+ if self.datakeyname in self.datadict:
761+ self.datadict[key_name] = self.datadict[self.datakeyname]
762+ del self.datadict[self.datakeyname]
763+ self.datakeyname = key_name
764+ self.datakeylist = [key_name]
765+
699766 def check_entrychange(self, *args):
700767 self.handle_change_validity(self.valid_data(None), self.file_display)
701768
@@ -730,12 +797,11 @@
730797 * set_data
731798 """
732799
733- datakey = "input_filename"
734-
735800 def __init__(self, parent, optiondict=None):
736801 tkpane.TkPane.__init__(self, parent, "Input filename", frame_config_opts(), frame_grid_opts())
737802 # Customize attributes
738803 self.optiondict = {} if optiondict is None else optiondict
804+ self.datakey = "input_filename"
739805 self.datakeylist = [self.datakey]
740806 # Create, configure, and place widgets.
741807 self.dir_label = ttk.Label(self, text='Input file:', width=12, anchor=tk.E)
@@ -820,6 +886,20 @@
820886 # Custom methods.
821887 #...........................................................................
822888
889+ def set_key(self, key_name):
890+ """Change the name of the data key used for the entered data.
891+
892+ :param key_name: New name for the data key.
893+
894+ This method allows the name of the data key to be customized to
895+ eliminate conflicts with other InputFilePane objects on the same UI.
896+ """
897+ if self.datakeyname in self.datadict:
898+ self.datadict[key_name] = self.datadict[self.datakeyname]
899+ del self.datadict[self.datakeyname]
900+ self.datakeyname = key_name
901+ self.datakeylist = [key_name]
902+
823903 def check_entrychange(self, *args):
824904 self.handle_change_validity(self.valid_data(None), self.file_display)
825905
@@ -1217,7 +1297,7 @@
12171297 :param column_headers: A list of the column names for the data table.
12181298 :param rowset: An iterable that yields lists of values to be used as rows for the data table.
12191299
1220- Data key managed by this pane:
1300+ Data key managed by this pane: "table_data".
12211301
12221302 * table_data: A dictionary of the selected data; keys are the table column names.
12231303
@@ -1330,6 +1410,20 @@
13301410 # Custom methods.
13311411 #...........................................................................
13321412
1413+ def set_key(self, key_name):
1414+ """Change the name of the data key used for the entered data.
1415+
1416+ :param key_name: New name for the data key.
1417+
1418+ This method allows the name of the data key to be customized to
1419+ eliminate conflicts with other TableSelectPane objects on the same UI.
1420+ """
1421+ if self.datakeyname in self.datadict:
1422+ self.datadict[key_name] = self.datadict[self.datakeyname]
1423+ del self.datadict[self.datakeyname]
1424+ self.datakeyname = key_name
1425+ self.datakeylist = [key_name]
1426+
13331427 def set_style(self, ttk_style):
13341428 self._setstyle([self.msg_label, self.tbl, self.ysb, self.xsb], ttk_style)
13351429
diff -r 06822cf5eee9 -r 35d6d2356679 tkpane/tkpane.py
--- a/tkpane/tkpane.py Wed Feb 21 13:06:03 2018 -0800
+++ b/tkpane/tkpane.py Wed Feb 21 20:14:46 2018 -0800
@@ -27,7 +27,7 @@
2727 that pass specific data to allow communication between panes, and callback methods
2828 for reporting status and progress."""
2929
30-__version__ = "0.13.0"
30+__version__ = "0.14.0"
3131
3232
3333 try:
@@ -700,7 +700,12 @@
700700 #-------------------------------------------------------------------------------
701701
702702 def enable_or_disable_all(panelist):
703- """Enable or disable all panes in the list, as required by their data status."""
703+ """Enable or disable all panes in the list, as required by their data status.
704+
705+ This function is intended primarily to be used after the UI has been built
706+ but before it has been activated, to ensure that all of the specified panes
707+ are initallly appropriately enabled or disabled.
708+ """
704709 for p in panelist:
705710 if p.can_enable():
706711 p.enable()
@@ -714,12 +719,13 @@
714719
715720
716721 def layout_panes(layout):
717- """Take a tklayout.AppLayout object and return an object with pane objects as attributes,
722+ """Take a tklayout.AppLayout object and return an object that has pane objects as attributes,
718723
719- If the tklayout package has been used to assemble panes into a UI, this function
720- will collect all of the pane names and corresponding pane objects out of the
721- layout object into a single new object. This may simplify access to the pane
722- objects for subsequent customization."""
724+ If the ``tklayout`` package has been used to assemble panes into a UI, this function
725+ will collect all of the pane names and corresponding pane objects from the
726+ layout object into a single new object. This can simplify access to the pane
727+ objects for subsequent customization.
728+ """
723729
724730 class LayoutPaneGroup(object):
725731 pass
@@ -745,6 +751,9 @@
745751 :param tk_parent: The Tkinter widget (e.g., a frame) that will be the parent widget for the entire UI.
746752 :param ui_root_element: The name of the layout element (in 'layout_spec') that is the container for all other layout elements.
747753 :param build_specs: A dictionary of layout element names and functions to populate those elements with panes (as is needed by tklayout.build_elements).
754+
755+ This is a convenience function that integrates operations of the ``tklayout``
756+ and ``tkpane`` packages to minimize application code.
748757 """
749758 layout_spec.create_layout(tk_parent, ui_root_element)
750759 layout_spec.build_elements(build_specs)
Show on old repository browser