wxptyhon中DataViewCtrl和PyDataViewModel的使用示例

  wxptyhon的文档很简单,关于DataViewCtrl和PyDataViewModel的使用示例没找到,所以这里记录一下。

wxptyhon中DataViewCtrl和PyDataViewModel的使用示例:


import wx
from loguru import logger
import wx.dataview as dv

class MergeDataViewModel(dv.PyDataViewModel):
    """
    用于管理和展示合并PDF文件的数据模型类。
    继承自wx.dataview.PyDataViewModel。
    """

    def __init__(self):
        """
        初始化MergeDataViewModel对象。
        创建一个空的数据列表。
        
        items = dv.DataViewItemArray()
        是一个专门设计用来存储和管理 DataViewItem 对象的容器,它通常用于批量操作或通知多个项目的变化。
        它的主要目的是为了提高性能,因为 DataViewItem 是一个相对昂贵的对象,在每次添加或删除项目时都要创建和销毁。
        通过使用 DataViewItemArray,您可以一次性创建多个 DataViewItem,然后将它们添加到 DataView 中,
        这可以减少创建和销毁对象的开销。
        
        在 DataView 中,DataViewItemArray 通常用于以下情况:
        批量添加项目:当您需要一次性添加多个项目时,使用 DataViewItemArray 可以提高性能。
        批量删除项目:当您需要一次性删除多个项目时,同样可以使用 DataViewItemArray 来提高性能。
        
        DataViewItem 是 wxPython 中用于在 DataView 控件中唯一标识一个项目的对象
        在 PyDataViewModel 中:
        bjectToItem 方法通常将 Python 对象包装成 DataViewItem,它可能简单地将行索引(一个整数)转换为 DataViewItem。
        ItemToObject 方法(在 GetRow 中使用)是 ObjectToItem 的反向操作,它将 DataViewItem 转换回 Python 对象(这里是行索引)。
        """
        dv.PyDataViewModel.__init__(self)
        self.data = []


    def GetColumnCount(self):
        """
        返回数据模型的列数。

        Returns:
            int: 列数,固定为5。
        """
        return 5

    def GetColumnType(self, col):
        """
        返回指定列的数据类型。

        Args:
            col (int): 列索引。

        Returns:
            str: 列的数据类型,所有列均为"string"。
        """
        return "string"

    def GetValue(self, item, col):
        """
        获取指定项和列的值。

        Args:
            item: DataViewItem对象,表示要获取值的行。
            col (int): 列索引。

        Returns:
            str: 指定单元格的值,如果索引无效则返回空字符串。
        """
        if item:
            row = self.GetRow(item)
            # 检查 row 和 col 是否在有效范围内
            if 0 <= row < len(self.data) and 0 <= col < len(self.data[row]):
                return str(self.data[row][col])
        return ""

    def SetValue(self, value, item, col):
        """
        设置指定项和列的值。

        Args:
            value: 要设置的新值。
            item: DataViewItem对象,表示要设置值的行。
            col (int): 列索引。

        Returns:
            bool: 如果设置成功返回True,否则返回False。
        """
        if item:
            row = self.GetRow(item)
            # 检查 row 和 col 是否在有效范围内
            if 0 <= row < len(self.data) and 0 <= col < len(self.data[row]):
                self.data[row][col] = value
                return True
        return False

    def GetAttr(self, item, col, attr):
        """
        获取指定项和列的属性。
        此方法可用于设置单元格的自定义样式。

        Args:
            item: DataViewItem对象。
            col (int): 列索引。
            attr: 属性对象。

        Returns:
            bool: 始终返回False,表示不使用自定义属性。
        """
        return False

    def GetChildren(self, parent, children):
        """
        获取指定父项的所有子项。

        Args:
            parent: 父DataViewItem对象。
            children: DataViewItemArray对象,用于存储子项。

        Returns:
            int: 子项数量。
        """
        if not parent:
            for i in range(len(self.data)):
                children.append(self.ObjectToItem(i))
            return len(self.data)
        return 0

    def IsContainer(self, item):
        """
        判断指定项是否为容器(即是否可以包含子项)。

        Args:
            item: DataViewItem对象。

        Returns:
            bool: 如果是根项(即item为空)返回True,否则返回False。
        """
        return not item

    def GetParent(self, item):
        """
        获取指定项的父项。

        Args:
            item: DataViewItem对象。

        Returns:
            DataViewItem: 始终返回NullDataViewItem,因为这是一个平面结构。
        """
        return dv.NullDataViewItem

    def AddRow(self, row_data):
        """
        添加新行到数据模型。

        Args:
            row_data (list): 要添加的行数据。
        """
        index = len(self.data)
        self.data.append(row_data)
        
        # 通知视图有新行添加
        items = dv.DataViewItemArray()
        items.append(self.ObjectToItem(index))
        self.ItemsAdded(dv.NullDataViewItem, items)
        


    def DeleteRow(self, row):
        """
        从数据模型中删除指定行。

        Args:
            row (int): 要删除的行索引。
        """
        if 0 <= row < len(self.data):
            del self.data[row]
            # 通知视图有行被删除
            items = dv.DataViewItemArray()
            items.append(self.ObjectToItem(row))
            self.ItemsDeleted(dv.NullDataViewItem, items)

    def GetRow(self, item):
        """
        根据 DataViewItem 获取对应的行索引。

        Args:
            item: DataViewItem对象。

        Returns:
            int: 对应的行索引。
        """
        return self.ItemToObject(item)


