wxformbuilder中使用Wxpython自定义控件的使用示例

Page content

  wxformbuilder中使用Wxpython自定义控件的使用示例。

1、自定义控件的说明

YearMonthPicker 控件: 该控件是一个 wx.Panel,里面包含两个 wx.ComboBox 控件:一个选择年份,一个选择月份。 self.year_combo 用于选择年份,self.month_combo 用于选择月份。 self.text_ctrl 是一个 wx.TextCtrl 控件,用于显示格式化后的年月 (%Y-%m)。

运行效果:

Wxpython_Custom_Conctol4.png

2、如何操作

首先插入一个自定义控件。

Wxpython_Custom_Conctol1.png

控件Tree效果:

Wxpython_Custom_Conctol2.png

然后,在属性面板中,设置控件的属性。

Wxpython_Custom_Conctol3.png

注意:

1、控件的name:设置为m_datePicker_end。

2、控件的class:设置为YearMonthPicker。

3、控件位于名叫m_panel2的panel下。

4、控件的construction:设置为`self.m_datePicker_end = YearMonthPicker(self.m_panel2, min_year=2021, min_month=2)`,这里self.m_datePicker_end对应控件的name,self.m_panel2对应控件的class。这个的作用是:当你使用wxformbuilder生成布局的代码时,`self.m_datePicker_end = YearMonthPicker(self.m_panel2, min_year=2021, min_month=2)`会自动插入到代码的控件定义部分。

5、控件的include:设置为`from YearMonthPicker import YearMonthPicker`,也就是说控件的代码为`YearMonthPicker.py`文件中的类`YearMonthPicker`。这个的作用是:当你使用wxformbuilder生成布局的代码时,`from YearMonthPicker import YearMonthPicker`会自动插入到代码的开头。

这样,你就可以使用自定义控件了。

YearMonthPicker.py控件代码如下:

import wx
import wx.adv

class YearMonthPicker(wx.Panel):
    def __init__(self, parent, min_year=2021, min_month=2, id=wx.ID_ANY, *args, **kwargs):
        """
            初始化YearMonthPicker控件。

            :param parent: 父窗口
            :param min_year: 最小可选年份,默认为2021
            :param min_month: 最小可选月份,默认为2
            :param id: 控件ID
            :param args: 额外的位置参数
            :param kwargs: 额外的关键字参数
        """
        super(YearMonthPicker, self).__init__(parent, id, *args, **kwargs)

        # 获取当前年份和月份
        now = wx.DateTime.Now()
        self.current_year = now.GetYear()
        self.current_month = now.GetMonth() + 1  # wx.DateTime 的 GetMonth() 返回 0-11,所以需要 +1

        # 记录最小可选年月
        self.min_year = min_year
        self.min_month = min_month

        # 创建年份选择控件(仅允许选择 min_year ~ current_year)
        self.year_combo = wx.ComboBox(self, size=(100, 25), style=wx.CB_READONLY)
        self.year_combo.AppendItems([str(year) for year in range(self.min_year, self.current_year + 1)])
        self.year_combo.SetValue(str(self.current_year))  # 默认当前年份

        # 创建月份选择控件(稍后根据年份动态更新可选范围)
        self.month_combo = wx.ComboBox(self, size=(80, 25), style=wx.CB_READONLY)
        self.update_month_choices(self.current_year, self.current_month)
        self.month_combo.SetValue(f"{self.current_month:02d}")  # 默认当前月份

        # 创建一个文本控件来显示选中的年月
        self.text_ctrl = wx.TextCtrl(self, style=wx.TE_READONLY, size=(100, 25))

        # 布局管理
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(self.year_combo, 0, wx.ALL, 5)
        sizer.Add(self.month_combo, 0, wx.ALL, 5)
        sizer.Add(self.text_ctrl, 0, wx.ALL, 5)

        self.SetSizer(sizer)
        self.SetSizerAndFit(sizer)
        self.Layout()

        # 绑定事件处理
        self.year_combo.Bind(wx.EVT_COMBOBOX, self.on_year_changed)
        self.month_combo.Bind(wx.EVT_COMBOBOX, self.on_date_changed)

        # 初始化显示
        self.update_display()

    def on_year_changed(self, event):
        """当年份改变时,更新可选的月份范围"""
        selected_year = int(self.year_combo.GetValue())

        # 获取当前年月
        now = wx.DateTime.Now()
        current_year = now.GetYear()
        current_month = now.GetMonth() + 1

        # 更新月份选择框的选项
        self.update_month_choices(selected_year, current_month)
        
        # 触发一次日期更新
        self.update_display()

    def on_date_changed(self, event):
        """当月份改变时,更新文本框显示"""
        self.update_display()

    def update_month_choices(self, selected_year, current_month):
        """根据所选年份更新月份选择框"""
        self.month_combo.Clear()

        if selected_year == self.min_year:
            start_month = self.min_month  # 最小年份时,从最小月份开始
        else:
            start_month = 1  # 其他年份,从1月开始

        if selected_year == self.current_year:
            end_month = current_month  # 最大年份时,最大可选月份为当前月份
        else:
            end_month = 12  # 其他年份,可选到12月

        # 添加可选的月份
        self.month_combo.AppendItems([f"{i:02d}" for i in range(start_month, end_month + 1)])

        # 确保月份选择框的值合法
        current_selected_month = int(self.month_combo.GetValue()) if self.month_combo.GetValue() else start_month
        if current_selected_month < start_month or current_selected_month > end_month:
            self.month_combo.SetValue(f"{start_month:02d}")  # 重置为可选范围的第一个月份
        else:
            self.month_combo.SetValue(f"{current_selected_month:02d}")  # 保持原选择值

    def update_display(self):
        """更新文本框显示选中的年月"""
        selected_year = self.year_combo.GetValue()
        selected_month = self.month_combo.GetValue()
        formatted_date = f"{selected_year}-{selected_month}"
        self.text_ctrl.SetValue(formatted_date)

    def GetValue(self):
        """获取当前选中的年月"""
        return self.text_ctrl.GetValue()

# 示例用法
class MyFrame(wx.Frame):
    def __init__(self, *args, **kw):
        super(MyFrame, self).__init__(*args, **kw)

        panel = wx.Panel(self)
        sizer = wx.BoxSizer(wx.VERTICAL)

        # 创建自定义的年-月选择控件,最小可选时间为2021年2月
        self.year_month_picker = YearMonthPicker(panel, min_year=2021, min_month=2)

        # 将控件添加到布局中
        sizer.Add(self.year_month_picker, 0, wx.ALL, 10)

        panel.SetSizer(sizer)

        self.SetSize((350, 150))
        self.SetTitle('自定义 年-月 选择器')
        self.Centre()


class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame(None)
        frame.Show()
        return True

if __name__ == "__main__":
    
    app = MyApp(False)
    app.MainLoop()