Простой иерархический листинг в PyQT

Я пытаюсь создать пользовательский интерфейс с 3 столбцами - когда вы выбираете элемент в левом столбце, элемент выбора передается функции, и она возвращает элементы для среднего столбца (и, конечно же, то же самое для выбора элементов в средний столбец)

Должно быть просто, но я не могу найти простого способа сделать это ..

Сначала я попробовал QColumnView, так как он казался идеальным ... однако реализация QAbstractItemModel кажется чрезмерно сложной, и я не смог найти никаких полезных примеров этого.

Затем, поскольку количество уровней фиксировано, я сделал три QListView и изменил этот пример QAbstractListModel

... однако не было никакого полезного сигнала, который я мог бы использовать для запуска обновления других уровней иерархии. Согласно документам PyQT, QListView имеет только " indexesMoved "сигнал. Также есть «нажатие» и «нажатие», однако они не срабатывают при изменении элементов с помощью клавиатуры.

Последним вариантом является QListWidget, который будет работать, поскольку он имеет необходимые сигналы (itemChanged и т. Д.), Но способ создания элементов списка немного утомителен (создание QListWidgetItem с родительским элементом, установленным для экземпляра QListWidget)

Изменить: QListWidget делает почти то, что мне нужно:

self.first_column = QListWidget()
self.first_column.itemSelectionChanged.connect(self.update_second_column)

person dbr    schedule 25.09.2011    source источник
comment
... похоже, нет полезного сигнала - Можете ли вы определить, что вы подразумеваете под полезным сигналом? Судя по вашему сообщению, я не знаю, какие именно события вас интересуют.   -  person Kaleb Pederson    schedule 27.09.2011
comment
@KalebPederson - сигнал, который будет срабатывать при изменении выбора, чтобы я мог обновить следующий уровень в иерархии. Думаю, ответ Жанно делает то, что мне нужно   -  person dbr    schedule 29.09.2011
comment
Да, если вы хотите получать уведомления об изменении выбора, вам следует посмотреть selectionModel   -  person Kaleb Pederson    schedule 29.09.2011


Ответы (2)


Любой QAbastractItemView имеет QItemSelectionModel, доступный через _ 3_. У QItemSelectionModel есть сигналы, которые могут вам помочь:

currentChanged ( const QModelIndex & current, const QModelIndex & previous )
currentColumnChanged ( const QModelIndex & current, const QModelIndex & previous )
currentRowChanged ( const QModelIndex & current, const QModelIndex & previous )
selectionChanged ( const QItemSelection & selected, const QItemSelection & deselected )

Надеюсь, это поможет.

person Jeannot    schedule 27.09.2011
comment
Ага, похоже на то, что я искал! Еще не было возможности протестировать, но я думаю, что могу сделать что-то вроде self.myQListView.selectionModel().currentChanged.connect(self.mycallback)? - person dbr; 29.09.2011

QListView наследуется от QAbstractItemView (я думаю, вы это знали), поэтому он получает несколько сигналов, надеюсь, один (или несколько) из них сработает для вас.

Это работает для меня (подключите сигналы при инициализации вашего QMainWindow или основного QWidget, как в примере SaltyCrane):

connect(your_list_view, SIGNAL("clicked(const QModelIndex&)"), handler_slot)

...

def handler_slot(idx):
    #idx is a QModelIndex
    #QModelIndex.data() returns a QVariant, Qt4's generic data container
    celldata = idx.data()
    #Choose the proper datatype to ask the QVariant for (e.g. QVariant.toInt())
    actualvalue = celldata.toInt()
    #QVariant.toInt() happens to return a tuple
    print actualvalue[0]

В зависимости от типа данных в вашей модели вам потребуется выберите правильный тип данных, который нужно запросить у QVariant.

Подлая часть здесь заключается в том, чтобы QListView сообщал вам, какая ячейка была нажата (например, с использованием clicked(const QModelIndex&) против clicked()). Думаю, я потратил некоторое время на изучение документации C ++ для Qt4, прежде чем понял, что вы можете получить больше от сигналов.

Отсюда у меня будет handler_slot() вызов setData() метода модели для вашего второго QListView (с использованием данных, сгенерированных функцией, которую вы изначально планировали использовать).

Я был бы рад уточнить, если бы не ответил на ваш вопрос.

Изменить: работа с клавишами со стрелками

Хм, кажется странным, что нет QListView сигнала по умолчанию для движения стрелы, но мы можем сделать свой собственный.

(Это почти кажется неуместным для сигналов и режимов работы слотов Qt4)

QListView повторно реализует метод keyPressEvent(self, QKeyEvent), который действует как функция обратного вызова при нажатии определенных клавиш. Подробнее… Мы можем использовать это, чтобы получить нужное ключевое событие (я) и испустить собственный сигнал.

class ArrowableListView(QListView):
    def keyPressEvent(self, keyevent):
        #Maintain original functionality by calling QListView's version
        QListView.keyPressEvent(self, keyevent)

        #QListView.selectedIndexes returns a list of selected cells, I'm just taking the first one here
        idx = self.selectedIndexes()[0]

        #We'll emit a signal that you can connect to your custom handler
        self.emit(SIGNAL("my_signal"), idx)

Как только происходит нажатие клавиши, мы спрашиваем QListView, каковы выбранные индексы (!). Конечно, вы можете выбрать отфильтровать определенные ключи и выберите, следует ли обрабатывать несколько выбранных ячеек (я думаю, вы можете установить режим выбора, когда это невозможно, см. QListView документацию).

Теперь, когда у нас есть выбранные индексы (список QModelIndex), мы передаем первый (QModelIndex) вместе с нашим сигналом. Поскольку мы определяем этот сигнал в python, нам не нужно устанавливать прототип функции; Понятия не имею, плохой ли это стиль.

Теперь все, что вам нужно сделать, это подключить сигнал к обработчику:

self.connect(your_list_view, SIGNAL("my_signal"), handler_slot)

и напишите свой обработчик.

Надеюсь, это не слишком неприятный способ обхода.

person anrope    schedule 25.09.2011
comment
QTableView - это альтернатива QListView, которая позволяет вам динамически изменять количество столбцов, которое вы хотите. - person anrope; 25.09.2011
comment
Хм, нажатие и т. Д. Предназначены только для активации мыши (кроме той, которая срабатывает при нажатии клавиши ввода) - есть слот selectionChanged, но мне это не кажется полезным ..? Раздражающе в Qt 3.3 был сигнал selectionChanged, но теперь его больше нет, и и в QAbstractItemView нет ничего, связанного с выбором - person dbr; 25.09.2011
comment
Я не уверен, что вы получите уведомление об изменении, так что вот уведомление на всякий случай. - person anrope; 25.09.2011
comment
@dbr Теперь вам нужно использовать selectionModel для выбора события, поскольку они были немного более разделены. - person Kaleb Pederson; 27.09.2011