Multiple menus using Tkinter - python

I would like to create two different menus using Tkinter, one of them is already done
And now I'm trying to create a pop-up menu that opens when I right-click.
Basically, my program is a table tree view with some .txt files, and I want when right-click on either of them to be able to open it in notepad++
This is how I created the first menu:
table_tree = ttk.Treeview(window)
table_tree.grid(column = 0, row = 0, sticky="ns")
# Create menu bar
menubar = Menu(window)
window.config(menu=menubar)
file_menu = Menu(
menubar,
tearoff=0
)
#Then added items...Open/Exit
Then this is how I tried to create the second menu:
def my_popup(e):
right_menu.tk_popup(e.x_window, e.y_window)
#create right click menu
right_menu = Menu(window, tearoff = False)
right_menu.add_command(label = "Open in Notepad", command = open_in_notepad)
window.bind("<Button-3>", my_popup)
open_in_notepad is a function that is getting the path of the file and opens it in notepad.
I even get an error when I right click anywhere: AttributeError: 'Event' object has no attribute 'x_window'. So what I'm trying to do is definitely wrong but I couldn't find a solution until now..

Related

Only opening a Window only when it already is not open in Tkinter

I created a button in tkinter with its command being to create anew window. But I don't want it to create a new window every time I click the create a new window button. I want to tell the program to open the new window only if it is not already open. If somewhere in the background the window is already open and the user presses the create a new window button I want it to move that window on the first layer of the user's screen (bringing it upfront from all the other open windows).
Here is my code --
def main():
main_bg = "Gray"
main_fg = "White"
import tkinter as tk
employees = []
window = tk.Tk()
window.configure(bg=main_bg)
window.title("Business app")
window.geometry("1100x650")
def open_new_window():
random_window = tk.Toplevel(window)
random_window.configure(bg=main_bg)
random_window.geometry("600x600")
random_button = tk.Button(window, text="Do Something", font="Times 32", bg=main_bg, fg=main_fg, command=open_new_window)
random_button.pack()
window.mainloop()
if __name__ == "__main__":
main()
I have searched websites like Geeksforgeeks and this website but I could not find the solution I was looking for. Please help.
NOTE -- PLEASE DO NOT CLOSE THIS QUESTION AND POINT ME TOWARDS ANOTHER FORUM BECAUSE I HAVE CHECKED OTHERS IN THIS WEBSITE AS I MENTIONED ABOVE
Added grab_set() will prevent open new window again.
def open_new_window():
random_window = tk.Toplevel(window)
#random_window.configure(bg=main_bg)
random_window.geometry("600x600")
random_window.grab_set()
Result:
When you click Do Something will prevent open new window. Unless close the topelevel window and then open new window again
You can save a reference to the widget, and then check the reference to see if it's set. If it is set, you can then call winfo_exists to check whether the reference points to an existing window.
random_window = None
...
def open_new_window():
global random_window
if random_window and random_window.winfo_exists():
# the window exists, so do nothing
return
random_window = tk.Toplevel(window)
random_window.configure(bg=main_bg)
random_window.geometry("600x600")

Generating a menu for a tkinter window doesn’t work using a function but works just fine if the steps are executed on a python console

I’m trying to generate a set of menus for a program from a dictionary using a more complex version of the function build_menu below. The function detects what it is supposed to do correctly (detects the structure of submenus and menu entries as desired) but it fails to add them to the window.
Things I have tried:
running the code step by step in a python console - works as intended
storing the menu objects in a global list so they don’t go out of scope in case they get garbage collected - didn’t work
What am I missing?
import tkinter as tk
def not_implemented():
pass
def build_menu(structure_dict, menu):
for entry in structure_dict:
if isinstance(structure_dict[entry], dict):
submenu = tk.Menu(menu, tearoff=False)
build_menu(structure_dict[entry], submenu)
menu.add_cascade(label=entry, menu=submenu)
if callable(structure_dict[entry]):
menu.add_command(label=entry, command=structure_dict[entry])
# format:
# "":{} -> menu or submenu
# "":function -> menu entry
menu_structure = {
"Help": {
"Manual...": not_implemented,
"About...": not_implemented,
}
}
main_window = tk.Tk()
menubar = tk.Menu(main_window)
menubar = build_menu(menu_structure, menubar)
main_window.config(menu=menubar)
main_window.mainloop()
Turns out I am an idiot.
I accidentally assigned build_menu to the variable holding the menu bar.
Correct code near the end is this:
menubar = tk.Menu(main_window)
build_menu(menu_structure, menubar)
main_window.config(menu=menubar)
main_window.mainloop()

