Объект Меню (Menu) в GUI. Урок 10

Методическая разработка урока
Элективный курс: Модуль tkinter. Создание графического интерфейса пользователя с помощью языка программирования Python
Уровень: Программирование для начинающих

Что такое меню

Меню — это объект, который присутствует во многих пользовательских приложениях. Находится оно под строкой заголовка и представляет собой выпадающие списки под словами; каждый такой список может содержать другой вложенный в него список. Каждый пункт списка представляет собой команду, запускающую какое-либо действие или открывающую диалоговое окно.
Создание меню в Tkinter

from tkinter import *
root = Tk()
 
m = Menu(root) #создается объект Меню на главном окне
root.config(menu=m) #окно конфигурируется с указанием меню для него
 
fm = Menu(m) #создается пункт меню с размещением на основном меню (m)
m.add_cascade(label="File",menu=fm) #пункту располагается на основном меню (m)
fm.add_command(label="Open...") #формируется список команд пункта меню
fm.add_command(label="New")
fm.add_command(label="Save...")
fm.add_command(label="Exit")
 
hm = Menu(m) #второй пункт меню
m.add_cascade(label="Help",menu=hm)
hm.add_command(label="Help")
hm.add_command(label="About")
 
root.mainloop() 

Метод add_cascade добавляет новый пункт в меню, который указывается как значение опции menu.

Метод add_command добавляет новую команду в пункт меню. Одна из опций данного метода (в примере выше ее пока нет) — command – связывает данную команду с функцией- обработчиком.

Можно создать вложенное меню. Для этого создается еще одно меню и с помощью add_cascade привязать к родительскому пункту.

nfm = Menu(fm)
fm.add_cascade(label="Import",menu=nfm)
nfm.add_command(label="Image")
nfm.add_command(label="Text")

Привязка функций к меню

Каждая команда меню обычно должна быть связана со своей функцией, выполняющей те или иные действия (выражения). Связь происходит с помощью опции command метода add_command. Функция обработчик до этого должна быть определена.

Для примера выше далее приводятся исправленные строки добавления команд “About”, “New” и “Exit”, а также функции, вызываемые, когда пользователь щелкает левой кнопкой мыши по соответствующим пунктам подменю.

def new_win():
     win = Toplevel(root)
 
def close_win():
     root.destroy()
 
def about():
     win = Toplevel(root)
     lab = Label(win,text="Это просто программа-тест \n меню в Tkinter")
     lab.pack() 
 
….
fm.add_command(label="New",command=new_win)
….
fm.add_command(label="Exit",command=close_win)
 
….
hm.add_command(label="About",command=about) 

Практическая работа

Напишите приложение с меню, содержащим два пункта: Color и Size. Пункт Color должен содержать три команды (Red, Green и Blue), меняющие цвет рамки на главном окне. Пункт Size должен содержать две команды (500x500 и 700х400), изменяющие размер рамки.

Примерный ответ к практической работе

from tkinter import *
root = Tk()
 
def colorR():
     fra.config(bg="Red")
def colorG():
     fra.config(bg="Green")
def colorB():
     fra.config(bg="Blue")
 
def square():
     fra.config(width=500)
     fra.config(height=500)
def rectangle():
     fra.config(width=700)
     fra.config(height=400)
 
fra = Frame(root,width=300,height=100,bg="Black")
fra.pack()
 
m = Menu(root)
root.config(menu=m)
 
cm = Menu(m)
m.add_cascade(label="Color",menu=cm)
cm.add_command(label="Red",command=colorR)
cm.add_command(label="Green",command=colorG)
cm.add_command(label="Blue",command=colorB)
 
sm = Menu(m)
m.add_cascade(label="Size",menu=sm)
sm.add_command(label="500x500",command=square)
sm.add_command(label="700x400",command=rectangle)
 
root.mainloop()

Решение практической в

Решение практической в ООП-стиле:

from tkinter import *
 
class Menu_options:
    def __init__(self):
        menu_ini = Menu(root)
        root.config(menu=menu_ini)
        color_menu = Menu(menu_ini)
        menu_ini.add_cascade(label="Color", menu = color_menu)
        color_menu.add_command(label="Red", command=self.change_color_red)
        color_menu.add_command(label="Green", command=self.change_color_green)
        color_menu.add_command(label="Blue", command=self.change_color_blue)
        size_menu = Menu(menu_ini)
        menu_ini.add_cascade(label="Size", menu = size_menu)
        size_menu.add_command(label="500x500", command=self.change_size1)
        size_menu.add_command(label="700x400", command=self.change_size2)
        self.fra = Frame(root, height=50, width=50, bg="purple")
        self.fra.pack()
 
    def change_color_red(self):
        self.fra.configure(bg="red")
    def change_color_green(self):
        self.fra.configure(bg="green")
    def change_color_blue(self):
        self.fra.configure(bg="blue")
 
    def change_size1(self):
        self.fra.configure(height=500, width=500)
    def change_size2(self):
        self.fra.configure(height=400, width=700)
 
root = Tk()
 
obj_menu = Menu_options()
 
root.mainloop()

Во-первых: огромное спасибо

Во-первых: огромное спасибо за эти уроки.

Во-вторых: еще бы уроки по Django и Django-CMS ;-)
а то у Вас все друпал, да друпал. Не питонично :-)

Кстати, кроме Tk(и PyQt) есть консольная библиотека Urwid ( делает все то же самое, но в консоли, что весьма необычно)

Теперь к делу:

если мышкой сразу после запуска изменить размеры окна, например потянуть правый нижний угол - увеличить окно, то все - размеры не изменяются!!!

только если сделать режим 300x100 (и если в данный момент окно больше этого размера), то внутри появится цветной прямоугольник 300x100.

Как с этим бороться???

проще всего сделать окно не

проще всего сделать окно не изменяемым в размерах:
root.resizable(False,False)
где root - главное окно

GUI и XML

Kak соединить в XML в GUI, то есть у меня есть Гуи там кнопка, я хотела бы нажать на кнопку и чтобы увидеть мой документ.xml.спасибо!

Кривовато, но зато работает и

Кривовато, но зато работает и не очень много лишних функций :-)

import Tkinter
 
colors = ("black", "red", "green", "blue")
sizes = ("500x500", "700x400")
 
frame = None
 
def changeColor(color):
    if frame is not None:
        frame.config(bg=colors[color])
 
def changeSize(sizeNum):
    if frame is not None:
        size = sizes[sizeNum].split("x")
        frame.config(width=size[0], height=size[1])
 
def main():
    global frame
 
    root = Tkinter.Tk()
    frame = Tkinter.Frame(root, width=300, height=250, bg="black")
 
    menu = Tkinter.Menu(root)
    root.config(menu=menu)
 
    colorMenu = Tkinter.Menu(menu)
    menu.add_cascade(label="Color", menu=colorMenu)
    colorMenu.add_command(label="Red", command=lambda *color: changeColor(1))
    colorMenu.add_command(label="Green", command=lambda *color: changeColor(2))
    colorMenu.add_command(label="Blue", command=lambda *color: changeColor(3))
    colorMenu.add_command(label="Reset", command=lambda *color: changeColor(0))
 
    sizeMenu = Tkinter.Menu(menu)
    menu.add_cascade(label="Size", menu=sizeMenu)
    sizeMenu.add_command(label="Square", command=lambda *size: changeSize(0))
    sizeMenu.add_command(label="Rectangle", command=lambda *size: changeSize(1))
 
    frame.grid(row=0, column=0, sticky=Tkinter.NSEW)
    root.mainloop()
 
if __name__ == "__main__":
    main()