PyQt: How to insert text at the cursor in QTableView

我是研究僧i 提交于 2019-12-08 04:02:43

问题


I have a QTableView as below. I'd like to press the Test button and insert an "a" at the cursor - for example in the middle of "11" at (row,column) = (2,2). That is, the user double-clicks cell (2,2) and places the cursor in the middle of "11", and presses Test. Desired result: "1a1".

Is this doable? If yes, how? Thanks very much.

# coding: utf-8

import sys
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import *
from PyQt4.QtGui import *

MY_ARRAY = [['00', '01', '02'],
            ['10', '11', '12'],
            ['20', '21', '22']]


class MyWindow(QTableView):
    def __init__(self, *args):
        super(MyWindow, self).__init__()

        self.tablemodel = MyTableModel(MY_ARRAY)

        self.tableview = QTableView()

        self.tableview.setModel(self.tablemodel)

        self.tableview.setItemDelegate(MyDelegate(self))

        self.layout = QVBoxLayout(self)
        self.layout.addWidget(self.tableview)

        self.button1 = QPushButton("Test")

        self.button1.released.connect(self.test)

        self.layout.addWidget(self.button1)
        self.setLayout(self.layout)

    def test(self):

        # MY_ARRAY.append([30,31,32])

        index = self.tableview.currentIndex()
        item = self.tablemodel.data(index, Qt.DisplayRole)

        print("item %s " % item)

        item_edit = self.tableview.edit(index)

        qDebug("qDebug: item_edit %s " % item_edit)

        MY_ARRAY.insert(index.row(), ['30', '31', '32'])

        self.tablemodel.layoutChanged.emit()

        qDebug(" {} " .format(MY_ARRAY))

        qcursor = QCursor.pos()
        qDebug(" {} ".format(qcursor))

        qcursor1 = self.mapFromGlobal(qcursor)
        qDebug(" {} ".format(qcursor1))

        # qDebug(" self.tableview.indexAt(qcursor) {} ".format(self.tableview(qcursor)))
        # qDebug(" self.tableview.indexAt(qcursor1) {} ".format(self.tableview(qcursor1)))

        # print(' index.row(): ', index.row())

        qDebug(
            " tableview.rowViewportPosition %s " %
            self.tableview.rowViewportPosition(index.row()))
        qDebug(
            " tableview.columnViewportPosition %s " %
            self.tableview.columnViewportPosition(index.column()))

        # qDebug(" tableview.viewport() %s " % self.tableview.viewport(qcursor))

        item = self.tableview.setCurrentIndex(index)
        qDebug(" tableview.item() %s " % self.tableview)


class MyTableModel(QAbstractTableModel):
    def __init__(self, datain, parent=None, *args):
        super(MyTableModel, self).__init__(parent, *args)

        self.arraydata = datain

    def rowCount(self, parent):
        return len(self.arraydata)

    def columnCount(self, parent):
        return len(self.arraydata[0])

    def data(self, index, role):
        if not index.isValid():
            return None

        elif not (role == Qt.DisplayRole or role == Qt.EditRole):
            return None
        return (self.arraydata[index.row()][index.column()])

    def setData(self, index, value, role=Qt.EditRole):
        self.arraydata[index.row()][index.column()] = value
        return True

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


class MyDelegate(QStyledItemDelegate):

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

    def createEditor(self, parent, option, index):
        editor = QLineEdit(parent)
        self.connect(editor, SIGNAL("returnPressed()"),
                     self.commitAndCloseEditor)
        return editor

    def commitAndCloseEditor(self):
        editor = self.sender()
        if isinstance(editor, (QTextEdit, QLineEdit)):
            self.emit(SIGNAL("commitData(QWidget*)"), editor)
            self.emit(SIGNAL("closeEditor(QWidget*)"), editor)

    def setEditorData(self, editor, index):
        text = index.model().data(index, Qt.DisplayRole)

        editor.setText(text)

    def setModelData(self, editor, model, index):
        model.setData(index, editor.text())

def main():
    app = QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

回答1:


A table cells do not have a cursor and are not directly editable. The editing capabilties are provided by the item-delegate. By default, the editor widget for text data is a QLineEdit, but other data types may use different editor widgets, such as a QSpinBox for numerical data, or a QComboBox for boolean data. The specific widget used can be controlled by setting a custom item-delegate.

The big problem with using something like a button to insert text in the editing widget, is that the editor will be automatically closed (and destroyed) as soon as the button is clicked. It will therefore be much simpler to use a context-menu to add custom actions:

class MyWindow(QTableView):
    def __init__(self, *args):
        ...
        self.delegate = MyDelegate(self)
        self.delegate.contextMenuRequested.connect(self.showContextMenu)
        self.tableview.setItemDelegate(self.delegate)

    def showContextMenu(self, editor, pos):
        pos = editor.mapToGlobal(pos)
        menu = editor.createStandardContextMenu()
        menu.addSeparator()
        action = menu.addAction('Insert Text')
        if menu.exec_(pos) is action:
            editor.insert(' foo ')

