Я использую wxPython уже довольно давно, так что я заметил увеличение частоты появления некоторых вопросов. Одним из наиболее популярных является то, как создать окно для того, куда бы пользователь должен был ввести свои данные ещё перед тем, как загрузится остальная часть приложения. Есть масса способов реализации данной возможности, но я сконцентрируюсь на двух наиболее простых из них, так как я верю в то, что простые решения могут стать основой для более сложных.
Есть вопросы по Python?
На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!
Паблик VK
Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!
Проще говоря, нам нужно создать диалоговое окно, куда пользователь должен ввести свои логин и пароль. Если они введены верно, то программа продолжит загрузку и выведет его в главное меню или другую часть интерфейса. Здесь работает тот же принцип, что и на большинстве веб-сайтов, особенно сервисов электронной почты. Приложения для рабочего стола обычно не располагают подобной функцией, однако вы сможете встретить её в приложениях от Stamps.com и некоторых силовых структур. В данной статье, мы создадим диалоговое окно, которое будет выглядеть вот так:
Используя Pubsub
Первое решение предполагает использования встроенной в wxPython версии Pubsub. Давайте взглянем на пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
import wx class LoginDialog(wx.Dialog): """ Class to define login dialog """ def __init__(self): """Constructor""" wx.Dialog.__init__(self, None, title="Login") self.logged_in = False # user info user_sizer = wx.BoxSizer(wx.HORIZONTAL) user_lbl = wx.StaticText(self, label="Username:") user_sizer.Add(user_lbl, 0, wx.ALL|wx.CENTER, 5) self.user = wx.TextCtrl(self) user_sizer.Add(self.user, 0, wx.ALL, 5) # pass info p_sizer = wx.BoxSizer(wx.HORIZONTAL) p_lbl = wx.StaticText(self, label="Password:") p_sizer.Add(p_lbl, 0, wx.ALL|wx.CENTER, 5) self.password = wx.TextCtrl(self, style=wx.TE_PASSWORD|wx.TE_PROCESS_ENTER) self.password.Bind(wx.EVT_TEXT_ENTER, self.onLogin) p_sizer.Add(self.password, 0, wx.ALL, 5) main_sizer = wx.BoxSizer(wx.VERTICAL) main_sizer.Add(user_sizer, 0, wx.ALL, 5) main_sizer.Add(p_sizer, 0, wx.ALL, 5) btn = wx.Button(self, label="Login") btn.Bind(wx.EVT_BUTTON, self.onLogin) main_sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5) self.SetSizer(main_sizer) def onLogin(self, event): """ Check credentials and login """ stupid_password = "pa$$w0rd!" user_password = self.password.GetValue() if user_password == stupid_password: print("You are now logged in!") self.logged_in = True self.Close() else: print("Username or password is incorrect!") class MyPanel(wx.Panel): """""" def __init__(self, parent): """Constructor""" wx.Panel.__init__(self, parent) class MainFrame(wx.Frame): """""" def __init__(self): """Constructor""" wx.Frame.__init__(self, None, title="Main App") panel = MyPanel(self) # Ask user to login dlg = LoginDialog() dlg.ShowModal() authenticated = dlg.logged_in dlg.Destroy() if not authenticated: self.Close() self.Show() if __name__ == "__main__": app = wx.App(False) frame = MainFrame() app.MainLoop() |
Большая часть этого кода функционирует благодаря подклассу wx.Dialog, который мы называем LoginDialog. Вы заметите, что мы настроили виджет контроля текста пароля, так, чтобы он использовал стиль wx.TE_PASSWORD, который будет скрывать (превращать в жирные точки) все вводимые в строку пароля символы. Всё самое интересное происходит в хендлере событий. Здесь мы определяем шуточный пароль, который мы используем для сравнения с тем, который вводит пользователь.
В реальности вам скорее всего придётся взять хэш введённых паролей, которые вводятся, чтобы сравнивать их с теми, что уже есть в реальной базе данных зарегистрированных пользователей. Или же вы можете отправлять введённые пользователем данные на сервер аутентификации, чтобы там они сравнивались и делался вывод об их подлинности. С целью демонстрации мы выбираем более простой вариант и просто проверяем сам пароль. Вы заметите, что данные вводимые в строку «Имя пользователя» полностью игнорируются. Да, согласен, это не реалистично, но всё же это лишь пример.
В любом случае, если пользователь вводит правильный пароль, хендлер событий отправляет сообщение через пабсаб в наш объект MainFrame, приказывая ему завершить загрузку, а затем и уничтожить само диалоговое окно.
Используя переменную инстанции
Существуют и другие способы сообщить главному фрейму о продолжении загрузки, такие как использование флажков в классе диалога, которые пользователь сможет выбрать. Мы сталкивались с таким методом при завершении установки wxPython. Вот имплементация, которая демонстрирует этот метод (метод latter), используя переменную в качестве флажка:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
import wx from wx.lib.pubsub import pub class LoginDialog(wx.Dialog): """ Класс для определения диалога логина """ def __init__(self): """Constructor""" wx.Dialog.__init__(self, None, title="Login") # user info user_sizer = wx.BoxSizer(wx.HORIZONTAL) user_lbl = wx.StaticText(self, label="Username:") user_sizer.Add(user_lbl, 0, wx.ALL|wx.CENTER, 5) self.user = wx.TextCtrl(self) user_sizer.Add(self.user, 0, wx.ALL, 5) # pass info p_sizer = wx.BoxSizer(wx.HORIZONTAL) p_lbl = wx.StaticText(self, label="Password:") p_sizer.Add(p_lbl, 0, wx.ALL|wx.CENTER, 5) self.password = wx.TextCtrl(self, style=wx.TE_PASSWORD|wx.TE_PROCESS_ENTER) p_sizer.Add(self.password, 0, wx.ALL, 5) main_sizer = wx.BoxSizer(wx.VERTICAL) main_sizer.Add(user_sizer, 0, wx.ALL, 5) main_sizer.Add(p_sizer, 0, wx.ALL, 5) btn = wx.Button(self, label="Login") btn.Bind(wx.EVT_BUTTON, self.onLogin) main_sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5) self.SetSizer(main_sizer) def onLogin(self, event): """ Проверка введённых данных и непосредственно логин """ stupid_password = "pa$$w0rd!" user_password = self.password.GetValue() if user_password == stupid_password: print("You are now logged in!") pub.sendMessage("frameListener", message="show") self.Destroy() else: print("Username or password is incorrect!") class MyPanel(wx.Panel): """""" def __init__(self, parent): """Constructor""" wx.Panel.__init__(self, parent) class MainFrame(wx.Frame): """""" def __init__(self): """Constructor""" wx.Frame.__init__(self, None, title="Main App") panel = MyPanel(self) pub.subscribe(self.myListener, "frameListener") # Ask user to login dlg = LoginDialog() dlg.ShowModal() def myListener(self, message, arg2=None): """ Show the frame """ self.Show() if __name__ == "__main__": app = wx.App(False) frame = MainFrame() app.MainLoop() |
В данном примере мы добавили флаг в подкласс диалога, который мы назвали elf.logged_in. Если пользователь вводит правильный пароль, мы приказываем диалогу закрыться. Это заставляет wxPython вернуть контроль обратно к классу MainFrame, где мы проверяем переменную, чтобы понять залогинился пользователь или же нет. Если нет – приложение закроется. В обратном случае, оно начнёт загрузку.
Итоги
Есть несколько улучшений, которые мы могли бы добавить, например, настройка фокуса на строке «Имя пользователя» или же добавление кнопки «Отмена». Я уверен, что вы можете сделать это самостоятельно. В целом, эта статья должна была вас раззадорить и подтолкнуть к новым свершениям!
Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.
E-mail: vasile.buldumac@ati.utm.md
Образование
Universitatea Tehnică a Moldovei (utm.md)
- 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»