Редактировать таблицу в PyQt QAbstractTableModel без удаления содержимого

Что я уже сделал:

Я реализую пользовательский QAbstractTableModel (используемый в QTableView-виджете), который содержит редактируемые ячейки. Свойства этих ячеек указаны в моем методе flags(), который выглядит так:

def flags(self, index):  # Qt was imported from PyQt4.QtCore
    if index.column() < 2:
        return Qt.ItemIsEditable | Qt.ItemIsEnabled | \
               Qt.ItemIsSelectable
    else:
        return Qt.ItemIsEnabled | Qt.ItemIsSelectable

Ячейки в первых двух столбцах помечены как редактируемые, как я и хочу.

Что я хочу сделать:

Однако при двойном щелчке по ячейке для запуска редактирования содержащийся в ней текст удаляется и отображается пустое поле.

Пример редактирования ячейки

Но я не хочу удалять и заменять содержащийся текст, потому что содержащийся текст может быть очень длинным и не должен быть перепечатан. Я просто хочу отредактировать то, что уже содержится. При двойном щелчке ячейка должна быть редактируемой с ранее содержащимся внутри текстом (возможно, уже выделенным).

Вопрос:

Как я могу добиться такого поведения? Нужно ли мне редактировать мой метод флагов и указывать разные свойства для этих ячеек?


person aisen    schedule 31.05.2016    source источник


Ответы (2)


У вас есть несколько вариантов.

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

Другой способ сделать это — использовать файл QItemDelegate. Это позволит вам вручную создать виджет редактора и инициализировать его до того, как он появится в файле QTableView. Вы можете использовать текст отображаемой роли, если текст редактирования не был заполнен.

class MyDelegate(QtGui.QItemDelegate):

    def createEditor(self, parent, option, index):
        if index.column() == 2:
            return super(MyDelegate, self).createEditor(parent, option, index)
        return None

    def setEditorData(self, editor, index):
        if index.column() == 2:
            # Gets display text if edit data hasn't been set.
            text = index.data(Qt.EditRole) or index.data(Qt.DisplayRole)
            editor.setText(text)         

delegate = MyDelegate()
tableview.setItemDelegate(delegate)
person Brendan Abel    schedule 31.05.2016
comment
Спасибо. Я попробовал ваш второй подход с QItemDelegate, и он работает так, как предполагалось. Если бы я хотел установить Qt.EditRole без использования класса, как бы я это сделал? Должен ли я определить новый метод в моем пользовательском TableModel? - person aisen; 07.06.2016
comment
Я не думаю, что вам нужно что-то делать в вашей модели. Хотя сомнительно, зачем вам нужно создавать пользовательскую модель. QStandardItemModel не работает? Если вы просто хотите управлять флагами, вы можете установить их на элементах по мере их создания. Это не обязательно должна быть динамическая функция модели. - person Brendan Abel; 07.06.2016
comment
Ну, я только выясняю, как что-то делать с PyQt, и даже не знал, что есть что-то вроде стандартного класса. Я посмотрю. - person aisen; 07.06.2016
comment
Кроме того, если вы не знаете, что вам нужна модель, классов виджетов элементов — QTreeWidget, QTableWidget и т. д. обычно будет достаточно, и обычно они будут быстрее кодироваться и создаваться, а также, как правило, более простой код. - person Brendan Abel; 07.06.2016
comment
эй, я хочу ровно наоборот, у меня есть собственный QListWidget, и когда я нажимаю на элемент, чтобы переименовать его, у меня просто есть старое имя, и я не могу его удалить, даже если я начну печатать, оно остается там, когда я нажимаю ввод, оно исчезает и получает новый, но это раздражает, я хочу нажать Enter и ведет себя так, как должно! помогите пожалуйста - person Nestor Colt; 14.10.2017
comment
@NestorColt Добро пожаловать! Вы должны отправить новый вопрос, описывающий эту проблему. Комментарии — не лучшее место для ответов на новые вопросы. - person Brendan Abel; 16.10.2017
comment
@BrendanAbel, откуда вы узнали о таких вещах, как QStandardItemModel и QTreeWidget? Книги, которые я нашел до сих пор по PyQt, освещают вещи очень поверхностно. Спасибо. - person user118967; 18.02.2021
comment
@user118967 user118967 Документация Qt и PySide довольно хороша и подробно описывает многое из этого. Кроме того, если вы загружаете PySide или Qt с помощью Creator или Designer, они содержат множество примеров для всех этих типов виджетов. - person Brendan Abel; 18.02.2021

Как сказал Брендан Абель,

Данные не отображаются в ячейках во время редактирования, потому что вы, вероятно, не установили данные в Qt.EditRole для каждого элемента в вашей модели.

В этом случае, чтобы отобразить предыдущие данные в поле редактирования после двойного щелчка по ячейке, требуется доступ к data() как EditRole, поэтому вы должны реализовать метод data() в унаследованном классе модели примерно так:

def data(self, index, role=None):
    ...
    if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
        item = index.internalPointer()
        return item.data[index.column()]
    ...

Он также упоминается в официальном документе модели посмотреть программу

person Claude C    schedule 21.02.2020
comment
index.internalPointer() возвращает None в PyQt5 - person Ciasto piekarz; 28.01.2021
comment
@Ciastopiekarz Документ говорит, что возвращает указатель на внутренние данные, и в моем приложении он действительно возвращает объект данных, а не None, если индекс действителен. - person Claude C; 29.01.2021
comment
Я ценю информацию о необходимости включения условия для EditRole. Однако этот ответ предлагает получить данные объекта QTableView index. Кажется, это противоречит всей концепции модели-представления, согласно которой данные (модель) должны быть отделены от представления. Возвращаемое значение могло быть вычислено или прочитано из любой пользовательской структуры данных, которую модель использует для хранения своих данных, не обязательно из index.internalPointer. Фактически, у ОП, вероятно, уже была реализация для data, делающая именно это, и ему просто нужно было добавить условие role == QtCore.Qt.EditRole. - person user118967; 18.02.2021
comment
@ user118967 Спасибо за совет. Я просто следовал примеру официального представления модели исходный код. В коде data(..) (ln143) вызывает getItem(..)(ln159), наконец, вызывает index.internalPointer() (ln161). IMO, это должно быть безвредно, потому что index - это объект индекса модели, созданный index(..) в классе модели, а не представлением. - person Claude C; 20.02.2021