Exemplo n.º 1
0
    def MakeToolBar(self):
        TBFLAGS = (wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT)
        tb = self.CreateToolBar(TBFLAGS)
        tsize = (24, 24)
        catagory_new_bmp = images.catagory_new.GetBitmap()
        goods_new_bmp = images.goods_new.GetBitmap()
        tb.SetToolBitmapSize(tsize)

        tb.AddTool(10, "新增类别", catagory_new_bmp, wx.NullBitmap, wx.ITEM_NORMAL,
                   "新增类别", "增加物品类别,用于物品归类,便于物品管理'", None)
        tb.AddTool(20, "新增物品", goods_new_bmp, wx.NullBitmap, wx.ITEM_NORMAL,
                   "新增物品", "添加新的物品", None)
        self.Bind(wx.EVT_TOOL, self.OnAddCatagory, id=10)
        self.Bind(wx.EVT_TOOL, self.OnAddGoods, id=20)

        tb.AddStretchableSpace()
        login_msg = '您好,{},欢迎使用系统! '.format(
            userservice.get_current_user().get('username'))
        login_info = wx.StaticText(tb, wx.ID_ANY, login_msg)
        tb.AddControl(login_info)
        tb.AddSeparator()

        bmp = StaticBitmap(tb, -1, images.setting.GetBitmap())
        tb.AddControl(bmp)
        modifypass_lb = StaticText(tb, -1, "修改密码")
        tb.AddControl(modifypass_lb)
        modifypass_lb.Bind(wx.EVT_MOUSE_EVENTS, self.OnModifyPassword)

        tb.Realize()
