简体   繁体   English

QTableView 如何从单元格中获取纯文本

[英]How to get plain text from a cell QTableView

I'm trying to do a drag and drop between two items, but I'm having trouble getting the information out of the cell I click on in the table.我正在尝试在两个项目之间进行拖放操作,但无法从我在表格中单击的单元格中获取信息。 I have a custom table that has a custom model.我有一个自定义表,其中包含自定义 model。

class PyTableWidget(QTableView):
    def __init__(self, *args):
        super().__init__()
        self.setDragEnabled(True)

        self.set_stylesheet(*args)

    def onLeftClick(self, index):
                print('onClick index.row: %s, index.col: %s' % (index.row(), index.column()))

    def mouseMoveEvent(self, event):
        if event.buttons() == Qt.LeftButton:
            drag = QDrag(self)
            mime = QMimeData()
            drag.setMimeData(mime)
            drag.exec(Qt.MoveAction)

Here's the custom model for the table:这是表的自定义 model:

class CustomizedNumpyModel(QAbstractTableModel):
    def __init__(self, data, parent=None):
        QAbstractTableModel.__init__(self, parent)
        self._data = np.array(data.values)
        self._cols = data.columns
        self.r, self.c = np.shape(self._data)

    def data(self, index, role=Qt.DisplayRole):

        if role == Qt.DisplayRole:
            value = self._data[index.row(), index.column()]

            if isinstance(value, float):
                return "%.2f" % value

            if isinstance(value, str):
                return '%s' % value

            return unicode(value)

    def rowCount(self, parent=None):
        return self.r

    def columnCount(self, parent=None):
        return self.c

    def headerData(self, p_int, orientation, role):
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                return str(self._cols[p_int])

            if orientation == Qt.Vertical:
                return p_int
        return None

    def flags(self, index):
        return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable

    def setData(self, index, value, role=Qt.EditRole):
        index_value = None
        based_columns = [6, 8, 10, 12]
        if role == Qt.EditRole:
            row = index.row()
            column = index.column()
            tmp = str(value)
            if tmp != '':
                if column in based_columns:
                    if column == 6 and tmp in self._cols:
                        index_no = np.where(self._cols == tmp)[0][0]
                        self._data[row, column + 1] = self._data[row, index_no]
                        self._data[row, column] = tmp
                    elif column in [8, 10, 12]:
                        for x in range(97, 181):
                            if self._data[row, x] == int(tmp):
                                index_value = x
                                break

                        col_name = self._cols[index_value]
                        col_name = col_name.removesuffix('_rank')
                        self._data[row, column + 1] = col_name
                        self._data[row, column] = tmp
                    self.dataChanged.emit(index, index)
                return True
            else:
                return False

And here the code in the other widget which accept the drop这里是另一个接受放置的小部件中的代码

class PyCustomButton(QPushButton):
    def __init__(self, *args):
        super().__init__()
        self.setCursor(Qt.PointingHandCursor)
        self.setAcceptsDrops(True)
        self._lista = []

    def dragEnterEvent(self, event):
        if event.mimeData().hasText():
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        self._lista.append(event.mimeData().text())
        print(self._lista)

The table has following aspect:该表具有以下方面:

Names名称
First第一的
Second第二

And I want plain text ie First or Second drag from table and drop in custom button.我想要纯文本,即FirstSecond从表格中拖动并放入自定义按钮。

The simple solution is to get the "selected" index using indexAt() .简单的解决方案是使用indexAt()获取“选定”索引。 Note that it's generally better to start a drag action when the user has moved the mouse by a certain amount of pixels, which defaults to the QApplicationstartDragDistance() property.请注意,通常最好在用户将鼠标移动一定数量的像素时开始拖动操作,这默认为 QApplicationstartDragDistance()属性。

class PyTableWidget(QTableView):
    _startPos = None
    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            index = self.indexAt(event.pos())
            if index.isValid():
                self._startPos = event.pos()
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if event.buttons() == Qt.LeftButton and self._startPos is not None:
            delta = (event.pos() - self._startPos).manhattanLength()
            if delta >= QApplication.startDragDistance():
                drag = QDrag(self)
                mime = QMimeData()
                mime.setText(self.indexAt(self._startPos).data())
                drag.setMimeData(mime)
                drag.exec(Qt.MoveAction)
                self._startPos = None
                return
        super().mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        self._startPos = None
        super().mouseReleaseEvent(event)

Note that Qt item views already support drag and drop: to enable that support in custom models, you need to also add Qt.ItemIsDragEnabled in flags() and ensure that the table supports drag either by using setDragEnabled(True) (as you did) or by setting the dragDropMode of the view at least to DragOnly .请注意,Qt 项目视图已经支持拖放:要在自定义模型中启用该支持,您还需要在flags()中添加Qt.ItemIsDragEnabled并确保该表支持使用setDragEnabled(True)进行拖动(就像您所做的那样)或者至少将视图的DragOnly dragDropMode

The only remaining "issue" is getting the data from outside the view from the drag mime data, which uses an internal format to serialize the content.唯一剩下的“问题”是从视图外部从拖动 mime 数据获取数据,它使用内部格式来序列化内容。

While this approach might seem more complex and difficult, it's also a better solution whenever you intend to support drag and drop between multiple item views, since that serialization format is common and standard to all Qt views.虽然这种方法可能看起来更复杂和困难,但只要您打算支持多个项目视图之间的拖放,它也是一个更好的解决方案,因为该序列化格式是所有 Qt 视图的通用和标准格式。

class CustomizedNumpyModel(QAbstractTableModel):
    # ...
    def flags(self, index):
        return (Qt.ItemIsEnabled 
            | Qt.ItemIsSelectable 
            | Qt.ItemIsEditable 
            | Qt.ItemIsDragEnabled)


class PyTableWidget(QTableView):
    def __init__(self, *args):
        super().__init__(*args)
        self.setDragEnabled(True)

    # nothing else to implement in this class


class PyCustomButton(QPushButton):
    def __init__(self, *args):
        super().__init__()
        self.setCursor(Qt.PointingHandCursor)
        self.setAcceptDrops(True)
        self._lista = []

    def dragEnterEvent(self, event):
        if 'application/x-qabstractitemmodeldatalist' in event.mimeData().formats():
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        mimeData = event.mimeData()
        if mimeData.hasText():
            self._lista.append(mimeData.text())
        elif 'application/x-qabstractitemmodeldatalist' in mimeData.formats():
            names = []
            stream = QDataStream(mimeData.data(
                'application/x-qabstractitemmodeldatalist'))
            while not stream.atEnd():
                # all fields must be read, even if not used
                row = stream.readInt()
                column = stream.readInt()
                for _ in range(stream.readInt()):
                    role = stream.readInt()
                    value = stream.readQVariant()
                    if role == Qt.DisplayRole:
                        names.append(value)
            self._lista.extend(names)
        print(self._lista)

Note that setData() must always return a bool.请注意, setData()必须始终返回一个布尔值。 Remove the last else: and push the return False back to the main indentation level of the function.删除最后一个else:并将return False推回到 function 的主缩进级别。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM