Меню
Видеоучебник
Видеоучебник  /  Информатика  /  Основы алгоритмизации и программирования на языке Python  /  Создание приложения с использованием виджетов

Создание приложения с использованием виджетов

Урок 28. Основы алгоритмизации и программирования на языке Python

Из этого урока ученики узнают, как создать простое приложение с графическим интерфейсом пользователя. Графический интерфейс будет создан с помощью программы-визуализатора QtDesigner, входящей в состав графической библиотеки PyQt5.
Плеер: YouTube Вконтакте

Конспект урока "Создание приложения с использованием виджетов"

Вопросы:

·     Элементы управления: кнопки, метки и поля ввода.

·     Создание и настройка окон сообщений.

Рассмотрим задачу. Написать приложение с графическим интерфейсом, вычисляющее сумму двух целых положительных чисел, вводимых пользователем.

Вначале с помощью редактора QtDesigner создадим пользовательский интерфейс приложения. Создадим форму для главного окна и настроим её размер.

Разместим на форме главного окна элемент управления Line Edit. Это будет поле ввода для первого числа. Настроим его размеры и изменим имя его объекта. Назовём его txtNum1. Скопируем его, выделив и используя сочетание клавиш Ctrl+C. Разместим копию поля ввода на форме, используя сочетание клавиш Ctrl+V. Разместим его справа на небольшом расстоянии от предыдущего. Назовём это поле txtNum2. Это будет поле ввода для второго числа. Теперь разместим между двумя полями ввода компонент Label. Это текстовая метка. Изменим текст метки на символ «+». Также изменим выравнивание текста в метке. За него отвечает свойство alignment. Есть горизонтальное и вертикальное выравнивания. Изменим горизонтальное выравнивание текста метки на выравнивание по центру. Настроим размер метки и выровняем её относительно полей ввода. Создадим копию этой метки и разместим её справа от второго поля ввода. Изменим название объекта этой метки на lblSum, изменим текст метки на знак равенства, после чего установим её горизонтальное выравнивание по левому краю. Увеличим горизонтальный размер метки, так как позже в неё будем выводить сумму чисел, введённых пользователем в поля ввода.

Теперь разместим на форме, ниже остальных элементов управления, кнопку PushButton. Назовём её btnResult. Изменим текст кнопки на надпись «Вычислить». Выровняем её относительно остальных элементов управления. Сохраним созданную форму под именем sumGUI в каталоге по умолчанию.

Теперь с помощью командной строки сконвертируем файл графического интерфейса в модуль языка Питон.

И просмотрим его в среде разработки. Ранее мы кратко рассмотрели структуру модуля, сформированного приложением QtDesigner. В первых 7 строках, в комментариях, следует описание модуля. Далее следует класс UiMainWindow. Он описывает созданную нами форму. И после класса следует основная программа, которая создаёт объект указанного класса и запускает у него цикл обработки событий. Класс UiMainWindow содержит методы setupUi и retranslateUi. Первый отвечает за создание и настройку формы, а также её элементов управления. Второй же метод отвечает за размещение текстовых надписей на элементах управления. Запустим модуль на выполнение. На экран было выведено окно, которое мы создали в приложении QtDesigner.

Нам нужно описать обработчик события, который будет вызываться при нажатии пользователем на кнопку «Вычислить». Для этого опишем в классе новый метод, назовём его getResult. У него будет единственный параметр – self. Работа метода будет начинаться с того, что мы считаем числа из полей ввода на форме. Считаем первое число в переменную n1. Чтобы считать текст, введённый пользователем в поле ввода, нужно обратиться к нему. У нас поле ввода называется txtNum1. У этого поля ввода нужно вызвать метод, название которого совпадает с соответствующим свойством элемента управления. Нас интересует свойство text, поэтому вызовем метод text без параметров. Он вернёт текстовую строку – значение соответствующего свойства. Нам нужно преобразовать эту строку в целое число. Для этого воспользуемся функцией int. Скопируем написанную строку кода и изменим её для считывания в переменную n2 текста из поля ввода txtNum2. Теперь в переменной s рассчитаем сумму значений переменных n1 и n2. Далее нам нужно вывести результат расчёта в метку lblSum. Для этого у метки вызовем метод setText, он присваивает свойству text новое значение. Этот метод принимает на вход один текстовый параметр – новое значение поля. Зададим его как результат склейки двух символьных строк. Первая символьная строка будет содержать «= ». Второй строкой будет преобразованное в строковый тип значение переменной s.