Exemplo n.º 2
0
class NameValue(icEvent):
    """
    Класс описывает строку панели свойств.
    """
    def __init__(self,
                 main,
                 indx,
                 name='',
                 value='',
                 type=icDefInf.EDT_TEXTFIELD,
                 dict={},
                 nameType=icNameTypeNormal,
                 height=oiLineHeight):
        """
        @type main: C{wx.Window}
        @param main: Указатель на окно сплиттера.
        @type indx: C{int}
        @param indx: Индекс свойства.
        @type type: C{int}
        @param type: Тип редактора. 
            EDT_TEXTFIELD = 0 - текстовое поле, 
            EDT_CHOICE = 1 - Choice, 
            EDT_CHECK_BOX = 2 - CheckBox,
            EDT_2CHECK_BOX = 3 - Разворачиваемый набор CheckBox (используется для комбинированных свойств). 
            EDT_EXTERNAL = 4 - Внешний редактор.
        @type dict: C{Dictionary}
        @param dict: Словарь дополнительных свойств.            
        @type nameType: C{int}
        @param nameType: Тип представления названия свойства:
            icNameTypeNormal - StaticText.
            icNameTypeCheckBox - CheckBox.
            icNameTypeReadonly - Нередактируемое свойство - StaticText выделенный жирным шрифтом.
        @type height: C{int}
        @param height: Высота строки.
        """
        icEvent.__init__(self)

        self.main = main
        self.name = name
        self.value = value
        self.oldValue = value
        self.height = height - IECWidthFudge
        self.isSelected = False
        self.edit_ctrl = None
        self.topLine = None
        self.bottomLine = None
        self.colorBox = None

        # Список ключей комбинированного  свойства (EDT_COMBINE)
        self.comboKeys = None

        # Список индексов свойств помеченных для удаления
        self.list_del_property = []

        self.type = type
        self.nameType = nameType
        self.dict = dict
        self.__editorEnable = main.isToggleEnable()
        bBuffName = False
        bBuffVal = False

        if nameType != icNameTypeCheckBox and type != icDefInf.EDT_COMBINE:
            bBuffName, self.name_ctrl = getStaticTextBuff(main.panel1,
                                                          icwidget.icNewId(),
                                                          '     ' + name,
                                                          pos=(0,
                                                               indx * height),
                                                          size=(1, height - 2))
            self.name_ctrl.SetBackgroundColour(wx.Colour(240, 240, 240))

            if nameType == icNameTypeReadonly:
                font = icFont({'style': 'bold'})
                self.name_ctrl.SetFont(font)
                self.name_ctrl.SetLabel('   ' + name)
            elif nameType == icNameTypeAddPropery:
                font = icFont({'style': 'bold'})
                self.name_ctrl.SetFont(font)
                self.name_ctrl.SetLabel('   ' + name)
                self.name_ctrl.SetBackgroundColour(wx.Colour(230, 230, 210))
        else:
            id = icwidget.icNewId()
            self.name_ctrl = wx.CheckBox(main.panel1,
                                         id,
                                         name,
                                         pos=(0, indx * height),
                                         size=(1, height))
            self.name_ctrl.SetValue(1)
            self.name_ctrl.Bind(wx.EVT_CHECKBOX, self.OnExpand, id=id)

            if type == icDefInf.EDT_FONT:
                self.comboKeys = icEdtFontKeys
            else:
                try:
                    self.comboKeys = value.keys()
                except:
                    print(name, value)

            font = icFont({'style': 'bold'})
            self.name_ctrl.SetFont(font)

        if type == icDefInf.EDT_COLOR:
            self.colorBox = wx.Window(main.panel2,
                                      -1, (3, indx * height), (14, height - 6),
                                      style=wx.SIMPLE_BORDER)

            if value is not None:
                self.colorBox.SetBackgroundColour(
                    wx.Colour(value[0], value[1], value[2]))

            self.value_ctrl = GenStaticText(main.panel2,
                                            icwidget.icNewId(),
                                            self.GetStr(),
                                            pos=(20, indx * height),
                                            size=(1, height))
        elif type == icDefInf.EDT_CHOICE:
            self.value_ctrl = wx.StaticText(main.panel2,
                                            icwidget.icNewId(),
                                            self.GetStr(),
                                            pos=(2, indx * height),
                                            size=(1, height),
                                            style=wx.ST_NO_AUTORESIZE)
        else:
            bBuffVal, self.value_ctrl = getStaticTextBuff(main.panel2,
                                                          icwidget.icNewId(),
                                                          self.GetStr(),
                                                          pos=(2,
                                                               indx * height),
                                                          size=(1, height))

        self.value_ctrl.SetForegroundColour(wx.Colour(20, 100, 180))

        self.line_name = wx.StaticLine(main.panel1,
                                       -1,
                                       style=wx.LI_HORIZONTAL,
                                       pos=(-2, (indx + 1) * height -
                                            IECWidthFudge),
                                       size=(10, 1))
        self.line_value = wx.StaticLine(main.panel2,
                                        -1,
                                        style=wx.LI_HORIZONTAL,
                                        pos=(-2, (indx + 1) * height -
                                             IECWidthFudge),
                                        size=(200, 1))

        if not bBuffName:
            self.name_ctrl.Bind(wx.EVT_LEFT_DOWN, main.OnSelect)

        if not bBuffVal:
            self.value_ctrl.Bind(wx.EVT_LEFT_DOWN, main.OnSelect)

    def SetEnableEditor(self, bEnable):
        """
        Разрешает или запрещает редактирование свойства.
        
        @type bEnable: C{bool}
        @param bEnable: Признак разрешения редактирования. Если bEditor == True, редактирование разрешено 
            в противном случае запрещено.
        """
        self.__editorEnable = bEnable

    def IsEnableEditor(self):
        """
        Возвращает значение признака редактирования.
        
        @rtype: C{bool}
        @return: Возвращает значение признака редактирования. Если True, редактирование разрешено 
            в противном случае запрещено.
        """
        return self.__editorEnable

    def OnExpand(self, evt):
        """
        """
        if self.edit_ctrl is not None:
            self.edit_ctrl.OnExpand(evt)
            self.main.RefreshPos()
            self.main.refreshSplitter()

    def GetExpandValue(self):
        """
        Определяет значение словаря у раскрытого списка.
        """
        ret = self.value

        try:
            if not self.name_ctrl.IsChecked():
                ret = {}
                indx = self.GetIndx() + 1

                for key in self.comboKeys:
                    val = self.main.NameValues[indx].value

                    if isinstance(self.oldValue[key], int):
                        ret[key] = int(self.main.NameValues[indx].value)
                    else:
                        ret[key] = self.main.NameValues[indx].value

                    indx += 1
        except:
            ret = self.value

        return ret

    def GetStr(self):
        """
        Возвращает строковое представление значение свойства.
        """
        if self.type == icDefInf.EDT_CHECK_BOX:
            if int(self.value):
                ret = 'True'
            else:
                ret = 'False'
        elif self.type == icDefInf.EDT_COMBINE:
            ret = ''
            for key in self.value.keys():
                if self.value[key]:
                    ret = ret + key + ' | '
            ret = ret[:-3]
        elif self.type == icDefInf.EDT_COLOR:
            if self.value is not None:
                ret = 'wx.Colour' + str(self.value)
            else:
                ret = 'None'

        elif self.type == icDefInf.EDT_POINT:
            ret = 'wx.Point' + str(self.value)

        elif self.type == icDefInf.EDT_SIZE:
            ret = 'wx.Size' + str(self.value)

        elif self.type in [icDefInf.EDT_PY_SCRIPT, icDefInf.EDT_ADD_PROPERTY] and \
             type(self.value) in (str, unicode) and ('\r\n' in self.value or '\n' in self.value):
            val = self.value.replace('\r\n', '\n')
            nf = val.find('\n')
            ret = '<Script> ' + val[:nf] + ' ...'
        elif self.type == icDefInf.EDT_NEW_PROPERTY:
            ret = '<...>'
        else:
            ret = str(self.value)

        return ret

    def CreateEditor(self, indx):
        """
        """
        height = self.height + IECWidthFudge
        prnt = self

        if self.type == icDefInf.EDT_TEXTFIELD:
            self.edit_ctrl = icEditPropText(
                prnt,
                pos=(-2, indx * height - 1),
                size=(self.main.panel2.GetSize()[0] + 4, self.height + 2))

        elif self.type == icDefInf.EDT_PY_SCRIPT:
            self.edit_ctrl = icEditPropPyScript(
                prnt,
                pos=(-2, indx * height - 1),
                size=(self.main.panel2.GetSize()[0] + 4, self.height + 2))

            if type(self.value) in (str, unicode) and ('\r\n' in self.value
                                                       or '\n' in self.value):
                self.edit_ctrl.OnEditScript(None)

        elif self.type == icDefInf.EDT_NUMBER:
            self.edit_ctrl = icEditPropNumber(
                prnt,
                pos=(-2, indx * height - 1),
                size=(self.main.panel2.GetSize()[0] + 4, self.height + 2))

        elif self.type == icDefInf.EDT_TEXTLIST:
            self.edit_ctrl = icEditPropTextList(
                prnt,
                pos=(-2, indx * height - 1),
                size=(self.main.panel2.GetSize()[0] + 4, self.height + 2))

        elif self.type == icDefInf.EDT_TEXTDICT:
            self.edit_ctrl = icEditPropTextDict(
                prnt,
                pos=(-2, indx * height - 1),
                size=(self.main.panel2.GetSize()[0] + 4, self.height + 2))

        elif self.type == icDefInf.EDT_DICT:
            self.edit_ctrl = icEditPropDict(
                prnt,
                pos=(-2, indx * height - 1),
                size=(self.main.panel2.GetSize()[0] + 4, self.height + 2))

        elif self.type == icDefInf.EDT_IMPORT_NAMES:
            self.edit_ctrl = icEditImportNames(
                prnt,
                pos=(-2, indx * height - 1),
                size=(self.main.panel2.GetSize()[0] + 4, self.height + 2))

        elif self.type == icDefInf.EDT_COMBINE:
            self.edit_ctrl = icEditPropCombine(
                prnt,
                pos=(-2, indx * height - 1),
                size=(self.main.panel2.GetSize()[0] + 4, self.height + 2))

        elif self.type == icDefInf.EDT_CHOICE:
            self.edit_ctrl = icEditPropChoice(
                prnt, (-2, indx * height - 1),
                (self.main.panel2.GetSize()[0] + 4, self.height + 2))

        elif self.type == icDefInf.EDT_CHECK_BOX:
            self.edit_ctrl = icEditPropCheckBox(
                prnt,
                pos=(2, indx * height - 1),
                size=(self.main.panel2.GetSize()[0] - 2, self.height + 2),
                style=wx.WANTS_CHARS | wx.TAB_TRAVERSAL)

        elif self.type == icDefInf.EDT_EXTERNAL:
            self.edit_ctrl = icEditPropTButton(
                prnt,
                pos=(-2, indx * height - 1),
                size=(self.main.panel2.GetSize()[0] + 4, self.height + 2))

        elif self.type == icDefInf.EDT_COLOR:
            self.edit_ctrl = icEditColor(prnt,
                                         pos=(-2, indx * height - 1),
                                         size=(self.main.panel2.GetSize()[0] +
                                               4, self.height + 2))

        elif self.type == icDefInf.EDT_FONT:
            self.edit_ctrl = icEditFont(prnt,
                                        pos=(-2, indx * height - 1),
                                        size=(self.main.panel2.GetSize()[0] +
                                              4, self.height + 2))

        elif self.type == icDefInf.EDT_POINT:
            self.edit_ctrl = icEditPropPoint(
                prnt,
                pos=(-2, indx * height - 1),
                size=(self.main.panel2.GetSize()[0] + 4, self.height + 2))

        elif self.type == icDefInf.EDT_SIZE:
            self.edit_ctrl = icEditPropSize(
                prnt,
                pos=(-2, indx * height - 1),
                size=(self.main.panel2.GetSize()[0] + 4, self.height + 2))

        elif self.type == icDefInf.EDT_NEW_PROPERTY:
            self.edit_ctrl = icEditNewProperty(
                prnt,
                pos=(-2, indx * height - 1),
                size=(self.main.panel2.GetSize()[0] + 4, self.height + 2))

        elif self.type == icDefInf.EDT_ADD_PROPERTY:
            self.edit_ctrl = icEditAddProperty(
                prnt,
                pos=(-2, indx * height - 1),
                size=(self.main.panel2.GetSize()[0] + 4, self.height + 2))

            if type(self.value) in (str, unicode) and ('\r\n' in self.value
                                                       or '\n' in self.value):
                self.edit_ctrl.OnEditScript(None)

        # Устанавливаем для редактора его высоту
        if self.edit_ctrl and self.edit_ctrl.editorCtrl:
            self.edit_ctrl.height_edt = height

            y0 = indx * height - IECWidthFudge + 2

            if y0 < 0:
                y0 = 0

            if not self.IsEnableEditor():
                self.edit_ctrl.editorCtrl.Enable(False)

            w = self.main.panel1.GetSize()[0] + 4

            self.topLine = wx.Window(self.main.panel1,
                                     -1,
                                     style=wx.LI_HORIZONTAL | wx.SIMPLE_BORDER,
                                     pos=(-2, y0),
                                     size=(w, 1))
            self.bottomLine = wx.Window(self.main.panel1,
                                        -1,
                                        style=wx.LI_HORIZONTAL,
                                        pos=(-2, (indx + 1) * height -
                                             IECWidthFudge),
                                        size=(w, 1))

            self.topLine.SetBackgroundColour(wx.Colour(0, 0, 0))
            self.bottomLine.SetBackgroundColour(wx.Colour(255, 255, 255))
            self.edit_ctrl.SetFocus()
            self.main.cursor = indx

            try:
                self.edit_ctrl.Bind(wx.EVT_KEY_DOWN, self.OnEditorKeyDown)
            except:
                self.edit_ctrl.editorCtrl.Bind(wx.EVT_KEY_DOWN,
                                               self.OnEditorKeyDown)

    def GetIndx(self):
        """
        Возвращает индекс строки
        """
        indx = 0

        for obj in self.main.NameValues:
            if obj == self:
                return indx
            indx += 1

        return -1

    def OnEditorKeyDown(self, evt):
        """
        """
        indx = self.GetIndx()
        wOffset, hOffset = self.main.GetViewStart()

        if evt.GetKeyCode() == wx.WXK_UP:
            if indx > 0:
                indx -= 1
                self.main.SelectEdt(indx)

            if self.line_name.GetPosition()[1] < (hOffset + 1) * oiLineHeight:
                self.main.Scroll(0, hOffset - 1)

        elif evt.GetKeyCode() == wx.WXK_DOWN or evt.GetKeyCode(
        ) == wx.WXK_RETURN:

            if indx < len(self.main.NameValues) - 1:
                indx += 1
                self.main.SelectEdt(indx)

            sy = self.main.GetClientSize().y / oiLineHeight
            sy += hOffset

            if self.line_name.GetPosition()[1] > sy * oiLineHeight:
                self.main.Scroll(
                    0,
                    self.line_name.GetPosition()[1] / oiLineHeight + 1)

        elif evt.GetKeyCode() == wx.WXK_HOME and evt.ControlDown():
            self.main.SelectEdt(0)
            self.main.Scroll(0, 0)

        elif evt.GetKeyCode() == wx.WXK_END and evt.ControlDown():
            indx = len(self.main.NameValues) - 1
            self.main.SelectEdt(indx)
            self.main.Scroll(0, indx)
        else:
            evt.Skip()
