Как сделать так, чтобы QLineEdit и QPushButton отображались в столбце и стиль, подобный этому, в виде таблицы в PyQt5? - PullRequest
0 голосов
/ 31 марта 2020

У меня есть три фотографии, показанные ниже:

picture1

enter image description here

enter image description here

Как позволить QLineEdit и QPushButton отображаться в столбце и стиль, подобный этому, в виде таблицы в PyQt5?

У меня есть следующие три изображения, показанные ниже,

Я хочу написать GUI, который выполняет эти функции PyQt5:

  1. , если щелкнуть мышью один раз, он выделит эту строку, а также выделит эту строку1. точно так же, как цифровая 1 точка к
  2. через несколько секунд, в «Нажмите здесь, чтобы добавить файл», нажмите один раз мышью, чтобы перейти в режим редактирования. точно так же, как цифровые 2 точки, QLineEdit и QPushButton '...' отобразятся во 2-м столбце. если я нажимаю «...» и открываю диалоговое окно «Выбор файла», при выборе файла он заменяет «Нажмите здесь, чтобы добавить файл» по абсолютному пути к файлу.

    будьте осторожны: не дважды -нажмите кнопку мыши, войдите в режим редактирования, нажмите кнопку мыши один раз, через несколько секунд снова нажмите кнопку мыши, войдите в режим редактирования. когда я выбираю файл, абсолютный путь которого очень и очень длинный. Я вижу какое-то символьное шоу за QPushButton '...', похоже, что QPushButton перекрывается справа от QLineEdit.

  3. , когда шаг 2 выполнен, если продолжать щелкать мышью в другой строке, QLineEdit и QPushButton '...' на шаге 2 будет удален, как строка '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_())

1 Ответ

1 голос
/ 02 апреля 2020

Если вы хотите использовать сложный виджет для редактора, вам определенно не следует использовать setIndexWidget() в createEditor, потому что вы потеряете прямой доступ к нему и контроль над ним. Вместо этого верните сложный виджет и убедитесь, что setModelData и setEditorData работают правильно.

Чтобы проверить наличие «отложенного» клика, вам также необходимо переопределить editorEvent(), чтобы убедиться, что событие на самом деле это щелчок левой кнопкой.
Однако этого будет недостаточно: выбор элементов всегда задерживается циклом события l oop, поэтому получение текущего выбора сразу после щелчка ненадежно, как это будет обновлено впоследствии; вам нужно использовать 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)
...