def getResult (self):

    n1 = int (txtNum1.text ())

    n2 = int (txtNum2.text ())

    s = n1 + n2

    self.lblSum.setText ('= ' + str (s))

Описание метода getResult завершено. Теперь нужно сделать его обработчиком события нажатия на кнопку btnResult. Для этого в конце метода setupUi добавим строку кода, которая обращается к кнопке btnResult на форме. У этой кнопки нас интересует событие clicked. С помощью метода connect можно назначить этому событию обработчик. В качестве параметра у этого метода нам нужно указать метод, который будет обработчиком события, то есть описанный нами getResult.

self.btnResult.clicked.connect (self.getResult)

Описание модуля завершено. Сохраним его и запустим на выполнение. На экране появилось окно, которое мы создали. Введём в поля ввода числа 3 и 5, после чего нажмём на кнопку «Вычислить». После знака равенства появилось число 8. Это действительно сумма введённых чисел. Пока наша программа работает правильно, но теперь уберём все данные из полей ввода и нажмём на кнопку «Вычислить». Программа завершила своё исполнение ошибкой.

Так произошло потому, что мы не учли возможность ввода пользователем некорректных данных. Исправим это. Условимся, что в случае, если хотя бы одно из полей ввода окажется пустым, будем выводить на экран окно с соответствующим сообщением об ошибке. У вас наверняка возник вопрос: «Как же мы вызовем окно с сообщением об ошибке? Ведь мы не создали для него интерфейс.». Дело в том, что мы можем создать форму окна с сообщением, как и любые другие элементы управления пользовательским интерфейсом, в коде программы.

Изменим код функции getResult. Поместим весь код, который в ней содержится, в блок try… Далее опишем блок except. Создадим в переменной msg объект класса QMessageBox, который описан в модуле QtWidgets. Таким образом, у нас уже есть простое окно пока без сообщения об ошибке. Чтобы показать его, нужно у объектаmsg вызвать метод exec без параметров.

def getResult (self):

    try:

        n1 = int (txtNum1.text ())

        n2 = int (txtNum2.text ())

        s = n1 + n2

        self.lblSum.setText ('= ' + str (s))

    except:

        msg = QtWidgets.QMessageBox ()

        msg.exec ()

Сохраним модуль и запустим его на выполнение. В окне программы оставим поля ввода пустыми и сразу нажмём на кнопку «Вычислить». На экран было выведено пустое окно с единственной кнопкой – «OK». Закроем программу.

Теперь настроим созданное окно. Для этого в классе QMessageBox реализовано несколько методов. Сначала зададим заголовок окна. Для этого между командами создания и вызова окна у объекта msg вызовем метод setWindowTitle. Как ясно из названия, этот метод задаёт значение свойства windowTitle, в котором хранится заголовок окна. Зададим в качестве аргумента текстовую строку «Ошибка ввода». Теперь изменим текст окна. Для этого вызовем у объекта метод setText. Текст будет содержать сообщение о том, что не все данные заданы.

Снова сохраним модуль и запустим его на выполнение. Сразу нажмём на кнопку «Вычислить». На экран было выведено окно с заголовком «Ошибка ввода» и текстом о том, что не все данные заданы. На этом наша работа над окном ошибки не закончена.

Окно должно содержать информацию о том, какое из полей ввода является пустым. Поэтому запишем ветвление, в котором проверим, является ли значение метода text у обоих полей ввода пустой строкой. Если это условие выполняется, то вызовем у нашего окна с сообщением метод setInformativeText, в котором в качестве аргумента укажем текстовое сообщение о том, что оба поля ввода пусты. Если это условие не выполняется, проверим, является ли пустым первое поле ввода. Если первое поле ввода действительно пустое, то зададим в качестве информации об ошибке сообщение об этом. Точно так же поступим, если пустым является только второе поле ввода.

def getResult (self):

    try:

        n1 = int (txtNum1.text ())

        n2 = int (txtNum2.text ())

        s = n1 + n2

        self.lblSum.setText ('= ' + str (s))

    except:

        msg = QtWidgets.QMessageBox ()

        msg.setWindowTitle ('Ошибка ввода')

        msg.setText ('Не все данные заданы.')

        if self.txtNum1.text () == '' and self.txtNum1.text () == '':

            msg.setInformativeText ('Оба поля ввода пусты.')

        elif self.txtNum1.text () == '':

            msg.setInformativeText ('Первое поле ввода пустое.')

        elif self.txtNum2.text () == '':

            msg.setInformativeText ('Второе поле ввода пустое.')

        msg.exec ()

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

