Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tkinter right to left menu

Tags:

python

tkinter

I am writing a GUI program using python with tkinter. I want to put menu items from right to left. is it possible? I tried grid, but I get Error 'it's a top-level window'.

import tkinter as tk
from tkinter import ttk
from tkinter import Menu
from tkinter import LEFT, RIGHT
from tkinter import W
menuBar = Menu(win)
win.config(menu=menuBar)
fileMenu = Menu(menuBar, tearoff=0).grid(sticky=W)
menuBar.add_cascade(label="File", menu=fileMenu)
fileMenu.add_command(label="New")
like image 347
keramat Avatar asked Dec 05 '22 13:12

keramat


2 Answers

There is not a built in way to do this but you can try to work around it with event bindings.

My below example will use a few bindings to try and manage the location of a menu.

One thing we will need is a Toplevel() window to house the menu.

Next we need to get rid of its buttons (-, []and X). This can be done with overidedirect(True).

Now that we cannot manually move the Toplevel() window we need to bind the <Configure> event to a function that will position the top level on the right most side of our main window.

Here is the binding:

win.bind("<Configure>", lambda x: win.after(0, move_menu(x)))

Here is the function:

def move_menu(event):
    x = (win.winfo_width() - menu_frame.winfo_width())
    z = (win.winfo_x(), win.winfo_y())
    xx = menu_frame.winfo_width()
    menu_frame.geometry('%dx%d+%d+%d' % ((xx), 0, (z[0]+x+8), (z[1]+30)))

Next we will need to force the menu or rather the Toplevel window to stay on top of the main window. This can be done with menu_frame.attributes('-topmost', True). However we encounter an issue when you click outside of the man window and that is the toplevel menu window stays on top of all programs outside of your tkinter app.

In order to manage this behavior we need another 2 bindings. One for event '<Enter>' and one for event '<Leave>'. This will allow us to toggle the overrideredirect() method when the mouse Enters and leaves the root window.

Here are the bindings:

win.bind("<Enter>", lambda x: win.after(0, manage_top_attr(x, True)))
win.bind("<Leave>", lambda x: win.after(0, manage_top_attr(x, False)))

Here is the function:

def manage_top_attr(event, tf):
    menu_frame.attributes('-topmost', tf)

With all that added to the program we can have a menu that sits on the right of the screen.

Code example:

import tkinter as tk

win = tk.Tk()
win.minsize(200, 200)
win.geometry("250x200")
menu_frame = tk.Toplevel(win)
menu_frame.overrideredirect(True)
menu_frame.attributes('-topmost', True)
tk.Label(win, text="").grid(row=0, column=0)

main_window_frame = tk.Frame(win)
main_window_frame.grid(row=1, column=0, sticky="nsew")

def manage_top_attr(event, tf):
    menu_frame.attributes('-topmost', tf)

def move_menu(event):
    print (event)
    x = (win.winfo_width() - menu_frame.winfo_width())
    z = (win.winfo_x(), win.winfo_y())
    xx = menu_frame.winfo_width()
    menu_frame.geometry('%dx%d+%d+%d' % ((xx), 0, (z[0]+x+8), (z[1]+30)))

win.bind("<Configure>", lambda x: win.after(0, move_menu(x)))
win.bind("<Enter>", lambda x: win.after(0, manage_top_attr(x, True)))
win.bind("<Leave>", lambda x: win.after(0, manage_top_attr(x, False)))

tk.Label(main_window_frame, text="Main window").grid(row=0, column=0)

menuBar = tk.Menu(menu_frame)
menu_frame.config(menu=menuBar)
fileMenu = tk.Menu(menuBar, tearoff=0)
menuBar.add_cascade(label="File", menu=fileMenu)
fileMenu.add_command(label="New")
menuBar.add_cascade(label="Edit", menu=fileMenu)
menuBar.add_cascade(label="Options", menu=fileMenu)
menuBar.add_cascade(label="Help", menu=fileMenu)

win.mainloop()

Results:

enter image description here

After you resize the window:

enter image description here

Now it doesn't behave perfectly and could probably use some work but its a start.

like image 56
Mike - SMT Avatar answered Jan 02 '23 14:01

Mike - SMT


No, you cannot create items on a menu from right to left.

like image 36
Bryan Oakley Avatar answered Jan 02 '23 13:01

Bryan Oakley