Статьи

wxPython: как создать диалог входа в систему

Я давно пользуюсь wxPython и вижу, что некоторые вопросы возникают довольно часто. Один из самых популярных — как запросить у пользователя свои учетные данные перед загрузкой остальной части приложения. Есть несколько подходов к этому, но я собираюсь сосредоточиться на простом решении, так как считаю, что это решение может быть использовано в качестве основы для более сложных решений.

По сути, мы хотим, чтобы пользователь увидел диалоговое окно входа в систему, где он должен ввести свое имя пользователя и пароль. Если они введут его правильно, программа продолжит загрузку и увидит основной интерфейс. Вы часто видите это на веб-сайтах, где часто используются клиенты веб-почты. Настольные приложения не включают эту функцию так часто, хотя вы увидите ее для приложения Stamps.com и для правоохранительных программ.

Давайте посмотрим на некоторый код:

import wx
 
if "2.8" in wx.version():
    import wx.lib.pubsub.setupkwargs
    from wx.lib.pubsub import pub
else:
    from wx.lib.pubsub import pub
 
 
########################################################################
class LoginDialog(wx.Dialog):
    """
    Class to define login 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):
        """
        Check credentials and login
        """
        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()

Большая часть этого кода занята подклассом wx.Dialog, который мы называем LoginDialog . Вы заметите, что мы установили виджет управления текстом пароля для использования wx.TE_PASSWORDстиль, который будет скрывать символы, которые пользователь вводит в этот элемент управления. Обработчик событий — это то, где происходит настоящее действие. Здесь мы определяем глупый пароль, который мы используем для сравнения с тем, который вводит пользователь. В реальном мире вы, вероятно, возьмете хеш введенного пароля и сравните его с тем, который хранится в базе данных. Или вы можете отправить учетные данные на ваш сервер аутентификации и попросить вас сообщить, являются ли учетные данные пользователя законными или нет. В демонстрационных целях мы выбираем простой подход и просто проверяем пароль. Вы заметите, что мы полностью игнорируем то, что пользователь вводит для имени пользователя. Это нереально, но опять же, это всего лишь пример.

В любом случае, если пользователь вводит правильный пароль, обработчик событий отправляет сообщение через pubsub нашему объекту MainFrame, сообщая ему о завершении загрузки, а затем диалоговое окно уничтожается. Есть и другие способы сообщить основному фрейму о продолжении, например, используя флаг в классе диалога, с которым мы можем проверить. Вот реализация, которая демонстрирует этот последний метод:

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
        if not authenticated:
            self.Close()
 
        self.Show()
 
if __name__ == "__main__":
    app = wx.App(False)
    frame = MainFrame()
    app.MainLoop()

В этом примере мы добавили флаг в подкласс диалога, который мы назвали self.logged_in . Если пользователь вводит правильный пароль, мы сообщаем, чтобы диалог закрылся. Это заставляет wxPython возвращать управление обратно классу MainFrame, где мы проверяем эту переменную, чтобы увидеть, вошел ли пользователь в систему или нет. Если это не так, мы закрываем приложение. В противном случае мы загружаем приложение.


Завершение

Мы можем добавить несколько улучшений, таких как установка фокуса на первый текстовый элемент управления или добавление кнопки отмены. Я уверен, что вы можете думать о нескольких других самостоятельно. В целом, это должно помочь вам начать.