Сделать элемент в QTableView перетаскиваемым, но не выбираемым

Небольшая предыстория (не совсем необходимая для понимания проблемы):

В приложении PySide2, которое я разработал ранее в этом году, у меня есть QTableView, который я использую с пользовательской моделью. Некоторые элементы там можно выбрать, чтобы затем нажать кнопку для выполнения массового действия над выбранными элементами. Некоторые другие элементы присутствуют как визуальное указание на то, что данные существуют, но функция, выполняющая массовое действие, не знает, как с ними обращаться, поэтому я сделал их недоступными для выбора. У меня есть еще одна область в моей программе, которая может принимать капли либо из внешних файлов, либо из элементов в моем TableView. В этом случае каждый из элементов таблицы должен иметь возможность перетаскиваться, а затем опускаться в другую область.

Проблема:

Когда элемент не может быть выбран, кажется, что его также нельзя перетаскивать.

Что я пробовал:

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

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

Минимальный код воспроизведения:

from PySide2 import QtCore, QtWidgets, QtGui


class MyWindow(QtWidgets.QWidget):
    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        self.setGeometry(300, 200, 570, 450)
        self.setWindowTitle("Drag Example")
        model = QtGui.QStandardItemModel(2, 1)
        table_view = QtWidgets.QTableView()

        selectable = QtGui.QStandardItem("I'm selectable and draggable")
        selectable.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsDragEnabled)
        model.setItem(0, 0, selectable)

        non_selectable = QtGui.QStandardItem("I'm supposed to be draggable, but I'm not")
        non_selectable.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsDragEnabled)
        model.setItem(1, 0, non_selectable)

        table_view.setModel(model)
        table_view.setDragDropMode(table_view.DragOnly)
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(table_view)
        self.setLayout(layout)


app = QtWidgets.QApplication([])
win = MyWindow()
win.show()
app.exec_()

Есть ли у кого-нибудь предложение о том, как сделать элемент перетаскиваемым, но отключенным при выборе?

Спасибо


person Erwan Leroy    schedule 22.09.2019    source источник


Ответы (1)


Я нашел обходной путь, хотя и не обязательно идеальный ответ, он помогает мне.

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

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

Чтобы создать впечатление, что элементы не выбраны, даже если они выбраны, я использовал делегат элемента с пользовательским стилем:

class MyDelegate(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent=None):
        super(MyDelegate, self).__init__(parent)

    def paint(self, painter, option, index):

        if option.state & QtWidgets.QStyle.State_Selected:
            if index.data(Qt.UserRole) == 2:  # Some random flag i'm using
                text_brush = option.palette.brush(QtGui.QPalette.Text)
                if index.row() % 2 == 0:
                    bg_brush = option.palette.brush(QtGui.QPalette.Base)
                else:
                    bg_brush = option.palette.brush(QtGui.QPalette.AlternateBase)
                # print brush
                option.palette.setBrush(QtGui.QPalette.Highlight, bg_brush)
                option.palette.setBrush(QtGui.QPalette.HighlightedText, text_brush)

        super(MyDelegate, self).paint(painter, option, index)

и в таблице я установил:

delegate = MyDelegate()
table_view.setItemDelegate(delegate)

Я адаптировал это решение из этого сообщения: QTreeView Item Hover/ Выбранный цвет фона на основе текущего цвета

person Erwan Leroy    schedule 29.09.2019