class MyDelegate(QStyledItemDelegate):
    contextMenuRequested = pyqtSignal(object, QPoint)

    def createEditor(self, parent, option, index):
        editor = QLineEdit(parent)
        editor.setContextMenuPolicy(Qt.CustomContextMenu)
        editor.customContextMenuRequested.connect(
            lambda pos: self.contextMenuRequested.emit(editor, pos))
        return editor



回答2:


After a lot of struggle and uses of qDebug I finally managed to find a solution. I am sure it can be further improved. But I don't know much about PyQt. The idea is to cache the cursor position in MyDelegate(QStyledItemDelegate) before the editor is closed. I hope it can be useful to someone who encounters the same problem.

class MyDelegate(QStyledItemDelegate):
    ...
    def createEditor(self, parent, option, index):
        self.cursorpos = -1  # unset flag
        editor = QLineEdit(parent)
        self.connect(editor, SIGNAL("editingFinished()"),
                         self.commitAndCloseEditor)
        return editor

    def commitAndCloseEditor(self):
        editor = self.sender()
        self.cursorpos = editor.cursorPosition()
        if isinstance(editor, (QTextEdit, QLineEdit)):
            self.emit(SIGNAL("commitData(QWidget*)"), editor)
            self.emit(SIGNAL("closeEditor(QWidget*)"), editor)

The whole thing is given below.

# coding: utf-8

import sys
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import *
from PyQt4.QtGui import *

MY_ARRAY = [['00', '01', '02'],
            ['10', '11', '12'],
            ['20', '21', '22']]


class MyWindow(QTableView):
    def __init__(self, *args):
        super(MyWindow, self).__init__()

        self.tablemodel = MyTableModel(MY_ARRAY)

        self.tableview = QTableView()

        self.tableview.setModel(self.tablemodel)

        # self.tableview.setItemDelegate(MyDelegate(self))

        self.delegate = MyDelegate(self)
        self.tableview.setItemDelegate(self.delegate)

        self.layout = QVBoxLayout(self)
        self.layout.addWidget(self.tableview)

        self.button1 = QPushButton("Test")

        self.button1.released.connect(self.test)

        self.layout.addWidget(self.button1)
        self.setLayout(self.layout)

    def test(self):

        index = self.tableview.currentIndex()
        item = self.tablemodel.data(index, Qt.DisplayRole)

        qDebug("item %s " % item)

        qDebug(" <test><MyDelegateMyDelegate> self.delegate.cursorpos: %s " % self.delegate.cursorpos)

        cursorpos = self.delegate.cursorpos
        qDebug(" <test> cursor pos %s " % cursorpos)
        if cursorpos > -1:
            index.model().setData(index, item[:cursorpos] + ' foo ' + item[cursorpos:])
            self.tablemodel.layoutChanged.emit()
            self.delegate.cursorpos = -1


class MyTableModel(QAbstractTableModel):
    def __init__(self, datain, parent=None, *args):
        super(MyTableModel, self).__init__(parent, *args)

        self.arraydata = datain

    def rowCount(self, parent):
        return len(self.arraydata)

    def columnCount(self, parent):
        return len(self.arraydata[0])

    def data(self, index, role):
        if not index.isValid():
            return None

        elif not (role == Qt.DisplayRole or role == Qt.EditRole):
            return None
        return (self.arraydata[index.row()][index.column()])

    def setData(self, index, value, role=Qt.EditRole):
        self.arraydata[index.row()][index.column()] = value
        return True

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


class MyDelegate(QStyledItemDelegate):

    def __init__(self, parent=None):
        super(MyDelegate, self).__init__(parent)
        self.cursorpos = -1  # unset flag

    def createEditor(self, parent, option, index):
        self.cursorpos = -1  # unset flag
        editor = QLineEdit(parent)
        self.connect(editor, SIGNAL("editingFinished()"),
                         self.commitAndCloseEditor)
        return editor

    def commitAndCloseEditor(self):
        editor = self.sender()
        self.cursorpos = editor.cursorPosition()
        if isinstance(editor, (QTextEdit, QLineEdit)):
            self.emit(SIGNAL("commitData(QWidget*)"), editor)
            self.emit(SIGNAL("closeEditor(QWidget*)"), editor)

    def setEditorData(self, editor, index):
        text = index.model().data(index, Qt.DisplayRole)

        editor.setText(text)


    def setModelData(self, editor, model, index):
        model.setData(index, editor.text())

def main():
    app = QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()


来源:https://stackoverflow.com/questions/40950105/pyqt-how-to-insert-text-at-the-cursor-in-qtableview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!