我目前在用QAbstractListModel
填充纸莎草菜单字段或ComboBox的QML材料时遇到问题。
有人知道有一种方法可以显示数据并预定义qml材质的纸莎草纸菜单字段给定值的C ++模型吗?
示例数据库
表域
字段:
这里是使用的类:
**domaine.h**
#ifndef DOMAINE_H
#define DOMAINE_H
#include <QString>
#include "gesprojet_global.h"
class GESPROJETSHARED_EXPORT Domaine
{
public:
explicit Domaine(const QString& name = "" );
int id() const;
void setId(int id);
QString name() const;
void setName(const QString& name);
private:
int mId;
QString mName;
};
#endif // DOMAINE_H
**domaine.cpp**
#include "domaine.h"
Domaine::Domaine(const QString &name) :
mId(-1),
mName(name)
{
}
int Domaine::id() const
{
return mId;
}
void Domaine::setId(int id)
{
mId = id ;
}
QString Domaine::name() const
{
return mName;
}
void Domaine::setName(const QString& name)
{
mName = name;
}
// domaineModel.h
#ifndef DOMAINEMODEL_H
#define DOMAINEMODEL_H
#include <QAbstractListModel>
#include <QHash>
#include <vector>
#include <memory>
#include "gesprojet_global.h"
#include "domaine.h"
#include "databasemanager.h"
class GESPROJETSHARED_EXPORT DomaineModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Roles {
IdRole = Qt::UserRole + 1,
NameRole,
};
DomaineModel(QObject * parent = 0);
QModelIndex addDomaine(const Domaine& domaine);
Q_INVOKABLE void addDomaineFromName(const QString& name);
Q_INVOKABLE void rename(int row, const QString& name);
int rowCount(const QModelIndex& index = QModelIndex()) const override;
Q_INVOKABLE QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex& index, const QVariant& value, int role) override;
Q_INVOKABLE bool removeRows(int row, int count, const QModelIndex& parent) override;
QHash<int, QByteArray> roleNames() const override;
private:
bool isIndexValid(const QModelIndex& index) const;
private:
DatabaseManager& mDb;
std::unique_ptr<std::vector<std::unique_ptr<Domaine>>> mDomaines;
};
#endif // DOMAINEMODEL_H
// domaineModel.cpp
#include "domainemodel.h"
using namespace std;
DomaineModel::DomaineModel(QObject * parent) :
QAbstractListModel (parent),
mDb(DatabaseManager::instance()),
mDomaines(mDb.domaineDao.domaine())
{
}
int DomaineModel::rowCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return mDomaines->size();
}
QVariant DomaineModel::data(const QModelIndex& index, int role) const
{
if(!isIndexValid(index)) {
return QVariant();
}
const Domaine& domaine = *mDomaines->at(index.row());
switch (role) {
case Roles::IdRole:
return domaine.id();
case Roles::NameRole:
case Qt::DisplayRole:
return domaine.name();
default:
return QVariant();
}
}
QHash<int, QByteArray> DomaineModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[Roles::IdRole] = "id";
roles[Roles::NameRole] = "name";
return roles;
}
bool DomaineModel::isIndexValid(const QModelIndex& index) const
{
if (index.row() < 0
|| index.row() >= rowCount()
|| !index.isValid()) {
return false;
}
return true;
}
QModelIndex DomaineModel::addDomaine(const Domaine& domaine)
{
int rowIndex = rowCount();
beginInsertRows(QModelIndex(), rowIndex, rowIndex);
unique_ptr<Domaine> newDomaine(new Domaine(domaine));
mDb.domaineDao.AddDomaine(*newDomaine);
mDomaines->push_back(move(newDomaine));
endInsertRows();
return index(rowIndex, 0);
}
void DomaineModel::addDomaineFromName(const QString& name)
{
addDomaine(Domaine(name));
}
bool DomaineModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
if(!isIndexValid(index)
|| role != Roles::NameRole) {
return false;
}
Domaine& domaine = *mDomaines->at(index.row());
domaine.setName(value.toString());
mDb.domaineDao.updateDomaine(domaine);
emit dataChanged(index, index);
return true;
}
void DomaineModel::rename(int row, const QString& name)
{
setData(index(row), name, Roles::NameRole);
}
bool DomaineModel::removeRows(int row, int count, const QModelIndex& parent)
{
if (row < 0
|| row >= rowCount()
|| count < 0
|| (row + count) > rowCount()) {
return false;
}
beginRemoveRows(parent, row, row + count -1);
int countleft = count;
while (countleft--) {
const Domaine& domaine = *mDomaines->at(row + countleft);
mDb.domaineDao.removeDomaine(domaine.id());
}
mDomaines->erase(mDomaines->begin() + row,
mDomaines->begin() + row + count);
endRemoveRows();
return true;
}
// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QQuickView>
#include "domainemodel.h"
#include "typeassocmodel.h"
#include "associationmodel.h"
#include "chefmodel.h"
#include "lieuactionmodel.h"
#include "partenairemodel.h"
#include "projetmodel.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
DomaineModel domaineModel; // my model concerned
TypeAssocModel typeAssocModel;
AssociationModel associationModel;
ChefModel chefModel;
LieuActionModel lieuActionModel;
PartenaireModel partenaireModel;
ProjetModel projetModel;
QQmlApplicationEngine engine;
QQmlContext * context = engine.rootContext();
context->setContextProperty("domaineModel", &domaineModel);
context->setContextProperty("typeAssocModel", &typeAssocModel);
context->setContextProperty("associationModel", &associationModel);
context->setContextProperty("chefModel", &chefModel);
context->setContextProperty("lieuActionModel", &lieuActionModel);
context->setContextProperty("partenaireModel", &partenaireModel);
context->setContextProperty("projetModel", &projetModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
// MenuFied.qml (part of qml-material)
import QtQuick 2.4
import QtQuick.Layouts 1.1
import Material 0.3
import Material.ListItems 0.1
/*!
\qmltype MenuField
\inqmlmodule Material
\brief A input field similar to a text field but that opens a dropdown menu.
*/
Item {
id: field
implicitHeight: hasHelperText ? helperTextLabel.y + helperTextLabel.height + 4 * Units.dp
: underline.y + 8 * Units.dp
implicitWidth: spinBoxContents.implicitWidth
activeFocusOnTab: true
property color accentColor: Theme.accentColor
property color errorColor: "#F44336"
property alias model: listView.model
property string textRole
readonly property string selectedText: (listView.currentItem) ? listView.currentItem.text : ""
property alias selectedIndex: listView.currentIndex
property int maxVisibleItems: 4
property alias placeholderText: fieldPlaceholder.text
property alias helperText: helperTextLabel.text
property bool floatingLabel: false
property bool hasError: false
property bool hasHelperText: helperText.length > 0
readonly property rect inputRect: Qt.rect(spinBox.x, spinBox.y, spinBox.width, spinBox.height)
signal itemSelected(int index)
Ink {
anchors.fill: parent
onClicked: {
listView.positionViewAtIndex(listView.currentIndex, ListView.Center)
var offset = listView.currentItem.itemLabel.mapToItem(menu, 0, 0)
menu.open(label, 0, -offset.y)
}
}
Item {
id: spinBox
height: 24 * Units.dp
width: parent.width
y: {
if(!floatingLabel)
return 16 * Units.dp
if(floatingLabel && !hasHelperText)
return 40 * Units.dp
return 28 * Units.dp
}
RowLayout {
id: spinBoxContents
height: parent.height
width: parent.width + 5 * Units.dp
Label {
id: label
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
text: (listView.currentItem) ? listView.currentItem.text : ""
style: "subheading"
elide: Text.ElideRight
}
Icon {
id: dropDownIcon
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
Layout.preferredWidth: 24 * Units.dp
Layout.preferredHeight: 24 * Units.dp
name: "navigation/arrow_drop_down"
size: 24 * Units.dp
}
}
Dropdown {
id: menu
anchor: Item.TopLeft
width: spinBox.width
//If there are more than max items, show an extra half item so
// it's clear the user can scroll
height: Math.min(maxVisibleItems*48 * Units.dp + 24 * Units.dp, listView.contentHeight)
ListView {
id: listView
width: menu.width
height: count > 0 ? menu.height : 0
interactive: true
delegate: Standard {
id: delegateItem
text: textRole ? model[textRole] : modelData
onClicked: {
itemSelected(index)
listView.currentIndex = index
menu.close()
}
}
}
Scrollbar {
flickableItem: listView
}
}
}
Label {
id: fieldPlaceholder
text: field.placeholderText
visible: floatingLabel
font.pixelSize: 12 * Units.dp
anchors.bottom: spinBox.top
anchors.bottomMargin: 8 * Units.dp
color: Theme.light.hintColor
}
Rectangle {
id: underline
color: field.hasError ? field.errorColor : field.activeFocus ? field.accentColor : Theme.light.hintColor
height: field.activeFocus ? 2 * Units.dp : 1 * Units.dp
anchors {
left: parent.left
right: parent.right
top: spinBox.bottom
topMargin: 8 * Units.dp
}
Behavior on height {
NumberAnimation { duration: 200 }
}
Behavior on color {
ColorAnimation { duration: 200 }
}
}
Label {
id: helperTextLabel
anchors {
left: parent.left
right: parent.right
top: underline.top
topMargin: 4 * Units.dp
}
visible: hasHelperText
font.pixelSize: 12 * Units.dp
color: field.hasError ? field.errorColor : Qt.darker(Theme.light.hintColor)
Behavior on color {
ColorAnimation { duration: 200 }
}
}
}
// AjouterAssociation.qml
import QtQuick 2.4
import QtQuick.Layouts 1.1
import Material 0.2
import Material.ListItems 0.1 as ListItem
import Material.Extras 0.1
Item {
property int domaineId
// property int typeId
View {
anchors.fill: parent
anchors.margins: dp(32)
width: dp(350)
height: column.implicitHeight + dp(32)
elevation: 1
radius: dp(2)
ColumnLayout {
id: column
anchors {
fill: parent
topMargin: dp(16)
bottomMargin: dp(16)
}
Label {
id: titleLabel
anchors {
fill: parent
leftMargin: dp(100)
}
style: "title"
text: "Ajout Association"
}
Item {
Layout.fillWidth: true
Layout.preferredHeight: dp(8)
}
ListItem.Standard {
action: Icon {
anchors.centerIn: parent
name: "action/settings"
}
Icon {
anchors.centerIn: parent
name: "action/account_circle"
}
content: RowLayout {
anchors.centerIn: parent
width: parent.width
TextField {
id: code
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 0.4 * parent.width
placeholderText: "Code"
}
TextField {
id:name
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 0.4 * parent.width
placeholderText: "Nom"
}
}
}
ListItem.Standard {
action: Icon {
anchors.centerIn: parent
name: "action/account_circle"
}
content: RowLayout {
anchors.centerIn: parent
width: parent.width
TextField {
id: adresse
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 0.4 * parent.width
placeholderText: "Adresse"
}
TextField {
id:telephone
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 0.4 * parent.width
placeholderText: "Telephone"
}
}
}
ListItem.Standard {
action: Icon {
anchors.centerIn: parent
name: "communication/email"
}
Icon {
anchors.centerIn: parent
name: ""
}
content: RowLayout {
anchors.centerIn: parent
width: parent.width
TextField {
id:email
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 0.4 * parent.width
placeholderText: "Email"
}
TextField {
id: codePostal
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 0.4 * parent.width
placeholderText: "Code Postal"
}
}
}
ListItem.Standard {
content: RowLayout {
anchors.centerIn: parent
width: parent.width
Text {
id: textDomaine
text: qsTr("Domaine")
}
MenuField {
id: domaine
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 0.3 * parent.width
model: domaineModel
textRole: "name"
//domaineId:
}
Text {
id: textType
text: qsTr("Type Association")
}
MenuField {
id: typeAssoc
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 0.3 * parent.width
model: typeAssocModel
textRole: "libelle"
selectedText: "libelle"
typeId: typeAssocModel.typeForLibelle(selectedText)
}
}
}
Item {
Layout.fillWidth: true
Layout.preferredHeight: dp(8)
}
RowLayout {
Layout.alignment: Qt.AlignRight
spacing: dp(8)
anchors {
right: parent.right
margins: dp(16)
}
Button {
text: "Annuler"
textColor: Theme.primaryColor
onClicked: {
code.text = ""
name.text = ""
adresse.text = ""
telephone.text = ""
email.text = ""
codePostal.text = ""
}
}
Button {
text: "Valider"
textColor: Theme.primaryColor
onClicked: associationModel.add(code.text, name.text, adresse.text, telephone.text, email.text, codePostal.text, 1, 1)
}
}
}
}
}