# 示例用法
class MainFrame(wx.Frame):
    def __init__(self, parent=None, id=wx.ID_ANY, title="DataView Example"):
        wx.Frame.__init__(self, parent, id, title, size=(800, 600))

        # 创建 DataViewCtrl
        self.dvc = dv.DataViewCtrl(self, style=wx.BORDER_THEME | dv.DV_ROW_LINES | dv.DV_VERT_RULES)

        # 创建数据模型
        self.model = MergeDataViewModel()
        self.dvc.AssociateModel(self.model)

        # 添加列
        self.dvc.AppendTextColumn("id", 0, width=100)
        self.dvc.AppendTextColumn("name", 1, width=150)
        self.dvc.AppendTextColumn("page_nums", 2, width=100)
        self.dvc.AppendTextColumn("file_size", 3, width=100)
        self.dvc.AppendTextColumn("merge_method", 4, width=150)

        # 添加一些示例数据
        self.model.AddRow([1, "file1.pdf", 10, "10MB", "Sequential"])
        self.model.AddRow([2, "file2.pdf", 20, "20MB", "Parallel"])

        # 创建按钮
        self.add_button = wx.Button(self, label="Add Row")
        self.delete_button = wx.Button(self, label="Delete Selected Row")

        # 绑定按钮事件
        self.add_button.Bind(wx.EVT_BUTTON, self.OnAddRow)
        self.delete_button.Bind(wx.EVT_BUTTON, self.OnDeleteRow)

        # 创建布局
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.dvc, 1, wx.EXPAND | wx.ALL, 5)
        button_sizer = wx.BoxSizer(wx.HORIZONTAL)
        button_sizer.Add(self.add_button, 0, wx.ALL, 5)
        button_sizer.Add(self.delete_button, 0, wx.ALL, 5)
        sizer.Add(button_sizer, 0, wx.ALIGN_CENTER)
        self.SetSizer(sizer)

    def OnAddRow(self, event):
        new_row = [len(self.model.data) + 1, "new_file.pdf", 0, "0MB", "None"]
        self.model.AddRow(new_row)

    def OnDeleteRow(self, event):
        selected_item = self.dvc.GetSelection()
        if selected_item:
            row = self.model.GetRow(selected_item)
            self.model.DeleteRow(row)


if __name__ == "__main__":
    app = wx.App()
    frame = MainFrame()
    frame.Show()
    app.MainLoop()