Какую модель для подкласса / представления использовать для списка пользовательских объектов - PullRequest
3 голосов
/ 20 июля 2011

У меня пока недостаточно опыта работы с Qt, чтобы сделать правильный выбор дизайна. Любая помощь опытных программистов на Qt будет очень признательна.
Я пытаюсь выяснить, какую модель для подкласса, какое представление использовать, какой подкласс / расширение делегата мне следует делать ...

Моя проблема похожа на: у меня есть эти зоны, которые я хотел бы отобразить, 1 на строку:

class Zone{

    //inputs
    string country;  //edited with a QComboBox
    string city;     //edited with a QComboBox
    int ageMin;

    //stored result
    int nbInhabitantsOlderThanMin;
}

Вот что я хотел бы сделать, и выбор дизайна каждого требования заставляет меня задуматься:

  • Я хотел бы отобразить список из них (-> QListView )
  • Но для отображения 1 элемента мне нужно несколько столбцов (-> QTableView )
  • Мне бы хотелось, чтобы двойной щелчок по строке вызвал редактирование в пользовательском виджете , поскольку nbInhabitantsOlderThanMin нельзя редактировать, а выбор страны ограничивает список городов, которые можно выбрать в QComboBox (и наоборот в моем реальном примере) (-> Я, вероятно, должен где-то использовать QDataWidgetMapper (или подкласс?) ...)

    Таким образом, в то время как редактирование строки должно происходить в виджете, отображение является простым / не пользовательским, и подклассом делегата (например, QStyledItemDelegate ) (я не уверен в этом) не похоже на правильный способ иметь 1 пользовательский виджет с множеством дочерних виджетов для одновременного редактирования 3 полей.
    Я думаю, что данные для модели предпочли бы подкласс модели QAbstractListModel , но дисплей с множеством столбцов, совместимых с просмотром делегатов по умолчанию, предпочитает QAbstractTableModel ..

Так что я не знаю, какой дизайн выбрать. Любая опытная помощь, соединяющая точки, очень приветствуется:)

Ответы [ 3 ]

5 голосов
/ 21 июля 2011

QDataWidgetMapper - это немного другое. Это способ отображения одного элемента из модели (например, QStandardItemModel) с использованием пользовательских элементов управления. Вы можете прочитать больше об этом здесь , с сопровождающими снимками и примером того, как реализовать один.

Хотя это, конечно, круто, я не думаю, что это то, что вы хотите здесь. Главным образом потому, что вы указали, что хотите просматривать свои элементы в виде списка. Тем не менее, вы можете отобразить все ваши элементы в простом списке, дважды щелкнув по которому откроется диалоговое окно с использованием QDataWidgetMapper. В этом случае все, что вам нужно сделать с QListView / QListWidget, это реализовать событие двойного щелчка.

Тем не менее, мне лично не нравится дополнительное бремя дополнительного окна для пользователя. Я предпочитаю использовать всплывающие окна экономно. Но если вам нравится такой подход, тогда продолжайте. Этот является еще одним примером довольно симпатичного QDataWidgetMapper.

Мой предпочтительный подход по-прежнему заключается в использовании QTableView и предоставлении делегатов для столбцов, которые требуют специального редактирования. Здесь - это отличный обзор всех вещей Модель / Вид. Поэтому, если вы решите использовать QListView или QTableView, это послужит вам хорошим началом. В нем также говорится о том, как вы можете создавать делегатов для редактирования полей по своему усмотрению.

Итак, как вы создаете пользовательский делегат? По сути, вы просто наследуете от QItemDelegate. В приведенной выше ссылке есть несколько примеров, но я выделю несколько важных моментов.

QWidget *ComboBoxDelegate::createEditor(QWidget *parent,
     const QStyleOptionViewItem &/* option */,
     const QModelIndex &index) const
 {
     QComboBox *editor = new QComboBox (parent);
     //  Add items to the combobox here.
     //  You can use the QModelIndex passed above to access the model
     //  Add find out what country was selected, and therefore what cities
     //  need to be listed in the combobox

     return editor;
 }

void ComboBoxDelegate::setEditorData(QWidget *editor,
                                     const QModelIndex &index) const
 {
     int value = index.model()->data(index, Qt::EditRole).toInt();

     QComboBox  *comboBox= static_cast<QComboBox *>(editor);
     int _SelectedItem = // Figure out which is the currently selected index;
     comboBox->setCurrentIndex(_SelectedItem);
 }

void ComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
                                    const QModelIndex &index) const
 {
     QComboBox  *comboBox= static_cast<QComboBox *>(editor);
     comboBox->interpretText();
     int value = comboBox->currentIndex();
     //  Translate the current index to whatever you actually want to
     // set in your model.

     model->setData(index, value, Qt::EditRole);
}

Заполните пробелы, которые я оставил в моем примере, и у вас есть ваш делегат. Теперь, как использовать это в вашем QTableView:

Вы можете установить делегата для определенного столбца вашей таблицы следующим образом:

setItemDelegateForColumn(_ColumnIndex, new ComboBoxDelegate(_YourTableModel));

И, если вы хотите запретить редактирование определенных столбцов:

_YourTableModel->setColumnEditable(_ColumnIndex, false);

Как только вы настроите свою модель, все остальное должно позаботиться о себе.

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

1 голос
/ 20 июля 2011

Во-первых, вы должны создать подкласс QAbstractItemDelegate (или QItemDeleage, что может быть удобнее), где переопределены createEditor, setEditorData и setModelData.

Чем вы должны установить собственный элемент ItemDelegate (см. QAbstractItemView::setItemDelegate).

Как правило, нет разницы, какой виджет использовать для представления данных: это может быть либо QTreeWidet, либо QTreeView, либо QTableWidget, либо QTableView. Обратите внимание, что «виджеты» проще в использовании, чем «представления», но они не такие мощные

1 голос
/ 20 июля 2011

Я только что закончил что-то очень похожее на это в том, что мне нужно было несколько полей для каждого объекта, который я хотел подряд.То, как я это сделал, что сработало очень хорошо, заключалось в создании подкласса QAbstractListmodel и использовании собственного ListItem.Я как бы подделал столбцы, имея собственный делегат и используя некоторый javascript, чтобы выяснить размер самой большой вещи в каждом поле, а затем установил размер столбца на эту ширину.Я думаю, что это самый простой способ сделать это.

Для комментария ниже, зона будет наследоваться от:

class ListItem: public QObject {
    Q_OBJECT

public:
    ListItem(QObject* parent = 0) : QObject(parent) {}
    virtual ~ListItem() {}
    virtual QString id() const = 0;
    virtual QVariant data(int role) const = 0;
    virtual QHash<int, QByteArray> roleNames() const = 0;

signals:
    void dataChanged();
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...