在我的测试数据库中,我有一个名为users的表,它表示可登录的用户。现在,我已经通过Qt / C ++成功连接到数据库,向QML公开了类(也没有问题),设置了QML ListView
以向用户显示自定义模型和委托(文件main.qml
),以及在我运行应用程序时,在ListView
中显示了五个项目。现在,ListView's
代表由“图像”和“文本”部分组成(可记录用户图像的“图像”部分,它作为mysql数据库中的BLOB驻留,而用户名的“文本”部分,也作为mysql数据库中的VARCHAR驻留)–这两个字段位于同一表中命名用户):
import QtQuick 2.3
Item
{
id: uePeopleItemDelegate
property Image uePersonImage
property string uePersonName
width: 256
height: 256
antialiasing: true
clip: true
Rectangle
{
id: ueRectangleMain
color: "#000000"
radius: 16
anchors.fill: parent
antialiasing: true
border.color: "#ffffff"
border.width: 4
clip: true
//opacity: 0.7
Grid
{
antialiasing: true
anchors.rightMargin: 12
anchors.leftMargin: 12
anchors.bottomMargin: 12
anchors.topMargin: 12
anchors.fill: parent
spacing: 4
rows: 2
columns: 1
}
Row
{
id: ueRowImage
anchors.rightMargin: 12
anchors.leftMargin: 12
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
anchors.top: parent.top
anchors.bottomMargin: 48
anchors.topMargin: 12
}
Image
{
id: uePersonleImage
x: 12
y: 12
width: 232
height: 196
antialiasing: true
fillMode: Image.PreserveAspectFit
source: ""
}
Column
{
id: ueColumnPeopleInfo
x: 12
y: 214
width: 232
height: 30
spacing: 0
}
Text
{
id: ueTextPersonName
x: 12
y: 214
width: 232
height: 30
color: "#ffffff"
text: uePersonName
font.bold: true
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 16
}
}
}
这是代表的屏幕截图:
如果我在数据库中删除/添加用户,则代表的数量会根据表用户记录的数量而变化,这非常有效。但是现在我有两个问题:在
main.qml
中,我实例化了这个ListView
:import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtMultimedia 5.0
import QtQuick.Layouts 1.0
import QtTest 1.1
import "gui/delegates"
ApplicationWindow
{
id: ueWindowMain
title: qsTr("TestApp")
width: Screen.desktopAvailableWidth
height: Screen.desktopAvailableWidth
visible: true
opacity: 1.0
contentOrientation: Qt.LandscapeOrientation
color: "black"
ListView
{
id: uePeopleListView
snapMode: ListView.SnapToItem
highlightRangeMode: ListView.ApplyRange
anchors.right: parent.right
anchors.rightMargin: 0
anchors.bottom: parent.top
anchors.bottomMargin: -128
anchors.left: parent.left
anchors.leftMargin: 0
anchors.top: parent.top
anchors.topMargin: 0
orientation: ListView.Horizontal
flickableDirection: Flickable.HorizontalFlick
antialiasing: true
spacing: 16
delegate: UePeopleItemDelegate
{
id: uePersonDelegate
uePersonImage: "" // Q1: How do I retreive image (user image) from database?
uePersonName: "" // Q2: How do I retreive text (user name) from database?
}
model: uePeopleModel
}
}
如何检索数据(图像和文本)以在第49和50行的委托中显示它?这也是我的模型类的标题和实现:
#ifndef UEPEOPLEMODEL_H
#define UEPEOPLEMODEL_H
#include <QImage>
#include <QVariant>
#include <QStringList>
#include <QDebug>
#include <QHash>
#include <QByteArray>
#include <QtSql/QSqlError>
#include <QtSql/QSqlQueryModel>
#include <QtSql/QSqlRecord>
#include <QModelIndex>
#include "../settings/uedefaults.h"
class UePeopleModel : public QSqlQueryModel
{
Q_OBJECT
private:
QHash<int, QByteArray> m_ueRoleNames;
void ueGenerateRoleNames();
public:
UePeopleModel(QObject *parent=0);
~UePeopleModel();
QVariant data(const QModelIndex &index,
int role) const Q_DECL_OVERRIDE;
void ueRefresh();
inline QHash<int, QByteArray> ueRoleNames() const
{ return this->m_ueRoleNames; }
};
#endif // UEPEOPLEMODEL_H
和实现:
#include "uepeoplemodel.h"
UePeopleModel::UePeopleModel(QObject* parent)
: QSqlQueryModel(parent)
{
QSqlDatabase db;
if(!QSqlDatabase::connectionNames().contains(UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE,
Qt::CaseInsensitive))
{
db=QSqlDatabase::addDatabase(UePosDatabase::DATABASE_DRIVER,
UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE);
} // if
db.setHostName(/*this->uePosSettings()->ueDbHostname()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_HOSTNAME);
db.setDatabaseName(/*this->uePosSettings()->ueDbName()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_NAME);
db.setUserName(/*this->uePosSettings()->ueDbUser()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_USERNAME);
db.setPassword(/*this->uePosSettings()->ueDbPassword()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_PASSWORD);
if(db.open())
{
this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE,
db);
this->ueGenerateRoleNames();
}
else
{
qDebug() << db.lastError().text();
}
} // default constructor
UePeopleModel::~UePeopleModel()
{
} // default destructor
QVariant UePeopleModel::data(const QModelIndex &index,
int role) const
{
QVariant value;
if(role<Qt::UserRole)
{
value=QSqlQueryModel::data(index,
role);
}
else
{
int iColumnIndex=role-Qt::UserRole-1;
QModelIndex modelIndex=this->index(index.row(),
iColumnIndex);
value=QSqlQueryModel::data(modelIndex,
Qt::DisplayRole);
} // if
return value;
// QVariant value=QSqlQueryModel::data(index,
// role);
// if(value.isValid()&&role==Qt::DisplayRole)
// {
// switch(index.column())
// {
// case UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_ID:
// return value.toInt();
// case UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_NAME:
// return value.toString();
// case UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_APPPASSWORD:
// return value.toString();
// case UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_CARD:
// return value.toString();
// case UePosDatabase::UeTableIndexes::UeTablePeople::INDEX_IMAGE:
// {
// QImage image;
// image.loadFromData(value.toByteArray());
// return image;
// } // case
// default:
// return value;
// } // switch
// } // if
// return QVariant();
} // data
void UePeopleModel::ueRefresh()
{
this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE);
} // ueRefresh
void UePeopleModel::ueGenerateRoleNames()
{
this->ueRoleNames().clear();
for(int iIndex=0; iIndex<this->record().count(); iIndex++)
{
this->ueRoleNames().insert(Qt::UserRole+1+iIndex,
this->record().fieldName(iIndex).toUtf8());
} // for
} // ueGenerateRoleNames
最佳答案
默认的QML图像提供程序只能使用URL或文件路径。如果要从C ++图像类(例如QPixmap
或QImage
)加载QML图像,则必须继续并实现自己的图像提供程序。我已经描述了one possible implementation strategy here:
之后,它非常简单,data()
方法将不会返回包装在QVariant
中的图像,而只是返回针对自定义图像提供程序的自定义图像URL,这就是您将在QML委托中使用的。自然,在数据库内部,您仍然会有一个blob,并且仍将使用fromData()
方法构造图像,但是图像提供程序将用于将自定义图像源字符串与实际图像相关联。自然,您必须找到一种方法来控制实际图像的生命周期,以免发生内存泄漏。我的建议是从上面列出的答案中实现类似Pixmap
的项目,并将其作为代表的一部分-这样,当不再需要该图像时,该图像将被删除。但是,您还需要为setData()
实现Pixmap
并以文本形式传递QPixmap
指针并将其存储在pix
中。
不将映像存储在数据库中可能会更容易,更明智,但是将其作为常规文件,仅将其相对路径存储在数据库中,将为您节省一些麻烦。至于“如何检索数据”问题-我会说去那里,实际上read the documentation ...