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()
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()
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
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()