0

我有 3 三张图片,如下所示:

图片1

在此处输入图像描述

在此处输入图像描述

如何让 QLineEdit 和 QPushButton 在 PyQt5 的 tableview 中以这样的列和样式显示?

我有以下三张图片,如下所示,

我想编写一个通过 PyQt5 实现这些功能的 GUI:

  1. 单击鼠标一次,它会选择这一行,并高亮这一行1。就像数字1点到
  2. 几秒钟后,在“单击此处添加文件”再次单击鼠标一次,它将进入编辑模式。就像数字 2 点一样,QLineEdit 和 QPushButton '...' 将显示在第二列。如果我单击“...”,并弹出一个文件选择对话框,当我选择一个文件时,它将用文件绝对路径替换“单击此处添加文件”。

    注意:不是双击鼠标进入编辑模式,应该是单击鼠标一次,几秒钟后,再次单击鼠标,将进入编辑模式。当我选择一个绝对路径非常长的文件时。我可以在 QPushButton '...' 后面看到一些字符显示,看起来 QPushButton 在 QLineEdit 的右侧重叠。

  3. 完成第 2 步后,如果继续在另一行单击鼠标,则第 2 步中的 QLineEdit 和 QPushButton '...' 将消失,如行 'VAR("myModelConer")

我研究了 3 个功能很多天,但无法获得我想要的风格。我将在这里给出我的代码,例如,它是 2 行和 2 列。任何人都可以帮助我修改和完成以上 3 个功能。

提前致谢

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class Delegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        super(Delegate, self).__init__(parent)

    def createEditor(self, parent, option, index):
        if index.column() == 0:
            lineedit    = QLineEdit("$woroot/1.scs",parent)
            pushbutton  = QPushButton("...", parent)
            #lineedit   = QLineEdit("..",self.parent())
            #pushbutton = QPushButton("...", self.parent())
            lineedit.index       = [index.row(), index.column()]
            pushbutton.index    = [index.row(), index.column()]
            h_box_layout = QHBoxLayout()
            h_box_layout.addWidget(lineedit)
            h_box_layout.addWidget(pushbutton)
            h_box_layout.setContentsMargins(0, 0, 0, 0)
            h_box_layout.setAlignment(Qt.AlignCenter)
            widget = QWidget()
            widget.setLayout(h_box_layout)
            self.parent().setIndexWidget(
                index,
                widget
            )
        elif index.column() == 1:
            combobox = QComboBox(parent)
            combobox.addItems(section_list)
            combobox.setEditable(True)
            #combobox.editTextChanged.connect(self.commitAndCloseEditor)        
            return combobox

    def setEditorData(self, editor, index):
        text = index.model().data(index, Qt.DisplayRole)
        print "setEditorData, text=", text
        text = str(text)
        i = editor.findText(text)
        print "i=", i
        if i == -1:     
            i = 0
        editor.setCurrentIndex(i)  

    def setModelData(self, editor, model, index):

        text = editor.currentText()
        if len(text) >= 1:
            model.setData(index, text)

    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)

    def commitAndCloseEditor(self):
        editor = self.sender()
        if isinstance(editor, (QTextEdit, QLineEdit,QSpinBox,QComboBox)):
            self.commitData[QWidget].emit(editor)
            self.closeEditor[QWidget].emit(editor)
if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    model = QStandardItemModel(4, 2)
    tableView = QTableView()
    tableView.setModel(model)
    delegate = Delegate(tableView)
    tableView.setItemDelegate(delegate)
    section_list = ['w','c','h']
    for row in range(4):
        for column in range(2):
            index = model.index(row, column, QModelIndex())
            model.setData(index, (row + 1) * (column + 1))
    tableView.setWindowTitle("Spin Box Delegate")
    tableView.show()
    sys.exit(app.exec_())
4

1 回答 1

1

