【问题标题】:Which model to subclass / view to use for a list of custom objects将哪个模型子类化/视图用于自定义对象列表
【发布时间】:2011-07-20 15:53:17
【问题描述】:

我还没有足够的 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..

所以我真的不知道该选择哪种设计。非常欢迎任何有经验的帮助来连接点:)

【问题讨论】:

    标签: c++ model-view-controller qt qt4


    【解决方案1】:

    QDataWidgetMapper 是一个稍微不同的东西。这是一种使用自定义控件从模型(例如 QStandardItemModel)中显示一个项目的方法。您可以阅读更多关于它的信息here,并附上快照和如何实现快照的示例。

    虽然它确实很酷,但我认为这不是您想要的。主要是因为您指定要以列表格式查看项目。但是,您可以在一个简单的列表中显示所有项目,双击它将使用 QDataWidgetMapper 打开一个对话框。在这种情况下,您需要对 QListView/QListWidget 做的就是实现双击事件。

    不过,我个人不喜欢额外窗口给用户带来的额外负担。我更喜欢谨慎使用弹出窗口。但是,如果您喜欢这种方法,请继续。 This 是另一个非常不错的 QDataWidgetMapper 示例。

    我的首选方法仍然是使用 QTableView,并为需要专门编辑的列提供委托。 Here 是模型/视图的所有东西的一个很好的演练。所以如果你决定使用 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);
    

    设置好模型后,其他一切都应自行处理。

    希望对您有所帮助。

    【讨论】:

    • Liz,这非常有帮助;非常感谢你!
    【解决方案2】:

    首先,您应该继承QAbstractItemDelegate(或QItemDeleage,这可能更方便),其中重新实现createEditorsetEditorDatasetModelData

    然后,您应该设置自己的 itemDelegate(请参阅QAbstractItemView::setItemDelegate)。

    通常没有区别,使用什么小部件来呈现数据:它可以是QTreeWidet,或QTreeView,或QTableWidget,或QTableView。请注意,“widgets”比“views”更容易使用,但没有那么强大

    【讨论】:

    • 感谢您的帮助。您能否进一步解释一下这种设计如何处理多列?另外,您的建议是否适用于 QDataWidgetMapper 或者您不推荐它?
    【解决方案3】:

    我刚刚完成了与此非常相似的事情,因为我需要为每个我想要连续的对象的多个字段。我这样做的方式非常好,就是继承 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();
    };
    

    【讨论】:

    • 感谢您的意见。自定义 ListItem 到底是什么意思? class Zone 会从您的模型中派生出什么?
    • 一个项目必须实现一些东西,所以我创建了一个区域可以继承的类。在我的答案中发布了代码。
    猜你喜欢
    • 1970-01-01
    • 2012-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多