Ткинтер. ткинтер. Для построения графического интерфейса в библиотеке Tk отобраны следующие
Скачать 239.78 Kb.
|
Классы виджетов Для построения графического интерфейса в библиотеке Tk отобраны следующие классы виджетов (в алфавитном порядке): 1. Button (Кнопка) Простая кнопка для вызова некоторых действий (выполнения определенной команды). 2. Canvas (Рисунок) Основа для вывода графических примитивов. 3. Checkbutton (Флажок) Кнопка, которая умеет переключаться между двумя состояниями при нажатии на нее. 4. Entry (Поле ввода) Горизонтальное поле, в которое можно ввести строку текста. 5. Frame (Рамка) Виджет, который содержит в себе другие визуальные компоненты. 6. Label (Надпись) Виджет может показывать текст или графическое изображение. 7. Listbox (Список) Прямоугольная рамка со списком, из которого пользователь может выделить один или несколько элементов. 8. Menu (Меню) Элемент, с помощью которого можно создавать всплывающие (popup) и ниспадающие (pulldown) меню. 9. Menubutton (Кнопка-меню) Кнопка с ниспадающим меню. 10. Message (Сообщение) Аналогично надписи, но позволяет заворачивать длинные строки и менять размер по требованию менеджера расположения. 11. Radiobutton (Селекторная кнопка) Кнопка для представления одного из альтернативных значений. Такие кнопки, как правило, действует в группе. При нажатии на одну из них кнопка группы, выбранная ранее, "отскакивает". 12. Scale (Шкала) Служит для задания числового значения путем перемещения движка в определенном диапазоне. 13. Scrollbar (Полоса прокрутки) Полоса прокрутки служит для отображения величины прокрутки в других виджетах. Может быть как вертикальной, так и горизонтальной. 14. Text (Форматированный текст) Этот прямоугольный виджет позволяет редактировать и форматировать текст с использованием различных стилей, внедрять в текст рисунки и даже окна. 15. Toplevel (Окно верхнего уровня) Показывается как отдельное окно и содержит внутри другие виджеты. Все эти классы не имеют отношений наследования друг с другом - они равноправны. Этот набор достаточен для построения интерфейса в большинстве случаев В системе современного графического интерфейса имеется возможность отслеживать различные события, связанные с клавиатурой и мышью, и происходящие на "территории" того или иного виджета. В Tk события описываются в виде текстовой строки - шаблона события, состоящего из трех элементов (модификаторы, тип события и детализация события). Тип события Содержание события Activate Активизация окна ButtonPress Нажатие кнопки мыши ButtonRelease Отжатие кнопки мыши Deactivate Деактивация окна Destroy Закрытие окна Enter Вхождение курсора в пределы виджета FocusIn Получение фокуса окном FocusOut Потеря фокуса окном KeyPress Нажатие клавиши на клавиатуре KeyRelease Отжатие клавиши на клавиатуре Leave Выход курсора за пределы виджета Motion Движение мыши в пределах виджета MouseWheel Прокрутка колесика мыши Reparent Изменение родителя окна Visibility Изменение видимости окна Примеры описаний событий строками и некоторые названия клавиш приведены ниже: " третьей, если считать на трехкнопочной мыши слева-направо). " качестве модификаторов могут быть использованы следующие (список неполный): Control, Shift, Lock, Button1-Button5 или B1-B5, Meta, Alt, Double, Triple. Просто символ обозначает событие - нажатие клавиши. Например, "k" - тоже, что " Cancel, BackSpace, Tab, Return, Shift_L, Control_L, Alt_L, Pause, Caps_Lock, Escape, Prior, Next, End, Home, Left, Up, Right, Down, Print, Insert, Delete, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, Num_Lock, Scroll_Lock, space, less Здесь , или менее соответствуют надписям на стандартной клавиатуре Примечание: Следует заметить, что Shift_L, в отличие от Shift, нельзя использовать как модификатор. В конкретной среде комбинации, означающие что-то особенное в системе, могут не дойти до графического приложения. Например, известный всем Ctrl-Alt-Del. Следующая программа позволяет печатать направляемые виджету события, в частности - keysym, а также анализировать, как различные клавиши можно представить в шаблоне события: from Tkinter import * tk = Tk() # основное окно приложения txt = Text(tk) # текстовый виджет, принадлежащий окну tk txt.pack() # располагается менеджером pack # функция обработки события def event_info(event): txt.delete("1.0", END) # удаляется с начала до конца текста for k in dir(event): # цикл по атрибутам события if k[0] != "_": # берутся только неслужебные атрибуты # готовится описание атрибута события ev = "%15s: %s\n" % (k, repr(getattr(event, k))) txt.insert(END, ev) # добавляется в конец текста # привязывается виджету txt функция event_info для обработки событий, # соответствующих шаблону txt.bind(" tk.mainloop() # главный цикл обработки событий При нажатии клавиши Esc в окне можно увидеть примерно следующее: char: '\x1b' delta: 9 height: 0 keycode: 9 keysym: 'Escape' keysym_num: 65307 num: 9 send_event: False serial: 159 state: 0 time: -1072960858 type: '2' widget: width: 0 x: 83 x_root: 448 y: 44 y_root: 306 Следует объяснить некоторые из этих атрибутов: char Нажатый символ (для некоторых событий - ??) height, width Высота и ширина. focus Был ли в момент события фокус у окна? keycode Код символа (скан-код клавиатуры). keysym Символическое имя клавиши. serial Серийный номер события. Увеличивается по мере возникновения событий. time Время возникновения события. Все время увеличивается. widget Виджет, в котором возникло событие. x, y Координаты указателя в виджете во время события. Создание и конфигурирование виджета Создание виджета происходит вызовом конструктора соответствующего класса. Вызов конструктора имеет следующий синтаксис: Widget([master[, option=value, ...]]) Здесь Widget - класс виджета, master - виджет-хозяин, option и value - конфигурационная опция и ее значение (таких пар может быть несколько). Каждый виджет имеет свойства, которые можно устанавливать (конфигурировать) с помощью методов config() (или configure() ) и читать с помощью методов, подобных методам работы со словарями. Ниже приведен возможный синтаксис для работы со свойствами: widget.config(option=value, ...) widget["option"] = value value = widget["option"] widget.keys() В случае, когда имя свойства совпадает с ключевым словом языка Python, принято использовать после имени одиночное подчеркивание. Так, свойство class нужно задавать как class_, а to как to_. Изменять конфигурацию виджета можно в любой момент. Это изменение прорисуется на экране по возвращении в цикл обработки событий или при явном вызове update_idletasks(). Следующий пример показывает окно с двумя виджетами внутри - полем ввода и надписью. С помощью переменной надпись напрямую связана с полем ввода. Этот пример нарочно использует очень много свойств, чтобы продемонстрировать возможности по конфигурированию: from Tkinter import * tk = Tk() tv = StringVar() Label(tk, textvariable=tv, relief="groove", borderwidth=3, font=("Courier", 20, "bold"), justify=LEFT, width=50, padx=10, pady=20, takefocus=False, ).pack() Entry(tk, textvariable=tv, takefocus=True, ).pack() tv.set("123") tk.mainloop() Виджеты конфигурируются прямо при создании. Более того, виджеты не связываются с именами, их только располагают внутри виджета-окна. В данном примере использованы свойства textvariable (текстовая переменная), relief (рельеф), borderwidth (ширина границы), justify (выравнивание), width (ширина, в знакоместах), padx и pady (прослойка в пикселях между содержимым и границами виджета), takefocus (возможность принять фокус при нажатии клавиши Tab), font (шрифт, один из способов его задания). Эти свойства достаточно типичны для многих виджетов, хотя иногда единицы измерения могут отличаться, например, для виджета Canvas ширина задается в пикселях, а не в знакоместах. В следующем примере демонстрируются возможности по назначению цветов фону, переднему плану (тексту), выделению виджета (подсветка границы) в активном состоянии и при отсутствии фокуса: from Tkinter import * tk = Tk() tv = StringVar() Entry(tk, textvariable=tv, takefocus=True, borderwidth=10, ).pack() mycolor1 = "#%02X%02X%02X" % (200, 200, 20) Entry(tk, textvariable=tv, takefocus=True, borderwidth=10, foreground=mycolor1, # fg, текст виджета background="#0000FF", # bg, фон виджета highlightcolor='green', # подсветка при фокусе highlightbackground='red', # подсветка без фокуса ).pack() tv.set("123") tk.mainloop() При желании можно задать стилевые опции для всех виджетов сразу: с помощью метода tk_setPalette(). Помимо использованных выше свойств в этом методе можно использовать selectForeground и selectBackground (передний план и фон выделения), selectColor (цвет в выбранном состоянии, например, у Checkbutton ), insertBackground (цвет точки вставки) и некоторые другие. Примечание: Получить значение из поля ввода можно и при помощи метода get(). Например, если назвать объект класса Entry именем e, получить значение можно так: e.get(). Правда, этот метод не обладает той же гибкостью, что метод get() экземпляров класса для форматированного текста Text: можно взять только все значение целиком. Виджет форматированного текста Для того чтобы показать работу с нетривиальным виджетом, можно взять виджет ScrolledText из одноименного модуля Python. Этот виджет аналогичен рамке с форматированным текстом и вертикальной полосой прокрутки: from Tkinter import * from ScrolledText import ScrolledText tk = Tk() # окно верхнего уровня txt = ScrolledText(tk) # виджет текста с прокруткой txt.pack() # виджет размещается for x in range(1, 1024): # виджет наполняется текстовым содержимым txt.insert(END, str(2L**x)+"\n") tk.mainloop() Примечание: Получить значение из поля ввода можно и при помощи метода get(). Например, если назвать объект класса Entry именем e, получить значение можно так: e.get(). Правда, этот метод не обладает той же гибкостью, что метод get() экземпляров класса для форматированного текста Text: можно взять только все значение целиком. Виджет форматированного текста Для того чтобы показать работу с нетривиальным виджетом, можно взять виджет ScrolledText из одноименного модуля Python. Этот виджет аналогичен рамке с форматированным текстом и вертикальной полосой прокрутки: from Tkinter import * from ScrolledText import ScrolledText tk = Tk() # окно верхнего уровня txt = ScrolledText(tk) # виджет текста с прокруткой txt.pack() # виджет размещается for x in range(1, 1024): # виджет наполняется текстовым содержимым txt.insert(END, str(2L**x)+"\n") tk.mainloop() Теперь следует рассмотреть методы и свойства виджета с форматированным текстом более подробно. Для навигации в тексте в Tk предусмотрены специальные индексы. Индексы вроде 1.0 и END уже встречались - это начало текста (первая строка, нулевой символ) и его конец. (В Tk строки нумеруются с единицы, а символы строки - с нуля). Более полный список индексов: 1. L.C Здесь L - номер строки, а C - номер символа в строке. 2. INSERT Точка вставки. 3. CURRENT Символ, ближайший к курсору мыши. 4. END Позиция сразу за последним символом в тексте 5. M.first, M.last Индексы начала и конца помеченного тегом M участка текста. 6. SEL_FIRST, SEL_LAST Индексы начала и конца выделенного текста. 7. M Пользователь может определять свои именованные позиции в тексте (аналогично END, INSERT или CURRENT ). При редактировании текста маркеры будут сдвигаться с заданными для них правилами. 8. @x,y Символ текста, ближайший к точке с координатами x, y. Следующий пример показывает, как снабдить форматированный текст гипертекстовыми возможностями: from Tkinter import * import urllib tk = Tk() txt = Text(tk, width=64) # поле с текстом txt.grid(row=0, column=0, rowspan=2) addr=Text(tk, background="White", width=64, height=1) # поле адреса addr.grid(row=0, column=1) page=Text(tk, background="White", width=64) # поле с html-кодом page.grid(row=1, column=1) def fetch_url(event): click_point = "@%s,%s" % (event.x, event.y) trs = txt.tag_ranges("href") # список областей текста, отмеченных как href url = "" # определяется, на какой участок пришелся щелчок мыши, и берется # соответствующий ему URL for i in range(0, len(trs), 2): if txt.compare(trs[i], "<=", click_point) and \ txt.compare(click_point, "<=", trs[i+1]): url = txt.get(trs[i], trs[i+1]) html_doc = urllib.urlopen(url).read() addr.delete("1.0", END) addr.insert("1.0", url) # URL помещается в поле адреса page.delete("1.0", END) page.insert("1.0", html_doc) # показывается HTML-документ textfrags = ["Python main site: ", "http://www.python.org", "\nJython site: ", "http://www.jython.org", "\nThat is all!"] for frag in textfrags: if frag.startswith("http:"): txt.insert(END, frag, "href") # URL помещается в текст с меткой href else: txt.insert(END, frag) # фрагмент помещается в текст # ссылки отмечаются подчеркиванием и синим цветом txt.tag_config("href", foreground="Blue", underline=1) # при щелчке мыши на тексте, отмеченном как "href", # следует вызывать fetch_url() txt.tag_bind("href", "<1>", fetch_url) tk.mainloop() # запускается цикл событий Для придания некоторым участкам текста особых свойств необходимо их отметить тегом. В данном случае URL отмечается тегом href. Позднее с помощью метода tag_config() задаются свойства отображения текста, отмеченного таким тегом. Методом tag_bind() привязывается некоторое событие (щелчок мыши) с вызовом заданной функции ( fetch_url() ). В самой функции fetch_url() нужно в начале определить, на какой именно участок текста пришелся щелчок мыши. Для этого с помощью метода tag_ranges() получаются все интервалы, которые отмечены как href. Для определения конкретного URL проводятся сравнения (методом compare() ) точки щелчка мышью с каждым из интервалов. Так находится интервал, на который попал щелчок, и с помощью метода get() получается текстовое значение найденного интервала. Найдя URL, его в поле записываются адреса, и получается HTML-код, соответствующий URL. Этот пример показывает основные принципы работы с форматированным текстом. Примененными методами арсенал виджета Изображения в Tkinter Средствами Tkinter можно выводить не только текст, примитивные формы (с помощью виджета Canvas), но и растровые изображения. Следующий пример демонстрирует вывод иконки с растровым изображением (для этого примера нужно предварительно установить пакет Python Imaging Library, PIL): import Tkinter, Image, ImageTk FILENAME = "lena.jpg" # файл с графическим изображением tk = Tkinter.Tk() c = Tkinter.Canvas(tk, width=128, height=128) src_img = Image.open(FILENAME) img = ImageTk.PhotoImage(src_img) c.create_image(0, 0, image=img, anchor="nw") c.pack() Tkinter.Label(tk, text=FILENAME).pack() tk.mainloop() В результате получается: Здесь использован виджет-рисунок ( Canvas ). С помощью функций из пакетов Image и ImageTk из PIL получается объект-изображение, подходящее для включения в рисунок Tkinter. Свойство anchor задает угол, который привязывается к координатам (0, 0) в рисунке. В данном примере это северо-западный угол (NW - North-West). Другие возможности: n (север), w (запад), s (юг), e (восток), ne, sw, se и с (центр). В следующем примере показаны графические примитивы, которые можно использовать на рисунке (приведенные комментарии объясняют свойства графических объектов внутри виджета-рисунка): from Tkinter import * tk = Tk() # Рисунок 300x300 пикселей, фон - белый c = Canvas(tk, width=300, height=300, bg="white") c.create_arc((5, 5, 50, 50), style=PIESLICE) # Сектор ("кусок пирога") c.create_arc((55, 5, 100, 50), style=ARC) # Дуга c.create_arc((105, 5, 150, 50), style=CHORD, # Сегмент start=0, extent=150, fill="blue") # от 0 до 150 градусов # Ломаная со стрелкой на конце c.create_line([(5, 55), (55, 55), (30, 95)], arrow=LAST) # Кривая (сглаженная ломаная) c.create_line([(105, 55), (155, 55), (130, 95)], smooth=1) # Многоугольник зеленого цвета c.create_polygon([(205, 55), (255, 55), (230, 95)], fill="green") # Овал c.create_oval((5, 105, 50, 120), ) # Прямоугольник красного цвета с большой серой границей c.create_rectangle((105, 105, 150, 130), fill="red", outline="grey", width="5") # Текст c.create_text((5, 205), text=" Hello", anchor="nw") # Эта точка визуально обозначает угол привязки c.create_oval((5, 205, 6, 206), outline="red") # Текст с заданным выравниванием c.create_text((105, 205), text="Hello,\nmy friend!", justify=LEFT, anchor="c") c.create_oval((105, 205, 106, 206), outline="red") # Еще один вариант c.create_text((205, 205), text="Hello,\nmy friend!", justify=CENTER, anchor="se") c.create_oval((205, 205, 206, 206), outline="red") c.pack() tk.mainloop() В результате работы этой программы на экране появится окно: Следует заметить, что методы create_* создают объекты, свойства которых можно менять в дальнейшем: переместить в другое место, перекрасить, удалить, изменить порядок и т.д. В следующем примере можно нарисовать кружок, меняющий цвет по щелчку мыши: from Tkinter import * from random import choice colors = "Red Orange Yellow Green LightBlue Blue Violet".split() R = 10 tk = Tk() c = Canvas(tk, bg="White", width="4i", height=300, relief=SUNKEN) c.pack(expand=1, fill=BOTH) def change_ball(event): c.coords(CURRENT, (event.x-R, event.y-R, event.x+R, event.y+R)) c.itemconfigure(CURRENT, fill=choice(colors)) oval = c.create_oval((100-R, 100-R, 100+R, 100+R), fill="Black") c.tag_bind(oval, "<1>", change_ball) tk.mainloop() Здесь нарисован кружок радиуса R, с ним связана функция change_ball() по нажатию кнопки мыши. В указанной функции заданы новые координаты кружка (его центр расположен в месте щелчка мыши) и затем изменен цвет случайным образом методом itemconfigure(). Тег CURRENT в Tkinter использован для указания объекта, который принял событ Графическое приложение на Tkinter Теперь следует рассмотреть небольшое приложение, написанное с использованием Tkinter. В этом приложении будет загружен файл с графическим изображением. Приложение будет иметь простейшее меню File с пунктами Open и Exit, а также виджет Canvas, на котором и будут демонстрироваться изображения (опять потребуется пакет PIL): from Tkinter import * import Image, ImageTk, tkFileDialog global img, imgobj def show(): global img, imgobj # Запрос на имя файла filename = tkFileDialog.askopenfilename() if filename != (): # Если имя файла было задано пользователем # рисуется изображение из файла src_img = Image.open(filename) img = ImageTk.PhotoImage(src_img) # конфигурируется изображение на рисунке c.itemconfigure(imgobj, image=img, anchor="nw") tk = Tk() main_menu = Menu(tk) # формируется меню tk.config(menu=main_menu) # меню добавляется к окну file_menu = Menu(main_menu) # создается подменю main_menu.add_cascade(label="File", menu=file_menu) # Заполняется меню File file_menu.add_command(label="Open", command=show) file_menu.add_separator() # черта для отделения пунктов меню file_menu.add_command(label="Exit", command=tk.destroy) c = Canvas(tk, width=300, height=300, bg="white") # готовим объект-изображение на рисунке imgobj = c.create_image(0, 0) c.pack() tk.mainloop() Приложение (с загруженной картинкой) будет выглядеть так: Стоит отметить, что здесь пришлось применить две глобальные переменные. Это не очень хорошо. Существует другой подход, когда приложение создается на основе окна верхнего уровня. Таким образом, само приложение становится особым виджетом. Переделанная программа представлена ниже: from Tkinter import * import Image, ImageTk, tkFileDialog class App(Tk): def __init__(self): Tk.__init__(self) main_menu = Menu(self) self.config(menu=main_menu) file_menu = Menu(main_menu) main_menu.add_cascade(label="File", menu=file_menu) file_menu.add_command(label="Open", command=self.show_img) file_menu.add_separator() file_menu.add_command(label="Exit", command=self.destroy) self.c = Canvas(self, width=300, height=300, bg="white") self.imgobj = self.c.create_image(0, 0) self.c.pack() def show_img(self): filename = tkFileDialog.askopenfilename() if filename != (): src_img = Image.open(filename) self.img = ImageTk.PhotoImage(src_img) self.c.itemconfigure(self.imgobj, image=self.img, anchor="nw") app = App() app.mainloop() В объекте заключена информация, которая до этого была глобальной со всеми следующими из этого ограничениями. Можно пойти дальше и выделить в отдельный метод настройку меню (если приложение будет динамически изменять меню, объектыменю тоже могут быть сохранены в приложении). Примечание: На некоторых системах новые версии Python плохо работают с национальными кодировками, в частности, с кодировками для кириллицы. Это связано с переходом на Unicode Tcl/Tk. Проблем можно избежать, если использовать кодировку UTF-8 в строках, которые должны выводиться в виджетах1>1> |