Qt QTreeView: разрешить удаление только для существующего элемента - PullRequest
3 голосов
/ 04 августа 2011

У меня есть пользовательская модель, унаследованная от QTreeView.Я включил перетаскивание и теперь могу перетащить элемент в дерево.Тем не менее, в настоящее время вы можете перейти на существующий элемент или между элементами.Я хотел бы ограничить это, чтобы вы могли перетаскивать только на существующие предметы.

Я установил DragDropOverwriteMode в true (фактически это значение по умолчанию для QTreeView).Тем не менее, это не мешает вам перетаскивать между элементами - это просто означает, что вы также можете перетаскивать на существующие элементы.

Я знаю, что могу игнорировать капли "insert" в dropMimeData (которые я переопределяю),проверяя, действительны ли строка и столбец (в выпадающих списках существующих элементов строка и столбец имеют значение -1, а родительский - текущий элемент), и я делаю этоТем не менее, я бы предпочел не получать эти капли.То есть.Мне бы хотелось, чтобы вы всегда опускали либо элемент выше, либо элемент ниже, а не между элементами.

Есть идеи?

Спасибо за любой совет, Джайлс

Ответы [ 2 ]

3 голосов
/ 05 августа 2011

Вам нужно перехватить события ввода при перетаскивании, переопределив метод dragEnterEvent в вашем пользовательском представлении.Пример из документации Qt:

void Window::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasFormat("text/plain"))
        event->acceptProposedAction();
}

В вашем случае вам, вероятно, нужно сравнить позицию x и y в событии с позицией x и y ближайшего элемента или чего-то подобного и отклонитьили принять предложенное действие на основе этой информации.

Из документации QAbstractItemModel::dropMimeData:

Представление несет ответственность за предоставление подходящего места для размещения данныхвставлен.

То, что я интерпретировал, означает, что представление должно отклонять отбрасывание, если оно не поддерживается базовой моделью, такой как ваша.

2 голосов
/ 22 марта 2016

Начиная с Qt 5.4 (и я предполагаю, что это было верно даже в Qt 4.8), установка DragDropOverwriteMode в true приведет к правильному , что приведет к сбросу перетаскивания только на существующие элементы и предотвратит " выше / ниже пунктов "отбрасывать цели от появления.

Кроме того, в отличие от того, о чем говорится в вопросе, DragDropOverwriteMode по умолчанию установлено на false для QTreeView (я не проверял, может быть, это более новые версии Qt), поэтому его нужно установить на true вручную.

Однако все же полезно иметь возможность рассчитывать, на какие позиции можно уронить предмет. Например, в QTreeView нельзя перетаскивать перетаскиваемый предмет на левое поле элементов, то есть на красную область ниже:

QTreeView invalid drop areas

Если что-то упало в недопустимой красной области, dropMimeData будет вызываться с аргументом parent, установленным в NULL. Так что было бы полезно ignore dragMoveEvent заранее, чтобы показать курсор "Вы не можете здесь сбросить" для пользователя , чтобы они знали, что не могут туда попасть. Qt не реализует изменение курсора мыши на недопустимых областях при перетаскивании (по состоянию на Qt 5.4), но мы можем сделать это так:

bool SubclassedTreeView::dropResultsInValidIndex(const QPoint& pos)
{
    QTreeWidgetItem* item = itemAt(pos);
    if (item == NULL || !indexFromItem(item).isValid())
        return false;
    return visualRect(indexFromItem(item)).adjusted(-1, -1, 1, 1).contains(pos, false);
}

virtual void SubclassedTreeView::dragMoveEvent(QDragMoveEvent* event)
{
    QTreeWidget::dragMoveEvent(event);
    if (!event->isAccepted())
        return;

    if (dropResultsInValidIndex(event->pos()))
        event->accept();
    else
        event->ignore(); //Show 'forbidden' cursor.
}

virtual bool SubclassedTreeView::dropMimeData(QTreeWidgetItem* parent, int index, const QMimeData* data, Qt::DropAction action)
{
    Q_UNUSED(index);
    //Modify the following action and data format checks to suit your needs:
    if (parent == NULL || action != Qt::CopyAction || !data->hasFormat("my/preferred-type"))
        return false;

    QModelIndex modelIndex = indexFromItem(parent);
    //modelIndex is where the data is dropped onto. Implement your custom drop action here...

    return true;
}

Приведенный выше код содержит небольшую часть visualRect….adjusted(-1, -1, 1, 1), которая была украдена из QAbstractItemViewPrivate::position источников. Фактически источники этой функции можно использовать для вычисления областей перезаписи / вставки / недействительных элементов, когда QAbstractItemViewPrivate::position равно false.

...