Exemplo n.º 3
0
class MainFrame(wx.Frame):
    """
    程序的主窗口,运行程序后程序展示的画面;
    """
    def __init__(self, *args, **kwargs):
        # ensure the parent's __init__ is called.
        super(self.__class__, self).__init__(*args, **kwargs)
        # 启动端口监听,将收到的卡片保存在用户表单中,若是收到的是用户的信息则发给对应的聊天窗口;
        # 当程序启动时,使用UDP协议向255.255.255.255这个广播地址发送广播包,默认端口是44444。
        self.usr_sheet = UserSheet()
        self.ip = self.usr_sheet.get_ip()
        self.message_list = []
        self.pop_chat_window_list = []
        Listener(self).start()
        # Set the window's size
        self.SetMaxSize((MAIN_WIN_WIDTH, MAIN_WIN_HIGH))
        self.SetMinSize((MAIN_WIN_WIDTH, MAIN_WIN_HIGH))
        # set Icon
        self.icon_img_path = os.path.abspath("./images/Icon_v0.1.png")
        self.icon = wx.Icon(self.icon_img_path, type=wx.BITMAP_TYPE_ANY)
        self.SetIcon(self.icon)
        # create a panel in the frame
        self.windowpanel = wx.Panel(self)

        # 添加头像 50* 50
        # 载入图像
        profile_photo = wx.Image("./images/profile_photo_v0.1.png",
                                 wx.BITMAP_TYPE_ANY)
        # 缩放图像
        # 转换它们为静态位图部件
        self.sbm_profile = wx.StaticBitmap(self.windowpanel, -1,
                                           wx.BitmapFromImage(profile_photo))
        self.sbm_profile.Bind(wx.EVT_LEFT_DCLICK, self.OnChangeprofilegraph)
        # put them into the sizer

        # 添加状态图标和文字
        list_status = ['在线', '忙', '离线']
        self.combo_box_1 = wx.ComboBox(self.windowpanel,
                                       -1,
                                       value='在线',
                                       choices=list_status,
                                       style=wx.CB_SORT)

        # 添加事件处理;
        self.Bind(wx.EVT_COMBOBOX, self.OnConbobox, self.combo_box_1)

        # 添加计算机名称
        self.host_name = HOST_NAME
        # 使用 wx.lib.stattext.GenStaticText
        # self.hname = wx.StaticText(self.windowpanel, label=self.host_name)
        self.hname = GenStaticText(self.windowpanel, -1, label=self.host_name)
        self.hname.Bind(wx.EVT_LEFT_DCLICK, self.OnChangehostname)

        # 添加个性签名
        profile_sign = '编辑个性签名'
        # self.psign = wx.StaticText(self.windowpanel, label=profile_sign)
        # wx.StaticText 是c++写的原生控件,不支持鼠标事件,而wx.lib.stattext.GenStaticText
        # 是使用python重写的一个静态文本控件,支持鼠标事件。
        self.psign = GenStaticText(self.windowpanel, -1, label=profile_sign)
        # 下面代码没有效果。 鼠标的事件应该绑定到具体的组件上而不是框架上。
        # self.Bind(wx.EVT_LEFT_DCLICK, self.OnChangehostname, self.hname)
        self.psign.Bind(wx.EVT_LEFT_DCLICK, self.OnChangepsign)

        # 添加搜索栏
        self.search_bar = wx.TextCtrl(self.windowpanel, -1, "Search friends!")
        # 当输入用户名后,回车返回搜索到的好友。

        # 添加用户列表notebook。
        # 使用notebook控件来达到用户列表,组列表的多标签窗口;
        # 如何使用notebook控件: 如下,定义不同的面板类,添加到多标签窗口中.
        self.note_book = wx.Notebook(self.windowpanel)
        self.note_book.AddPage(UsrsPanel(self.note_book, self), "用户列表")
        self.note_book.AddPage(GroupPanel(self.note_book), "用户组列表")
        self.note_book.AddPage(UsrSheetShow(self.usr_sheet, self.note_book),
                               "用户组列表2")

        # 测试函数用按钮
        self.testhostname = wx.Button(self.windowpanel, -1, "testhostname")
        self.Bind(wx.EVT_BUTTON, self.OnChangehostname, self.testhostname)

        # layout
        # 主要布局
        mainbox = wx.BoxSizer(wx.VERTICAL)
        # 个人信息状态布局
        headsizer = wx.GridBagSizer(hgap=10, vgap=10)
        headsizer.Add(self.sbm_profile,
                      pos=(0, 0),
                      span=(2, 1),
                      flag=wx.EXPAND)
        headsizer.Add(self.combo_box_1, pos=(0, 1))
        headsizer.Add(self.hname, pos=(0, 2))
        headsizer.Add(self.psign, pos=(1, 1), span=(1, 2))
        headsizer.Add(self.search_bar, pos=(2, 0), span=(1, 3), flag=wx.EXPAND)
        # 使最后的行和列可增长。
        headsizer.AddGrowableCol(2)
        headsizer.AddGrowableRow(2)
        mainbox.Add(headsizer,
                    proportion=0,
                    flag=wx.EXPAND | wx.ALL,
                    border=10)

        # 用户列表布局
        # usrs_sizer = wx.BoxSizer()
        # usrs_sizer.Add(self.note_book)
        # mainbox.Add(usrs_sizer, flag=wx.EXPAND | wx.ALL, border=10)
        # 使用上面三行代码会导致notebook控件不能向两边自动扩充,而是根据内容实际的尺寸。
        mainbox.Add(self.note_book,
                    proportion=1,
                    flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
                    border=10)

        # 用于测试按钮的布局
        testsizer = wx.BoxSizer()
        testsizer.Add(self.testhostname)
        mainbox.Add(testsizer)

        self.windowpanel.SetSizer(mainbox)
        self.windowpanel.Fit()

    def OnChangeprofilegraph(self, event):
        """
        双击头像控件时,弹出图片文件选择对话框,更改图片。
        :param event:
        :return: None
        """
        print("ok")
        return None

    def OnConbobox(self, event):
        """
        当更改状态时触发。
        :param event:
        :return:
        """
        print('hello')

    def OnChangehostname(self, event):
        """
        当双击主机名称时触发,用来更改主机的名称。
        :param event:
        :return: None
        """
        text_entry_dialog = wx.TextEntryDialog(None, "请输入主机名称:", "编辑主机名称",
                                               "主机名称")
        if text_entry_dialog.ShowModal() == wx.ID_OK:
            host_name = text_entry_dialog.GetValue()
            if host_name == "":
                host_name = HOST_NAME
        else:
            host_name = HOST_NAME
        self.hname.SetLabel(host_name)
        return None

    def OnChangepsign(self, event):
        """
        当双击个性签名时触发,用来更改个性签名。
        :param event:
        :return: None
        """
        texentrydialog = wx.TextEntryDialog(None, "请输入个性签名:", "编辑个性签名", "个性签名")
        if texentrydialog.ShowModal() == wx.ID_OK:
            psing = texentrydialog.GetValue()
            if psing == "":
                psing = HOST_NAME
        else:
            psing = HOST_NAME
        self.psign.SetLabel(psing)
        return None

    def pop_chat_window(self, event):
        """
        聊天时调用次方法弹出聊天窗口;
        :return: None
        """
        pass