如果你想为编辑器使用一个复杂的小部件,你当然不应该使用setIndexWidget()within createEditor,因为你会失去对它的直接访问和控制。而是返回复杂的小部件,并确保 setModelData 和 setEditorData 都正确运行。

要检查“延迟”单击,您还需要覆盖editorEvent()以确保事件实际上是左键单击。
但是,这还不够:项目视图选择总是被事件循环的一个周期延迟,因此在单击后立即获取当前选择是不可靠的,因为它会在之后更新;您需要使用单次 QTimer 才能正确检查表的选择和当前索引。

最后,无需检查委托中的列,只需使用即可setItemDelegateForColumn()

class ClickDelegate(QtWidgets.QStyledItemDelegate):
    blankText = '<Click here to add path>'

    def openFileDialog(self, lineEdit):
        if not self.blankText.startswith(lineEdit.text()):
            currentPath = lineEdit.text()
        else:
            currentPath = ''
        path, _ = QtWidgets.QFileDialog.getOpenFileName(lineEdit.window(), 
            'Select file', currentPath)
        if path:
            lineEdit.setText(path)

    def createEditor(self, parent, option, index):
        editor = QtWidgets.QWidget(parent)

        layout = QtWidgets.QHBoxLayout(editor)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        editor.lineEdit = QtWidgets.QLineEdit(self.blankText)
        layout.addWidget(editor.lineEdit)
        # set the line edit as focus proxy so that it correctly handles focus
        editor.setFocusProxy(editor.lineEdit)
        # install an event filter on the line edit, because we'll need to filter
        # mouse and keyboard events
        editor.lineEdit.installEventFilter(self)

        button = QtWidgets.QToolButton(text='...')
        layout.addWidget(button)
        button.setFocusPolicy(QtCore.Qt.NoFocus)
        button.clicked.connect(lambda: self.openFileDialog(editor.lineEdit))
        return editor

    def setEditorData(self, editor, index):
        if index.data():
            editor.lineEdit.setText(index.data())
        editor.lineEdit.selectAll()

    def setModelData(self, editor, model, index):
        # if there is no text, the data is cleared
        if not editor.lineEdit.text():
            model.setData(index, None)
        # if there is text and is not the "blank" default, set the data accordingly
        elif not self.blankText.startswith(editor.lineEdit.text()):
            model.setData(index, editor.lineEdit.text())

    def initStyleOption(self, option, index):
        super().initStyleOption(option, index)
        if not option.text:
            option.text = self.blankText

    def eventFilter(self, source, event):
        if isinstance(source, QtWidgets.QLineEdit):
            if (event.type() == QtCore.QEvent.MouseButtonPress and 
                source.hasSelectedText() and 
                self.blankText.startswith(source.text())):
                    res = super().eventFilter(source, event)
                    # clear the text if it's the "Click here..."
                    source.clear()
                    return res
            elif event.type() == QtCore.QEvent.KeyPress and event.key() in (
                QtCore.Qt.Key_Escape, QtCore.Qt.Key_Tab, QtCore.Qt.Key_Backtab):
                    # ignore some key events so that they're correctly filtered as
                    # they are emitted by actual editor (the QWidget) 
                    return False
        return super().eventFilter(source, event)

    def checkIndex(self, table, index):
        if index in table.selectedIndexes() and index == table.currentIndex():
            table.edit(index)

    def editorEvent(self, event, model, option, index):
        if (event.type() == QtCore.QEvent.MouseButtonPress and 
            event.button() == QtCore.Qt.LeftButton and
            index in option.widget.selectedIndexes()):
                # the index is already selected, we'll delay the (possible)
                # editing but we MUST store the direct reference to the table for
                # the lambda function, since the option object is going to be
                # destroyed; this is very important: if you use "option.widget"
                # in the lambda the program will probably hang or crash
                table = option.widget
                QtCore.QTimer.singleShot(0, lambda: self.checkIndex(table, index))
        return super().editorEvent(event, model, option, index)
于 2020-04-02T13:39:27.457 回答