How to know current cursor location out of multiple Entry widgets in tkinter

'I am writing a GUI application in tkinter, I have multiple entry widgets, and I am trying to assign a menu with copy and paste option, I am having trouble with paste function. To paste the text from clipboard I need to know the current cursor location based on which entry widget the cursor is, and I am not able to get the current cursor location.'
import tkinter as tk
def do_popup(event):
right_click_menu.tk_popup(event.x_root, event.y_root)
def copy_clipboard():
global selected
root.clipboard_clear()
if path_for_result.select_present():
selected = selected_text.selection_get()
root.clipboard_append(selected)
elif user_defined_loadcases.select_present():
selected = selected_text.selection_get()
root.clipboard_append(selected)
def paste_clipboard():
global selected
if root.clipboard_get():
path_for_result.insert(tk.INSERT,root.clipboard_get())
user_defined_loadcases.insert(tk.INSERT,root.clipboard_get())
right_click_menu = tk.Menu(frame, tearoff =0)
right_click_menu.add_command(label ="Cut")
right_click_menu.add_command(label ="Copy",command = copy_clipboard)
right_click_menu.add_command(label ="Paste",command = paste_clipboard)
path_for_result.bind("<Button-3>", do_popup)
user_defined_loadcases.bind("<Button-3>", do_popup)

Adding a function directly to "menuBar" buttons without creating a sub-menu or dropdown

I want to make menu in Python PyQt5 with a function directly linked to it and not with a the sub-menu or dropdown it creates. Here is a snippet from my code:
def create_menu(self):
self.menu = self.menuBar()
self.this = self.menu.addMenu('This')
self.that = self.menu.addMenu('That')
self.menu.show()
self.this.addAction("I want to make it without this", self.there)

Is it possible take user text input in a Tkinter dropdown menu? If so, how?

This is what I have tried:
win = Tk()
menubar = Menu(win)
dropDown = Menu(menubar)
dropDown.add_command(label = "Do something", command = ...)
entry = Entry()
dropDown.add(entry)
menubar.add_cascade(label = "Drop Down", menu = dropDown)
win.config(menu = menubar)
win.update()
I have looked through the docs and it seems like there is no way to do it with a single line like dropDown.add_entry(...), but I thought there might be a workaround like using the one of the geometry manager to place the entry in the menu somehow.
I am using Python 3.6 (but I'm not tagging it because I'll get a thousand mods from the Python tag who have no interest in answering my question voting to close for no reason)
No, there is no way using the standard menus to have a menu that accepts user input. This is simply not how menus are designed to work.
If you need the user to type in a string, you need to use a dialog.
Here is a simple program where you can click a menu button to prompt the user for input. Then do something with that input. In this case print to console.
We need to write a function that makes use of askstring() from simpledialog that you can import from Tkinter. Then take the results of that string the user types and do something with it.
import tkinter as tk
from tkinter import simpledialog
win = tk.Tk()
win.geometry("100x50")
def take_user_input_for_something():
user_input = simpledialog.askstring("Pop up for user input!", "What do you want to ask the user to input here?")
if user_input != "":
print(user_input)
menubar = tk.Menu(win)
dropDown = tk.Menu(menubar, tearoff = 0)
dropDown.add_command(label = "Do something", command = take_user_input_for_something)
# this entry field is not really needed her.
# however I noticed you did not define this widget correctly
# so I put this in to give you an example.
my_entry = tk.Entry(win)
my_entry.pack()
menubar.add_cascade(label = "Drop Down", menu = dropDown)
win.config(menu = menubar)
win.mainloop()

Categories

Resources