Многократно используемый класс формы

mnogokratno ispolzuemyj klass formy Сетевые сценарии

Если вы похожи на меня, то писать всю реализацию компоновки формы для этих двух сценариев покажется вам утомительным, какой бы менеджер компоновки, pack или grid, вы ни использовали. Мне это показалось настолько скучным, что я решил написать класс структуры формы общего назначения, представленный в примере 12.20, который выполняет большую часть черновой работы по компоновке элементов графического интерфейса.

Пример 12.20. PP4E\Internet\Sockets\form.py

################################################################## многократно используемый класс формы, задействованный

в сценарии getfilegui (и в других)

##################################################################

from tkinter import * entrysize = 40

class Form: # немодальное окно формы

def __init__(self, labels, parent=None): # передать список меток полей labelsize = max(len(x) for x in labels) + 2

box = Frame(parent) # в окне есть ряды, кнопка

box.pack(expand=YES, fill=X) # ряды оформлены как фреймы

rows = Frame(box, bd=2, relief=GROOVE) # нажатие кнопки или Enter

rows.pack(side=TOP, expand=YES, fill=X) # вызывают метод onSubmit self.content = {} for label in labels:

row = Frame(rows) row.pack(fill=X)

Label(row, text=label, width=labelsize).pack(side=LEFT) entry = Entry(row, width=entrysize) entry.pack(side=RIGHT, expand=YES, fill=X) self.content[label] = entry

Button(box, text=’Cancel’, command=self.onCancel).pack(side=RIGHT)

Button(box, text=’Submit’, command=self.onSubmit).pack(side=RIGHT) box.master.bind(‘<Return>’, (lambda event: self.onSubmit()))

def onSubmit(self): # переопределить этот метод

for key in self.content: # ввод пользователя

print(key, ‘\t=>\t’, self.content[key].get()) # в self.content[k]

def onCancel(self): # переопределить при необходимости

Tk().quit() # по умолчанию осуществляет выход

class DynamicForm(Form):

def __init__(self, labels=None):

labels = input(‘Enter field names: ‘).split()

Form.__init__(self, labels)

def onSubmit(self):

print(‘Field values…’)

Form.onSubmit(self)

self.onCancel()

if __name__ == ‘__main__’:

import sys

if len(sys.argv) == 1:

Form([‘Name‘, ‘Age‘, ‘Job‘]) # предопределенные поля остаются

else: # после передачи

DynamicForm() # динамически созданные поля

mainloop() # исчезают после передачи

Сравните этот подход с тем, что был реализован в функции конструирования рядов форм, которую мы написали в главе 10, в примере 10.9. В то время как этот пример заметно уменьшает объем программного кода, необходимого для его использования, он реализует более полную и автоматизированную схему — модуль конструирует форму целиком, исходя из заданного набора имен меток, и предоставляет словарь со всеми виджетами полей ввода, готовыми для извлечения информации.

Если запустить этот модуль как самостоятельный сценарий, выполняется программный код самотестирования, находящийся в конце. При запуске без аргументов (или двойным щелчком в проводнике файлов Windows) программный код самопроверки генерирует форму с готовыми полями, как показано на рис. 12.4, и выводит значения полей при нажатии клавиши Enter или щелчке на кнопке Submit:

C:\\PP4E\Internet\Sockets> python form.py

Age => 40

Name => Bob

Job => Educator, Entertainer

Рис. 12.4. Тест формы, предопределенные поля ввода

 

При запуске с аргументами командной строки программный код самопроверки в модуле класса формы предлагает ввести произвольную группу имен полей формы. При желании поля могут создаваться динамически. На рис. 12.5 показана форма для ввода, сконструированная в результате приведенного ниже диалога в консоли. Имена полей могут быть взяты из командной строки, но в таких простых проверках столь же хорошо действует и встроенная функция input. В этом режиме графический интерфейс исчезает после первой передачи данных, потому что так определено в методе DynamicForm.onSubmit:

C:\\PP4E\Internet\Sockets> python form.py Enter field names: Name Email Web Locale Field values

Locale => Florida

Web => http://learning-python.com

Name => Book

Email => pp4e@learning-python.com

Рис. 12.5. Тест формы, динамические поля ввода

 

И последнее, но немаловажное замечание. В примере 12.21 приводится еще одна реализация интерфейса пользователя для getfile, на этот раз построенного с помощью многократно используемого класса компоновки формы. Необходимо лишь заполнить список меток и предоставить свой метод обратного вызова onSubmit. Все действия по созданию формы совершаются «бесплатно» в результате импорта многократно используемого суперкласса Form.

Пример 12.21. PP4E\Internet\Sockets\getfilegui.py

запускает функцию client из модуля getfile и реализует графический интерфейс на основе многократно используемого класса формы;

с помощью os.chdir выполняет переход в требуемый локальный каталог, если указан (getfile сохраняет файл в cwd);

что сделать: использовать потоки выполнения, вывести индикатор хода выполнения операции и отобразить вывод getfile;

from form import Form

from tkinter import Tk, mainloop

from tkinter.messagebox import showinfo

import getfile, os

class GetfileForm(Form):

def __init__(self, oneshot=False):