Exemplo n.º 4
0
class UsrsPanel(wx.Panel):
    """
    创建用户列表的panel;
    显示的用户列表需要实时刷新;(没有实现):思路使用wx.Timer类,定期事件。
    问题1:在wxpython中如何实时刷新一个面板上控件;
        想法1. 基础的,看看文档里有关wx.DC类的说明,稍微高级的试试wxpython里带的floatcanvas子模块。
        使用定时器和设备上下文实现该功能,类似代码为: 一个简单的数字时钟.py。
        方法一:直接用控件和布局来实现。用户列表示例
            失败: 当接收到新用户时无法接受,在屏幕上实时显示。
        方法二:使用wxpython计时器和设备上下文来动态刷新; 用户组列表1
            暂时还没有实现,复杂度高;且如何响应鼠标事件呢?
        方法三:列表控件;用户组列表
        方法四:使用定时器检查用户表单列表中的是否添加了新的用户,如果有一个新用户则添加一个新用户卡片。
            已实现 @@@@@@@@@@@@@@
    问题2:如何设定notebook标签下panal的大小;
        答案同问题5

    问题3:如何点击一片区域(用户显示区域)来弹出用户聊天对话框;
    问题4:用户信息和聊天信息如何正确传递到聊天对话框中;
    问题5:使用Sizer布局是如何,设置个控件个控件之间占据的距离;
        使用Sizer.Add()中的 proportion 比例选项来设置。
    """
    def __init__(self, parent, main_frame):
        super(self.__class__, self).__init__(parent)
        # text = wx.TextCtrl(self, style=wx.TE_MULTILINE, size=(250, 150))
        # self.SetSizer((280, 300))
        self.usr_sheet = main_frame.usr_sheet
        self.main_frame = main_frame
        self.ip_list = []
        # UsrSheetShow(self.usr_sheet, self)
        self.show_usr_sheet()
        # 设定定时器(不起作用)
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.Add_usr_card, self.timer)
        self.timer.Start(1000)

    def usr_card(self, usr_card):
        ip = usr_card.ip()
        # print("ok")
        head_sizer = wx.GridBagSizer(hgap=5, vgap=5)
        usr_photo = wx.Image("./images/profile_photo_v0.1.png",
                             wx.BITMAP_TYPE_ANY)
        self.sbm_profile = wx.StaticBitmap(self,
                                           -1,
                                           wx.BitmapFromImage(usr_photo),
                                           name=ip)
        self.sbm_profile.Bind(wx.EVT_LEFT_DCLICK, self.pop_chat_window)
        usr_name = usr_card.usr_name()
        self.ip_list.append(ip)
        # usr_name = usr_card.split("#")[2]
        host_name = usr_card.host_name()
        # host_name = usr_card.split("#")[3]
        print(usr_name)
        self.usr_text = GenStaticText(self, -1, label="用户名:", name=ip)
        self.usr_text.Bind(wx.EVT_LEFT_DCLICK, self.pop_chat_window)
        self.host_text = GenStaticText(self, -1, label="IP地址:", name=ip)
        self.host_text.Bind(wx.EVT_LEFT_DCLICK, self.pop_chat_window)
        self.ip = GenStaticText(self, -1, label=ip, name=ip)
        self.ip.Bind(wx.EVT_LEFT_DCLICK, self.pop_chat_window)
        self.usr_name = GenStaticText(self, -1, label=usr_name, name=ip)
        self.usr_name.Bind(wx.EVT_LEFT_DCLICK, self.pop_chat_window)
        # 个人信息状态布局
        head_sizer.Add(self.sbm_profile,
                       pos=(0, 0),
                       span=(2, 1),
                       flag=wx.EXPAND)
        head_sizer.Add(self.usr_text,
                       pos=(0, 1),
                       flag=wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL)
        head_sizer.Add(self.host_text,
                       pos=(1, 1),
                       flag=wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL)
        head_sizer.Add(self.usr_name,
                       pos=(0, 2),
                       flag=wx.EXPAND | wx.ALIGN_CENTER)
        head_sizer.Add(self.ip,
                       pos=(1, 2),
                       flag=wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL)

        head_sizer.AddGrowableCol(2)
        # head_sizer.AddGrowableRow(1)
        self.main_box.Add(head_sizer, flag=wx.EXPAND | wx.ALL, border=5)

        self.SetSizerAndFit(self.main_box)

    def show_usr_sheet(self):
        """
        启动显示用户列表;
        :return:
        """
        self.main_box = wx.BoxSizer(wx.VERTICAL)
        for usr_card in self.usr_sheet.usersheet:
            self.usr_card(usr_card)
            self.SetSizerAndFit(self.main_box)

    def Add_usr_card(self, event):
        # print("il")
        for usr_card in self.usr_sheet.usersheet:
            if usr_card.ip() not in self.ip_list:
                self.usr_card(usr_card)

    def pop_chat_window(self, event):
        print(event.GetId())
        my_ip = self.usr_sheet.get_ip()
        friend_ip = wx.FindWindowById(event.GetId(), self).GetName()
        print(friend_ip)
        # friend_ip = "123"
        print(f"get label:{friend_ip}")
        print("pop window")
        chat_frame = ChatFrame(my_ip, friend_ip, None, title="chat_frame")
        self.main_frame.pop_chat_window_list.append(chat_frame)
        chat_frame.Show()