Обычно окна программ можно разделить на несколько типов в зависимости от значков, которые на них присутствуют. Это могут быть информационные окна, окна с вопросом, окна с предупреждением и окна с сообщением о критической ошибке.

Используем для вывода нашего окна значок предупреждения. Для этого вызовем у объекта окна метод setIcon, в котором в качестве параметра укажем вызванное у нашего окна свойство Warning.

def getResult (self):

    try:

        n1 = int (txtNum1.text ())

        n2 = int (txtNum2.text ())

        s = n1 + n2

        self.lblSum.setText ('= ' + str (s))

    except:

        msg = QtWidgets.QMessageBox ()

        msg.setWindowTitle ('Ошибка ввода')

        msg.setText ('Не все данные заданы.')

        if self.txtNum1.text () == '' and self.txtNum1.text () == '':

            msg.setInformativeText ('Оба поля ввода пусты.')

        elif self.txtNum1.text () == '':

            msg.setInformativeText ('Первое поле ввода пустое.')

        elif self.txtNum2.text () == '':

            msg.setInformativeText ('Второе поле ввода пустое.')

    msg.setIcon (msg.Warning)   

    msg.exec ()

Снова сохраним модуль и проверим наше сообщение об ошибке. На этот раз в окне с сообщением об ошибке присутствует значок предупреждения.

Однако, мы не рассмотрели ещё одну ситуацию: когда в поля ввода задаются не числа. В качестве решения можно ограничить возможности пользователя по вводу символов в поля ввода. Мы можем в коде программы запретить пользователю вводить в поля ввода любые символы, кроме цифр.

Опишем для этого метод changeText, который будет вызываться при изменении текста в одном из полей ввода. В самом начале метода сохраним в строковой переменной s текст из поля ввода. И тут перед нами встаёт вопрос: «Из какого поля ввода нужно взять текст? Ведь мы не знаем, в каком именно поле ввода он был изменён». Для того, чтобы узнать, каким элементом управления было вызвано событие, нужно обратиться к текущему циклу обработки событий. Для этого из модуля QtCore, из класса QCoreApplication, вызывается метод instance. У текущего цикла обработки событий вызовем метод sender. На русский язык название этого метода можно перевести как «отправитель». Этот метод возвращает ссылку на элемент управления, который отправил сообщение о событии. В переменной s сохраним результат метода text, вызванного у объекта-отправителя. Описываемый метод будет автоматически вызываться при любом изменении текста в любом из полей ввода. Это значит, что при вызове данного метода в поле ввода может быть не более одного некорректного символа. Запишем цикл с параметром i, в котором будем последовательно перебирать индексы символов строки s от последнего к первому, так как чаще всего новые символы добавляются в конец строки. В этом цикле, если мы найдём в строке s символ, не являющийся цифрой, то мы удалим его из строки, после чего завершим цикл. Так, если в процессе работы цикла в строке будет найден некорректный символ, то он будет удалён из строки. После работы цикла вызовем у объекта-отправителя метод setText, которому в качестве аргумента зададим изменённую строку s. Таким образом, если в поле будет введён некорректный символ, то он сразу будет удалён.

def changeText:

    s = QtCore.QCoreApplication.instance ().sender ().text ()

    for i in range (len (s) – 1, - 1, -1):

        if not s[i].isdigit ():

            s = s[0:i] + s[i + 1:len (s)]

            break

Теперь в конце метода setupUi свяжем у поля ввода txtNum1 событие textChanged с описанным нами методом changeText. Скопируем эту строку кода и изменим её так, чтобы она связывала у поля txtNum2 то же событие с тем же методом.

Сохраним модуль и запустим его на выполнение. Теперь при попытке ввести в поле ввода любой символ, кроме цифры, он будет сразу удалён, однако это происходит так быстро, что мы просто не успеваем увидеть изменений в поле ввода. Попробуем задать числа сто и сорок пять. Их сумма действительно равна ста сорока пяти. Попробуем оставить второе поле ввода пустым. Программа вывела сообщение об ошибке, в котором указано, что второе поле ввода пустое. Программа работает правильно. Задача решена.

Мы узнали:

·     Как происходят создание и настройка таких компонентов, как поля ввода, метки и кнопки.

·     Как создать приложение с графическим интерфейсом с использованием перечисленных элементов управления,

Мы научились:

·     Создавать и настраивать окна с сообщениями в приложениях с графическим интерфейсом.

0
1396

Комментарии 0

Чтобы добавить комментарий зарегистрируйтесь или на сайт