wxpython DataViewCtrl - правильно определить цель удаления - PullRequest
0 голосов
/ 15 января 2019

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

drop on parent drop between two lines

Это код:

import wx
import wx.dataview as dv

print(wx.__version__)

class Container(list):
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return 'Container {}'.format(self.name)

class Element(object):
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return 'Element {}'.format(self.name)

    @property
    def len(self):
        return str(len(self.name))

class MyTreeListModel(dv.PyDataViewModel):
    def __init__(self, data):
        dv.PyDataViewModel.__init__(self)
        self.data = data

    def GetColumnCount(self):
        return 2

    def GetColumnType(self, col):
        mapper = { 0 : 'string',
                   1 : 'string'
                   }
        return mapper[col]


    def GetChildren(self, parent, children):
        if not parent:
            for cont in self.data:
                children.append(self.ObjectToItem(cont))
            return len(self.data)

        node = self.ItemToObject(parent)
        if isinstance(node, Container):
            for ds in node:
                children.append(self.ObjectToItem(ds))
            return len(node)
        return 0

    def IsContainer(self, item):
        if not item:
            return True
        node = self.ItemToObject(item)
        if isinstance(node, Container):
            return True
        return False

    def GetParent(self, item):
        if not item:
            return dv.NullDataViewItem

        node = self.ItemToObject(item)
        if isinstance(node, Container):
            return dv.NullDataViewItem
        elif isinstance(node, Element):
            for g in self.data:
                try:
                    g.index(node)
                except ValueError:
                    continue
                else:
                    return self.ObjectToItem(g)

    def GetValue(self, item, col):
        node = self.ItemToObject(item)

        if isinstance(node, Container):
            mapper = { 0 : node.name,
                       1 : '',
                       }
            return mapper[col]

        elif isinstance(node, Element):
            mapper = { 0 : node.name,
                       1 : node.len
                       }
            return mapper[col]

        else:
            raise RuntimeError("unknown node type")

class MyFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, "Table")

        panel = wx.Panel(self)

        dvcTree = dv.DataViewCtrl(panel,style=wx.BORDER_THEME|dv.DV_MULTIPLE)
        self.model = MyTreeListModel(data)
        dvcTree.AssociateModel(self.model)

        dvcTree.AppendTextColumn("Container",   0, width=80)
        dvcTree.AppendTextColumn("Element",   1, width=80)

        dvcTree.Bind(dv.EVT_DATAVIEW_ITEM_BEGIN_DRAG, self._onDrag)
        dvcTree.Bind(dv.EVT_DATAVIEW_ITEM_DROP, self._onEndDrag)
        dvcTree.Bind(dv.EVT_DATAVIEW_ITEM_DROP_POSSIBLE, self._onDropPossible)

        self.dvcTree = dvcTree
        dvcTree.EnableDragSource(wx.DataFormat(wx.DF_UNICODETEXT))
        dvcTree.EnableDropTarget(wx.DataFormat(wx.DF_UNICODETEXT))

        box = wx.BoxSizer(wx.VERTICAL)
        box.Add(dvcTree, 1, wx.EXPAND)
        panel.SetSizer(box)
        self.Layout()

    def _onDropPossible(self, evt):
        item = evt.GetItem()
        mod = evt.GetModel()

        if not evt.GetItem().IsOk():
            return

    def _onEndDrag(self, evt):
        if not evt.GetItem().IsOk():
            evt.Veto()
            return

        mod = evt.GetModel()
        print('dropped at', mod.ItemToObject(evt.GetItem()))
        try:
            print('parent:',mod.ItemToObject(mod.GetParent(evt.GetItem())))
        except TypeError:
            print('parent: None')

    def _onDrag(self, evt):
        evt.Allow()
        mod = evt.GetModel()
        print('from', mod.GetValue(evt.GetItem(),0))
        evt.SetDataObject(wx.TextDataObject('don\'t know how to retrieve that information in the drop handler'))
        evt.SetDragFlags(wx.Drag_AllowMove)      

data = [Container('eins'),Container('zwei'),Container('drei')]
for d in data:
    d[:] = [Element('element {}'.format('X'*q)) for q in range(5)]

if __name__ == "__main__":
    app = wx.App()
    f = MyFrame(None)
    f.Show()
    app.MainLoop()

EDIT:

Это в основном проблема в OSX, поскольку реализация MSW не предлагает пропадать между строками. Я не смог проверить это на Linux, хотя.

...