qt: QTreeView - ограничить перетаскивание, чтобы это происходило только в пределах определенного прародителя (предка) - PullRequest
1 голос
/ 18 ноября 2010

У меня есть QTreeView, в котором я реализовал перетаскивание, чтобы разрешить переупорядочение элементов.

GПриведен следующий пример дерева:

Food                        <--fixed
|--Vegetables               <--fixed
|  |--carrots            <-- draggable/parentable
|  |--lettuce            <-- draggable/parentable
|  |  |--icebergLettuce  <-- draggable but NOT parentable
|--Fruit                    <-- fixed
|  |--apple              <-- draggable/parentable
|  |--orange             <-- draggable/parentable
|  |--bloodOrange        <-- draggable/parentable
etc...

Все, что помечено какможно перетаскивать.Все, что помечено как родительское, может иметь перетаскиваемый предмет в детстве.Все, что помечено как исправленное, ну, в общем, исправлено.

Мой вопрос: как мне ограничить выбрасывание предмета, чтобы он оставался в пределах определенного родителя?Например, я мог бы перетащить «bloodOrange» и сделать его потомком «яблока» или «апельсина» (или даже просто изменить его порядковый номер внутри «Fruit»), но я не смогу сделать его дочерним элементом морковиили салат и т. д.

Мне удалось правильно кодировать флаги для всего, кроме части, которая ограничивает операцию удаления, чтобы остаться в пределах определенного родителя.Я просто не знаю, как захватить перетаскиваемый в данный момент QModelIndex (из которого я могу определить родителя, дедушку и т.д.)

Спасибо!

Вот мой код для метода flags в случаеэто помогает: Примечание: я называю детей верхнего уровня Узлами (то есть «Еда»), следующий уровень - как Группы (то есть «Фрукты»), а последние два уровня (то есть салат и айсберг) - оба параметра.

#---------------------------------------------------------------------------
def flags(self, index):
    """
    Returns whether or not the current item is editable/selectable/etc. 
    """

    if not index.isValid():
        return QtCore.Qt.ItemIsEnabled

    #by default, you can't do anything
    enabled = QtCore.Qt.NoItemFlags
    selectable = QtCore.Qt.NoItemFlags
    editable = QtCore.Qt.NoItemFlags
    draggable = QtCore.Qt.NoItemFlags
    droppable = QtCore.Qt.NoItemFlags

    #get a pointer to the referenced object
    item = index.internalPointer()

    #only 'valid' cells may be manipulated ('valid' is defined by the obj)
    if item.column_is_valid(index.column()):

        #all valid cells are selectable and enabled
        selectable = QtCore.Qt.ItemIsSelectable
        enabled = QtCore.Qt.ItemIsEnabled

        #column 0 cells may occasionally be dragged and dropped
        if index.column() == 0:

            #drag/drop is only possible if it is a param...
            if item.get_obj_type() == 'param':

                #...and then only child-less params may be dragged...
                if item.get_child_count() == 0:
                    draggable = QtCore.Qt.ItemIsDragEnabled

                #...and only params with a group as parent may be dropped on
                if item.get_parent().get_obj_type() == "group":
                    droppable = QtCore.Qt.ItemIsDropEnabled

        #all other valid columns > 0 may be edited (no drag or drop)
        else:                
            editable = QtCore.Qt.ItemIsEditable

    #return our flags.
    return enabled | selectable| editable| draggable| droppable 

1 Ответ

1 голос
/ 15 февраля 2011

Если вы хотите, чтобы перетаскивание отображало значок «не разрешено» при наведении курсора на определенные строки, я полагаю, что вы не можете сделать это из модели. Вам нужно будет перехватить события dragEnter / Move в виджете View.

Однако dropMimeData () может возвращать False, чтобы указать, что отбрасывание отклонено.

Обратите внимание, что (в моей версии Qt) в qdnd_win есть ошибка, касающаяся отбрасываний, которые отклоняются моделью. Вот мой обходной путь, основанный на некоторых источниках дайвинга; это метод, определенный в моем подклассе QTreeView:

def dropEvent(self, evt):
    QTreeView.dropEvent(self, evt)
    if not evt.isAccepted():
        # qdnd_win.cpp has weird behavior -- even if the event isn't accepted
        # by target widget, it sets accept() to true, which causes the executed
        # action to be reported as "move", which causes the view to remove the
        # source rows even though the target widget didn't like the drop.
        # Maybe it's better for the model to check drop-okay-ness during the
        # drag rather than only on drop; but the check involves not-insignificant work.
        evt.setDropAction(Qt.IgnoreAction)

(обратите внимание, что под «немаловажной работой» я действительно имею в виду «я не хочу беспокоиться о перехвате событий»: -)

...