easy-menus 1.3.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2026 John Bolkcom
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,291 @@
1
+ Metadata-Version: 2.4
2
+ Name: easy-menus
3
+ Version: 1.3.6
4
+ Summary: Wrapper classes for easy implementation of Tkinter menus.
5
+ Author-email: John Bolkcom <johnbolk6502@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/johnbolk/easy-menus.git
8
+ Keywords: Tkinter,Menus,macOS
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Intended Audience :: Developers
12
+ Requires-Python: >=3.7
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: pillow>=9.5.0
16
+ Dynamic: license-file
17
+
18
+ **Wrapper classes for easy implementation of Tkinter menus.**
19
+
20
+ This package was created to simplify the process of implementing menus in Tkinter windows. This was accomplished by defining functional "building block" classes which can be assembled together to create the user interface. Each of these classes provides the methods and properties needed to accomplish the assembly task. The design goal was to make this process as easy and intuitive as possible.
21
+
22
+ As a quick example, the following script will construct a Tkinter window and display a top menu bar that contains a single menu entry labeled **File**. This entry is a drop-down menu, and it has a selection item labeled **Exit**. Clicking on this item will call the **on_exit( )** event handler, which closes the window and exits the program.
23
+
24
+ ```
25
+ from tkinter import Tk
26
+ from menus import MainMenu
27
+
28
+ root = Tk()
29
+
30
+ def on_exit():
31
+ root.destroy()
32
+
33
+ # Create and Populate the Top Menu Bar
34
+ menu_bar = MainMenu(root)
35
+ file_menu = menu_bar.add_menu('File')
36
+ file_menu.add_item('Exit', on_exit)
37
+
38
+ root.mainloop()
39
+ ```
40
+
41
+ <div class="page"/>
42
+
43
+ ## Overview
44
+
45
+ This package provides the following class definitions **:**
46
+
47
+ * **MainMenu -** A class that displays a menu bar across the top of a window.
48
+ * **Menu -** A class used to represent a selection menu.
49
+ * **MenuItem -** A class used to represent a selection item in a Menu.
50
+ * **EntryType -** An enumerated dataclass of the available MenuItem entry types.
51
+ * **ConfigInfo -** A dataclass that provides MenuItem configuration information.
52
+ * **MenuButton -** A class used to represent a drop-down selection menu button.
53
+ * **ContextMenu -** A class used to represent a pop-up context menu.
54
+
55
+ The **MainMenu, Menu,** and **MenuItem** classes are the three "building blocks" used to construct the user interface for applications.
56
+
57
+ Consider the previous section's example script with the following changes **:**
58
+ 1) The import statement now includes the **Menu,** and the **MenuItem** classes.
59
+ 2) The **File** menu is first created and then added to the top menu bar.
60
+ 3) The **Exit** selection item is first created and then added to the **File** menu.
61
+
62
+ ```
63
+ from tkinter import Tk
64
+ from menus import MainMenu, Menu, MenuItem
65
+
66
+ root = Tk()
67
+
68
+ def on_exit():
69
+ root.destroy()
70
+
71
+ # Create and Populate the Top Menu Bar
72
+ menu_bar = MainMenu(root)
73
+ file_menu = Menu('File')
74
+ menu_bar.add(file_menu)
75
+ exit_item = MenuItem('Exit', on_exit)
76
+ file_menu.add(exit_item)
77
+
78
+ root.mainloop()
79
+ ```
80
+
81
+ Both scripts are functionally equivalent, but the second version shows the individual classes being created and then assembled to construct the user interface. The reader can refer to [**The Zen of Python**](https://peps.python.org/pep-0020/) to decide if either one of these two scripts is the more Pythonic than the other.
82
+
83
+ <div class="page"/>
84
+
85
+ Referring back to the original example script, consider these two changes to the **Exit** selection item **:**
86
+ 1) The **Exit** selection item's label string has been changed to **'E&xit'**
87
+ 2) The **Exit** selection item's **shortcut** property has been assigned a key character value of **'w'**
88
+
89
+ ```
90
+ from tkinter import Tk
91
+ from menus import MainMenu
92
+
93
+ root = Tk()
94
+
95
+ def on_exit():
96
+ root.destroy()
97
+
98
+ # Create and Populate the Top Menu Bar
99
+ menu_bar = MainMenu(root)
100
+ file_menu = menu_bar.add_menu('File')
101
+ file_menu.add_item('E&xit', on_exit).shortcut = 'w'
102
+
103
+ root.mainloop()
104
+ ```
105
+
106
+ The Windows and Linux platforms support the **Alt+Key** technique for navigating the top menu bar and its entries. The active key value for each entry appears as an underlined character in that entry's label. By default, the first character in the entry's label is the active key value. In this example, the top menu bar displays a **<u>F</u>ile** label. When the **&** symbol appears in the label string, the next character in the label will be designated as the active key value for that entry. The **&** symbol is not part of the displayed label. In this example, the **'E&xit'** string denotes that the **x** character is the active key value for this entry, and the label is displayed as **E<u>x</u>it** on the screen.
107
+
108
+ The **shortcut** property allows a selection item to have a **Control+Key ( Command+key )** keyboard shortcut assigned to it. This is consistent with commonly used keyboard shortcuts such as the **Ctrl+C ( <font size="2">&#x2318;</font>C )** shortcut for a **Copy,** or the **Ctrl+V ( <font size="2">&#x2318;</font>V )** shortcut for a **Paste.** In this example, assigning the **'w'** character to the **shortcut** property creates a keyboard shortcut of **Ctrl+W ( <font size="2">&#x2318;</font>W )** for the **Exit** selection item. The shortcut's name is displayed next to the label on the screen. The **MenuItem** class also has a **set_custom_shortcut( )** method which can be used to assign other kinds of keyboard shortcuts, such as using a Function Key as a shortcut. The reader should refer to the Tkinter documentation for information on keyboard events.
109
+
110
+ The reader may wonder why the **'q'** character wasn't chosen for the **Exit** shortcut. The **Ctrl+Q** shortcut is commonly used to exit a program, and it certainly can be used on either a Windows or a Linux platform. However, the **<font size="2">&#x2318;</font>Q** shortcut is reserved for the system-level **Quit** command on macOS platforms. For the **<font size="2">&#x2318;</font>Q** shortcut to actually call the **on_exit( )** event handler, the macOS user must override the system by adding the following statement **:**
111
+
112
+ ```
113
+ root.createcommand('tk::mac::Quit', on_exit)
114
+ ```
115
+
116
+ <div class="page"/>
117
+
118
+ A menu entry can also display an icon image. Assuming there is an **image_folder** that contains an icon image file named **exit.png**, an icon image can be added to the **Exit** selection item by making the following changes to the previous example **:**
119
+ 1) Import the PhotoImage class from tkinter
120
+ 2) Create an **exit_icon** PhotoImage from the **image_folder/exit.png** image file
121
+ 3) Add the **exit_icon** PhotoImage to the **Exit** selection item's argument list
122
+
123
+ ```
124
+ from tkinter import Tk, PhotoImage
125
+ from menus import MainMenu
126
+
127
+ root = Tk()
128
+
129
+ def on_exit():
130
+ root.destroy()
131
+
132
+ # Create and Populate the Top Menu Bar
133
+ menu_bar = MainMenu(root)
134
+ file_menu = menu_bar.add_menu('File')
135
+
136
+ exit_icon = PhotoImage(file='image_folder/exit.png')
137
+ file_menu.add_item('E&xit', on_exit, exit_icon).shortcut = 'w'
138
+
139
+ root.mainloop()
140
+ ```
141
+
142
+ An application's top menu bar typically contains several drop-down menu entries. In this next example, four entries **( File, Edit, View,** and **Help )** are added to the top menu bar. The **begin_update( )** method should be called prior to adding multiple entries to the **MainMenu** class. Calling this method causes all the added entries to be placed into a queue, and it prevents multiple screen updates from occurring during this process. When all the entries have been added, the **end_update( )** method is called to process all the queued entries and to allow those entries to be displayed on the screen. Use of the **begin_update( ) ... end_update( )** pair is recommended on all platforms, and it is required on the macOS platform to ensure the correct behavior of the top menu bar.
143
+
144
+ ```
145
+ # Create and Populate the Top Menu Bar
146
+ menu_bar = MainMenu(root)
147
+ menu_bar.begin_update()
148
+ file_menu = menu_bar.add_menu('File')
149
+ edit_menu = menu_bar.add_menu('Edit')
150
+ view_menu = menu_bar.add_menu('View')
151
+ help_menu = menu_bar.add_menu('Help')
152
+ menu_bar.end_update()
153
+
154
+ ...
155
+ ```
156
+
157
+ <div class="page"/>
158
+
159
+ Continuing this theme, a typical **File** drop-down menu will also have several selection items, such as **Open**, **Save**, and **Exit**. The **add_separator( )** method displays a horizontal line between the **Save** and **Exit** selection items. Once again, the **begin_update( ) ... end_update( )** pair should be used when adding multiple entries to an instance of the **Menu** class.
160
+
161
+ ```
162
+ def on_open():
163
+ print('File_Menu - Open')
164
+
165
+ def on_save():
166
+ print('File_Menu - Save')
167
+
168
+ open_icon = PhotoImage(file='image_folder/open.png')
169
+ save_icon = PhotoImage(file='image_folder/save.png')
170
+ exit_icon = PhotoImage(file='image_folder/exit.png')
171
+
172
+ file_menu.begin_update()
173
+ file_menu.add_item('Open', on_open, open_icon).shortcut = 'o'
174
+ file_menu.add_item('Save', on_save, save_icon).shortcut = 's'
175
+ file_menu.add_separator()
176
+ file_menu.add_item('E&xit', on_exit, exit_icon).shortcut = 'w'
177
+ file_menu.end_update()
178
+
179
+ ...
180
+ ```
181
+
182
+ In this next code snippet, the **Edit** drop-down menu has the **Cut, Copy,** and **Paste** selection items. Here the **&** symbol appears in the **Cu&t** label string, and it is used to make that entry's active key value = **'t'**.
183
+
184
+ ```
185
+ def on_cut():
186
+ print('Edit_Menu - Cut')
187
+
188
+ def on_copy():
189
+ print('Edit_Menu - Copy')
190
+
191
+ def on_paste():
192
+ print('Edit_Menu - Paste')
193
+
194
+ edit_menu.begin_update()
195
+ edit_menu.add_item('Cu&t', on_cut).shortcut = 'x'
196
+ edit_menu.add_item('Copy', on_copy).shortcut = 'c'
197
+ edit_menu.add_item('Paste', on_paste).shortcut = 'v'
198
+ edit_menu.end_update()
199
+
200
+ ...
201
+ ```
202
+
203
+ <div class="page"/>
204
+
205
+ The **View** drop-down menu has a **Zoom** menu entry, which in turn, has have three different zoom options. These three selection items are configured to behave like Tkinter Radiobutton widgets. First, the import statements from the previous example need to be updated to the following **:**
206
+
207
+ ```
208
+ from tkinter import Tk, PhotoImage, IntVar
209
+ from menus import MainMenu, EntryType, ConfigInfo
210
+ ```
211
+
212
+ Next, each selection item in the **Zoom** menu must be configured as a 'Radiobutton' entry. The **EntryType** and the **ConfigInfo** dataclasses are used to perform that task. The **EntryType** defines the behavior of the entry, and it can be one of three options **: STANDARD**( default )**, CHECKBUTTON,** or **RADIOBUTTON**. Just like Radiobuttons, the Tkinter **IntVar** class is used to provide communication between the entries, and each entry must have a unique id value. The **ConfigInfo** dataclass is used to provide the configuration information when creating each of the three selection items. In this next code section, the three different zoom options are created and added to the **Zoom** menu entry in the **View** drop-down menu **:**
213
+
214
+ ```
215
+ zoom_variable = IntVar(value=100)
216
+
217
+ def on_zoom():
218
+ print(f'View_Menu - Zoom {zoom_variable.get()}%')
219
+
220
+ zoom_menu = view_menu.add_menu('Zoom')
221
+ zoom_menu.begin_update()
222
+ for value in (100, 200, 400):
223
+ label = f'&{value}%'
224
+ config = ConfigInfo(EntryType.RADIOBUTTON, zoom_variable, value)
225
+ zoom_menu.add_item(label, on_zoom, config=config)
226
+ zoom_menu.end_update()
227
+
228
+ ...
229
+ ```
230
+
231
+ Finally, the **Help** drop-down menu has a single selection item labeled **About**, which has been assigned **'Ctrl+Shift+A'** as its custom keyboard shortcut.
232
+ ```
233
+ def on_about():
234
+ print('Help_Menu - About')
235
+
236
+ about = help_menu.add_item('About', on_about)
237
+ about.set_custom_shortcut('<Control-Shift-A>', 'Ctrl+Shift+A')
238
+
239
+ root.mainloop()
240
+ ```
241
+
242
+ <div class="page"/>
243
+
244
+ The **MenuButton** is essentially a single entry menu bar that can be positioned anywhere in the application window. The **MenuButton**'s text and optional image are always visible on the screen. Its drop-down menu, the **menu** property, is displayed when the **MenuButton** is clicked. This is an example using the **MenuButton :**
245
+
246
+ ```
247
+ from tkinter import Tk
248
+ from menus import MenuButton
249
+
250
+ root = Tk()
251
+ selections = MenuButton(root, 'Selections', 20)
252
+ selections.grid(padx=40, pady=40)
253
+ selections.menu.begin_update()
254
+ for i in range(1, 5):
255
+ def on_select(index=i):
256
+ print(f'Selection Number {index}')
257
+ selections.menu.add_item(f'Selection #{i}', on_select)
258
+ selections.menu.end_update()
259
+ root.mainloop()
260
+ ```
261
+
262
+ The **ContextMenu** is a pop-up menu that can be displayed at a specified screen location. A **ContextMenu** is not visible until it is invoked by some action, usually a right-button mouse click. In this next example, a **ContextMenu** is created and then associated with a **Label** widget **:**
263
+
264
+ ```
265
+ from tkinter import Tk, Label
266
+ from menus import ContextMenu
267
+
268
+ root = Tk()
269
+
270
+ def on_context_event():
271
+ print('Context Menu Event')
272
+
273
+ context_menu = ContextMenu()
274
+ context_menu.add_item('Copy', on_context_event)
275
+ context_menu.add_item('Save As ...', on_context_event)
276
+ context_menu.add_item('Delete Text', on_context_event)
277
+
278
+ label = Label(root, text=' ContextMenu Example ', relief='groove')
279
+ label.grid(padx=40, pady=40)
280
+
281
+ def on_right_button(e): # Display the ContextMenu at the mouse position
282
+ position = (label.winfo_rootx() + e.x, label.winfo_rooty() + e.y)
283
+ context_menu.display(position)
284
+
285
+ label.bind('<Button-3>', on_right_button) # use '<Button-2>' on macOS
286
+ root.mainloop()
287
+ ```
288
+
289
+ ## Documentation
290
+
291
+ Full documentation for all the classes contained in this package, as well as usage examples, are available at the package's GitHub repository: https://github.com/johnbolk/easy-menus
@@ -0,0 +1,274 @@
1
+ **Wrapper classes for easy implementation of Tkinter menus.**
2
+
3
+ This package was created to simplify the process of implementing menus in Tkinter windows. This was accomplished by defining functional "building block" classes which can be assembled together to create the user interface. Each of these classes provides the methods and properties needed to accomplish the assembly task. The design goal was to make this process as easy and intuitive as possible.
4
+
5
+ As a quick example, the following script will construct a Tkinter window and display a top menu bar that contains a single menu entry labeled **File**. This entry is a drop-down menu, and it has a selection item labeled **Exit**. Clicking on this item will call the **on_exit( )** event handler, which closes the window and exits the program.
6
+
7
+ ```
8
+ from tkinter import Tk
9
+ from menus import MainMenu
10
+
11
+ root = Tk()
12
+
13
+ def on_exit():
14
+ root.destroy()
15
+
16
+ # Create and Populate the Top Menu Bar
17
+ menu_bar = MainMenu(root)
18
+ file_menu = menu_bar.add_menu('File')
19
+ file_menu.add_item('Exit', on_exit)
20
+
21
+ root.mainloop()
22
+ ```
23
+
24
+ <div class="page"/>
25
+
26
+ ## Overview
27
+
28
+ This package provides the following class definitions **:**
29
+
30
+ * **MainMenu -** A class that displays a menu bar across the top of a window.
31
+ * **Menu -** A class used to represent a selection menu.
32
+ * **MenuItem -** A class used to represent a selection item in a Menu.
33
+ * **EntryType -** An enumerated dataclass of the available MenuItem entry types.
34
+ * **ConfigInfo -** A dataclass that provides MenuItem configuration information.
35
+ * **MenuButton -** A class used to represent a drop-down selection menu button.
36
+ * **ContextMenu -** A class used to represent a pop-up context menu.
37
+
38
+ The **MainMenu, Menu,** and **MenuItem** classes are the three "building blocks" used to construct the user interface for applications.
39
+
40
+ Consider the previous section's example script with the following changes **:**
41
+ 1) The import statement now includes the **Menu,** and the **MenuItem** classes.
42
+ 2) The **File** menu is first created and then added to the top menu bar.
43
+ 3) The **Exit** selection item is first created and then added to the **File** menu.
44
+
45
+ ```
46
+ from tkinter import Tk
47
+ from menus import MainMenu, Menu, MenuItem
48
+
49
+ root = Tk()
50
+
51
+ def on_exit():
52
+ root.destroy()
53
+
54
+ # Create and Populate the Top Menu Bar
55
+ menu_bar = MainMenu(root)
56
+ file_menu = Menu('File')
57
+ menu_bar.add(file_menu)
58
+ exit_item = MenuItem('Exit', on_exit)
59
+ file_menu.add(exit_item)
60
+
61
+ root.mainloop()
62
+ ```
63
+
64
+ Both scripts are functionally equivalent, but the second version shows the individual classes being created and then assembled to construct the user interface. The reader can refer to [**The Zen of Python**](https://peps.python.org/pep-0020/) to decide if either one of these two scripts is the more Pythonic than the other.
65
+
66
+ <div class="page"/>
67
+
68
+ Referring back to the original example script, consider these two changes to the **Exit** selection item **:**
69
+ 1) The **Exit** selection item's label string has been changed to **'E&xit'**
70
+ 2) The **Exit** selection item's **shortcut** property has been assigned a key character value of **'w'**
71
+
72
+ ```
73
+ from tkinter import Tk
74
+ from menus import MainMenu
75
+
76
+ root = Tk()
77
+
78
+ def on_exit():
79
+ root.destroy()
80
+
81
+ # Create and Populate the Top Menu Bar
82
+ menu_bar = MainMenu(root)
83
+ file_menu = menu_bar.add_menu('File')
84
+ file_menu.add_item('E&xit', on_exit).shortcut = 'w'
85
+
86
+ root.mainloop()
87
+ ```
88
+
89
+ The Windows and Linux platforms support the **Alt+Key** technique for navigating the top menu bar and its entries. The active key value for each entry appears as an underlined character in that entry's label. By default, the first character in the entry's label is the active key value. In this example, the top menu bar displays a **<u>F</u>ile** label. When the **&** symbol appears in the label string, the next character in the label will be designated as the active key value for that entry. The **&** symbol is not part of the displayed label. In this example, the **'E&xit'** string denotes that the **x** character is the active key value for this entry, and the label is displayed as **E<u>x</u>it** on the screen.
90
+
91
+ The **shortcut** property allows a selection item to have a **Control+Key ( Command+key )** keyboard shortcut assigned to it. This is consistent with commonly used keyboard shortcuts such as the **Ctrl+C ( <font size="2">&#x2318;</font>C )** shortcut for a **Copy,** or the **Ctrl+V ( <font size="2">&#x2318;</font>V )** shortcut for a **Paste.** In this example, assigning the **'w'** character to the **shortcut** property creates a keyboard shortcut of **Ctrl+W ( <font size="2">&#x2318;</font>W )** for the **Exit** selection item. The shortcut's name is displayed next to the label on the screen. The **MenuItem** class also has a **set_custom_shortcut( )** method which can be used to assign other kinds of keyboard shortcuts, such as using a Function Key as a shortcut. The reader should refer to the Tkinter documentation for information on keyboard events.
92
+
93
+ The reader may wonder why the **'q'** character wasn't chosen for the **Exit** shortcut. The **Ctrl+Q** shortcut is commonly used to exit a program, and it certainly can be used on either a Windows or a Linux platform. However, the **<font size="2">&#x2318;</font>Q** shortcut is reserved for the system-level **Quit** command on macOS platforms. For the **<font size="2">&#x2318;</font>Q** shortcut to actually call the **on_exit( )** event handler, the macOS user must override the system by adding the following statement **:**
94
+
95
+ ```
96
+ root.createcommand('tk::mac::Quit', on_exit)
97
+ ```
98
+
99
+ <div class="page"/>
100
+
101
+ A menu entry can also display an icon image. Assuming there is an **image_folder** that contains an icon image file named **exit.png**, an icon image can be added to the **Exit** selection item by making the following changes to the previous example **:**
102
+ 1) Import the PhotoImage class from tkinter
103
+ 2) Create an **exit_icon** PhotoImage from the **image_folder/exit.png** image file
104
+ 3) Add the **exit_icon** PhotoImage to the **Exit** selection item's argument list
105
+
106
+ ```
107
+ from tkinter import Tk, PhotoImage
108
+ from menus import MainMenu
109
+
110
+ root = Tk()
111
+
112
+ def on_exit():
113
+ root.destroy()
114
+
115
+ # Create and Populate the Top Menu Bar
116
+ menu_bar = MainMenu(root)
117
+ file_menu = menu_bar.add_menu('File')
118
+
119
+ exit_icon = PhotoImage(file='image_folder/exit.png')
120
+ file_menu.add_item('E&xit', on_exit, exit_icon).shortcut = 'w'
121
+
122
+ root.mainloop()
123
+ ```
124
+
125
+ An application's top menu bar typically contains several drop-down menu entries. In this next example, four entries **( File, Edit, View,** and **Help )** are added to the top menu bar. The **begin_update( )** method should be called prior to adding multiple entries to the **MainMenu** class. Calling this method causes all the added entries to be placed into a queue, and it prevents multiple screen updates from occurring during this process. When all the entries have been added, the **end_update( )** method is called to process all the queued entries and to allow those entries to be displayed on the screen. Use of the **begin_update( ) ... end_update( )** pair is recommended on all platforms, and it is required on the macOS platform to ensure the correct behavior of the top menu bar.
126
+
127
+ ```
128
+ # Create and Populate the Top Menu Bar
129
+ menu_bar = MainMenu(root)
130
+ menu_bar.begin_update()
131
+ file_menu = menu_bar.add_menu('File')
132
+ edit_menu = menu_bar.add_menu('Edit')
133
+ view_menu = menu_bar.add_menu('View')
134
+ help_menu = menu_bar.add_menu('Help')
135
+ menu_bar.end_update()
136
+
137
+ ...
138
+ ```
139
+
140
+ <div class="page"/>
141
+
142
+ Continuing this theme, a typical **File** drop-down menu will also have several selection items, such as **Open**, **Save**, and **Exit**. The **add_separator( )** method displays a horizontal line between the **Save** and **Exit** selection items. Once again, the **begin_update( ) ... end_update( )** pair should be used when adding multiple entries to an instance of the **Menu** class.
143
+
144
+ ```
145
+ def on_open():
146
+ print('File_Menu - Open')
147
+
148
+ def on_save():
149
+ print('File_Menu - Save')
150
+
151
+ open_icon = PhotoImage(file='image_folder/open.png')
152
+ save_icon = PhotoImage(file='image_folder/save.png')
153
+ exit_icon = PhotoImage(file='image_folder/exit.png')
154
+
155
+ file_menu.begin_update()
156
+ file_menu.add_item('Open', on_open, open_icon).shortcut = 'o'
157
+ file_menu.add_item('Save', on_save, save_icon).shortcut = 's'
158
+ file_menu.add_separator()
159
+ file_menu.add_item('E&xit', on_exit, exit_icon).shortcut = 'w'
160
+ file_menu.end_update()
161
+
162
+ ...
163
+ ```
164
+
165
+ In this next code snippet, the **Edit** drop-down menu has the **Cut, Copy,** and **Paste** selection items. Here the **&** symbol appears in the **Cu&t** label string, and it is used to make that entry's active key value = **'t'**.
166
+
167
+ ```
168
+ def on_cut():
169
+ print('Edit_Menu - Cut')
170
+
171
+ def on_copy():
172
+ print('Edit_Menu - Copy')
173
+
174
+ def on_paste():
175
+ print('Edit_Menu - Paste')
176
+
177
+ edit_menu.begin_update()
178
+ edit_menu.add_item('Cu&t', on_cut).shortcut = 'x'
179
+ edit_menu.add_item('Copy', on_copy).shortcut = 'c'
180
+ edit_menu.add_item('Paste', on_paste).shortcut = 'v'
181
+ edit_menu.end_update()
182
+
183
+ ...
184
+ ```
185
+
186
+ <div class="page"/>
187
+
188
+ The **View** drop-down menu has a **Zoom** menu entry, which in turn, has have three different zoom options. These three selection items are configured to behave like Tkinter Radiobutton widgets. First, the import statements from the previous example need to be updated to the following **:**
189
+
190
+ ```
191
+ from tkinter import Tk, PhotoImage, IntVar
192
+ from menus import MainMenu, EntryType, ConfigInfo
193
+ ```
194
+
195
+ Next, each selection item in the **Zoom** menu must be configured as a 'Radiobutton' entry. The **EntryType** and the **ConfigInfo** dataclasses are used to perform that task. The **EntryType** defines the behavior of the entry, and it can be one of three options **: STANDARD**( default )**, CHECKBUTTON,** or **RADIOBUTTON**. Just like Radiobuttons, the Tkinter **IntVar** class is used to provide communication between the entries, and each entry must have a unique id value. The **ConfigInfo** dataclass is used to provide the configuration information when creating each of the three selection items. In this next code section, the three different zoom options are created and added to the **Zoom** menu entry in the **View** drop-down menu **:**
196
+
197
+ ```
198
+ zoom_variable = IntVar(value=100)
199
+
200
+ def on_zoom():
201
+ print(f'View_Menu - Zoom {zoom_variable.get()}%')
202
+
203
+ zoom_menu = view_menu.add_menu('Zoom')
204
+ zoom_menu.begin_update()
205
+ for value in (100, 200, 400):
206
+ label = f'&{value}%'
207
+ config = ConfigInfo(EntryType.RADIOBUTTON, zoom_variable, value)
208
+ zoom_menu.add_item(label, on_zoom, config=config)
209
+ zoom_menu.end_update()
210
+
211
+ ...
212
+ ```
213
+
214
+ Finally, the **Help** drop-down menu has a single selection item labeled **About**, which has been assigned **'Ctrl+Shift+A'** as its custom keyboard shortcut.
215
+ ```
216
+ def on_about():
217
+ print('Help_Menu - About')
218
+
219
+ about = help_menu.add_item('About', on_about)
220
+ about.set_custom_shortcut('<Control-Shift-A>', 'Ctrl+Shift+A')
221
+
222
+ root.mainloop()
223
+ ```
224
+
225
+ <div class="page"/>
226
+
227
+ The **MenuButton** is essentially a single entry menu bar that can be positioned anywhere in the application window. The **MenuButton**'s text and optional image are always visible on the screen. Its drop-down menu, the **menu** property, is displayed when the **MenuButton** is clicked. This is an example using the **MenuButton :**
228
+
229
+ ```
230
+ from tkinter import Tk
231
+ from menus import MenuButton
232
+
233
+ root = Tk()
234
+ selections = MenuButton(root, 'Selections', 20)
235
+ selections.grid(padx=40, pady=40)
236
+ selections.menu.begin_update()
237
+ for i in range(1, 5):
238
+ def on_select(index=i):
239
+ print(f'Selection Number {index}')
240
+ selections.menu.add_item(f'Selection #{i}', on_select)
241
+ selections.menu.end_update()
242
+ root.mainloop()
243
+ ```
244
+
245
+ The **ContextMenu** is a pop-up menu that can be displayed at a specified screen location. A **ContextMenu** is not visible until it is invoked by some action, usually a right-button mouse click. In this next example, a **ContextMenu** is created and then associated with a **Label** widget **:**
246
+
247
+ ```
248
+ from tkinter import Tk, Label
249
+ from menus import ContextMenu
250
+
251
+ root = Tk()
252
+
253
+ def on_context_event():
254
+ print('Context Menu Event')
255
+
256
+ context_menu = ContextMenu()
257
+ context_menu.add_item('Copy', on_context_event)
258
+ context_menu.add_item('Save As ...', on_context_event)
259
+ context_menu.add_item('Delete Text', on_context_event)
260
+
261
+ label = Label(root, text=' ContextMenu Example ', relief='groove')
262
+ label.grid(padx=40, pady=40)
263
+
264
+ def on_right_button(e): # Display the ContextMenu at the mouse position
265
+ position = (label.winfo_rootx() + e.x, label.winfo_rooty() + e.y)
266
+ context_menu.display(position)
267
+
268
+ label.bind('<Button-3>', on_right_button) # use '<Button-2>' on macOS
269
+ root.mainloop()
270
+ ```
271
+
272
+ ## Documentation
273
+
274
+ Full documentation for all the classes contained in this package, as well as usage examples, are available at the package's GitHub repository: https://github.com/johnbolk/easy-menus
@@ -0,0 +1,25 @@
1
+ [build-system]
2
+ requires = ["setuptools>=40.8.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "easy-menus"
7
+ version = "1.3.6"
8
+ description = "Wrapper classes for easy implementation of Tkinter menus."
9
+ readme = "README.md"
10
+ authors = [
11
+ {name = "John Bolkcom", email = "johnbolk6502@gmail.com"}
12
+ ]
13
+ license = "MIT"
14
+ license-files = ["LICENSE"]
15
+ requires-python = ">=3.7"
16
+ dependencies = ["pillow>=9.5.0"]
17
+ keywords = ["Tkinter", "Menus", "macOS"]
18
+ classifiers = [
19
+ "Programming Language :: Python :: 3",
20
+ "Operating System :: OS Independent",
21
+ "Intended Audience :: Developers",
22
+ ]
23
+
24
+ [project.urls]
25
+ Homepage = "https://github.com/johnbolk/easy-menus.git"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+