root = Tk()

root.title(‘getfilegui’)

labels = [‘Server Name’, ‘Port Number’, ‘File Name’, ‘Local Dir?’] Form.__init__(self, labels, root) self.oneshot = oneshot

def onSubmit(self):

Form.onSubmit(self)

localdir = self.content[‘Local Dir?’].get()

portnumber = self.content[‘Port Number’].get() servername = self.content[‘Server Name’].get() filename = self.content[‘File Name’].get() if localdir:

os.chdir(localdir)

portnumber = int(portnumber)

getfile.client(servername, portnumber, filename) showinfo(‘getfilegui’, ‘Download complete’)

if self.oneshot: Tk().quit() # иначе останется в последнем localdir

if __name__ == ‘__main__’:

GetfileForm() mainloop()

Импортированный здесь класс компоновки формы может быть использован любой программой, где требуется организовать ввод данных в виде формы. При использовании в данном сценарии в Windows 7 получается интерфейс пользователя, как показано на рис. 12.6 (и похожий на других платформах).

Рис. 12.6. Сценарий getfilegui в действии

 

Щелчок на кнопке Submit или нажатие клавиши Enter в этой форме, как и раньше, заставляет сценарий getfilegui вызвать импортированную функцию клиентской части getfile.client. Однако на сей раз сначала производится переход в указанный в форме локальный каталог, куда следует сохранить полученный файл (getfile сохраняет файл в текущем рабочем каталоге, каким бы он ни был при вызове сценария). Ниже приводятся сообщения, которые выводятся в консоли клиента, а также результат проверки переданного файла — сервер все так же действует в каталоге выше testdir, а клиент сохраняет файл в каком-то другом месте после извлечения его из сокета:

C:\\Internet\Sockets> getfilegui.py

Local Dir? => C:\users\Mark\temp

File Name => testdir\ora-lp4e.gif

Server Name => localhost

Port Number => 50001

Client got testdir\ora-lp4e.gif at Sun Apr 25 17:22:39 2010

C:\\Internet\Sockets> fc /B C:\Users\mark\temp\ora-lp4e.gif testdir\ora-lp4e.gif

FC: no differences encountered

Как обычно, с помощью этого интерфейса можно соединяться с серверами, которые выполняются локально на том же компьютере (как здесь) или удаленно. Если у вас сервер выполняется удаленно, укажите другое имя компьютера сервера и путь к файлу — волшебная сила сокетов «просто действует», независимо от того, где выполняется сервер, локально или удаленно.

Здесь стоит сделать одно предупреждение: графический интерфейс фактически замирает, пока происходит загрузка (даже перерисовка экрана не выполняется — попробуйте заслонить окно и снова открыть его, и вы поймете, что я имею в виду). Положение можно улучшить, запустив загрузку в отдельном потоке выполнения, но пока мы не увидим, как это делается, — в следующей главе, где будем исследовать протокол FTP, — следует считать это замечание предварительным знакомством с проблемой.

В завершение несколько последних замечаний. Во-первых, я должен отметить, что сценарии, представленные в этой главе, применяют приемы использования tkinter, которые мы уже видели раньше и здесь не станем подробно рассматривать их в интересах экономии места. Советы по реализации можно найти в главах этой книги, посвященных графическому интерфейсу.

Имейте также в виду, что все эти интерфейсы добавляются к уже существующим сценариям, повторно используя их реализацию, — таким способом можно снабдить графическим интерфейсом любой инструмент командной строки, сделав его более привлекательным и дружественным пользователю. Например, в главе 14 мы познакомимся с более удобным клиентским интерфейсом пользователя на основе tkinter, предназначенным для чтения и отправки электронной почты через сокеты (PyMailGui), который в общем-то лишь добавляет графический интерфейс к средствам обработки электронной почты. Вообще говоря, графические интерфейсы часто могут быть добавлены к программам почти что задним числом. Хотя степень разделения интерфейса пользователя и базовой логики может быть различной в каждой программе, отделение одного от другого облегчает возможность сосредоточиться на каждом из них в отдельности.

И наконец, теперь, когда я показал, как создавать интерфейсы пользователя поверх сценария getfile из этой главы, должен также сказать, что в действительности они не столь полезны, как может показаться. В частности, клиенты getfile могут общаться только с теми компьютерами, на которых выполняется сервер getfile. В следующей главе мы откроем для себя еще один способ загрузки файлов с сервера, протокол FTP, который также основывается на сокетах, но предоставляет интерфейс более высокого уровня и доступен в качестве стандартной службы на многих компьютерах в Сети. Обычно не требуется запускать индивидуально разработанный сервер для передачи файлов через FTP, как мы это делали с getfile. Сценарии с графическим интерфейсом пользователя, представленные в этой главе, можно легко изменить, чтобы получить нужный файл с помощью инструментов FTP, имеющихся в Python, а не модуля getfile. Но я не стану сейчас все рассказывать, а просто предложу продолжить чтение.

Использованная литература:

Марк Лутц — Программирование на Python, 4-е издание, II том, 2011

Каталог сайтов Всего.ру
Оцените статью
Секреты программирования
Добавить комментарий