- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在制作一个聊天客户端,并且使用 qml ListView
来显示“聊天室”中的所有消息。
我正在使用派生自 QAbstractListModel
的自己的模型类来存储用户所属的所有房间中的所有消息。
我希望所有消息根据最初发送的时间戳进行排序,最新的消息应显示在 View 的底部,最旧的消息应显示在顶部。
我还希望用户能够根据他们发送的房间来过滤消息。我已经解决了这个问题。
这是我的自定义模型的声明
class MessageModel : public QAbstractListModel
{
public:
enum MessageRoles {
Id = Qt::UserRole + 1,
RoomId = Qt::UserRole + 2,
PersonId = Qt::UserRole + 3,
PersonEmail = Qt::UserRole + 4,
Created = Qt::UserRole + 5,
Text = Qt::UserRole + 6
};
explicit MessageModel(QObject * parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void reset_data(QJsonArray new_data);
void insert_unique_data(QJsonArray new_data);
private:
QList<LocalData::Message> m_data;
};
这是我的模型的实现
MessageModel::MessageModel(QObject *parent) : QAbstractListModel(parent)
{}
int MessageModel::rowCount(const QModelIndex &parent) const
{
return m_data.size();
}
QHash<int, QByteArray> MessageModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[Id] = "id";
roles[RoomId] = "roomId";
roles[PersonId] = "personId";
roles[PersonEmail] = "personEmail";
roles[Created] = "created";
roles[Text] = "messageText";
return roles;
}
QVariant MessageModel::data(const QModelIndex &index, int role) const {
if(!index.isValid())
return QVariant();
if(index.row() >= m_data.size())
return QVariant();
switch (role) {
case Id:
return m_data.at(index.row()).id;
case RoomId:
return m_data.at(index.row()).roomId;
case PersonId:
return m_data.at(index.row()).personId;
case PersonEmail:
return m_data.at(index.row()).personEmail;
case Text:
return m_data.at(index.row()).text;
case Created:
return m_data.at(index.row()).created.toString(Qt::ISODateWithMs);
}
return QVariant();
}
void MessageModel::update_data(QJsonArray new_data)
{
beginResetModel();
m_data.clear();
foreach (const QJsonValue & val, new_data) {
m_data.push_back(LocalData::Message(val.toObject()));
}
endResetModel();
}
void MessageModel::insert_unique_data(QJsonArray new_data)
{
QList<LocalData::Message> temp;
foreach (const QJsonValue & val, new_data) {
auto obj_to_insert = LocalData::Message(val.toObject());
if(!m_data.contains(obj_to_insert))
temp.push_back(obj_to_insert);
}
int begin = rowCount();
int end = rowCount() + temp.size() - 1;
beginInsertRows(QModelIndex(), begin, end);
foreach (const LocalData::Message & msg, temp) {
m_data.push_back(msg);
}
endInsertRows();
}
我想使用QSortFilterProxyModel
对消息进行排序和过滤。我已设法使其根据 RoomId
角色正确过滤消息,但在 Created
角色上正确排序消息时遇到问题。
我使用的代理模型非常简单,我只是尝试重写 lessThan() 函数,如下所示:
bool SortFilterProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
QVariant leftData = sourceModel()->data(source_left);
QVariant rightData = sourceModel()->data(source_right);
if(leftData.type() == QVariant::DateTime)
{
return leftData.toDateTime() < rightData.toDateTime();
}
else {
return leftData.toString() < rightData.toString();
}
}
否则它只是一个普通的QSortFilterProxyModel
。当它被初始化时,我调用以下函数:
m_messageModel = new MessageModel;
m_messageProxyModel = new SortFilterProxyModel;
m_messageProxyModel->setSourceModel(qobject_cast<QAbstractListModel *>(m_messageModel));
m_engine.rootContext()->setContextProperty("messages", m_messageProxyModel);
m_messageProxyModel.setSortRole(MessageModel::Created);
m_messageProxyModel.setDynamicSortFilter(true);
m_messageProxyModel.sort(0, Qt::AscendingOrder);
m_messageModel
、m_messageProxyModel
和 m_engine
是在 main( 中实例化的类中声明的所有成员变量(指针)) )
。m_engine 是一个QQmlApplicationEngine
,它将变量公开给qml。
这是包含带有所有消息的 ListView 的 qml 文件。
import QtQuick 2.0
import QtQuick.Controls 1.4
Rectangle{
property alias messageView: _messagePanelView
Component {
id: _messagePanelDelegate
Item{
id: _messagePanelDelegateItem;
width: root.width * 0.8
height: _messagePanelMessageColumn.height
Column{
id: _messagePanelMessageColumn;
height: children.height;
spacing: 20
Text{ text: "<b>" + personEmail + "</b> <t />" + created; font.pointSize: 7 + Math.log(root.width) }
Text{ text: messageText }
Rectangle{
width: parent.width
height: 20
color: "#FFFFFF"
}
}
}
}
ScrollView{
anchors.fill: parent
ListView {
id: _messagePanelView
height: root.height - 100
model: messages
delegate: _messagePanelDelegate
interactive: true
}
}
}
当用户请求特定“聊天室”中的所有消息时,源模型当前会填充数据。当用户按下按钮时,将调用与此类似的函数。
void sync_messages_and_filter_based_on_roomId(QString roomId)
{
m_messageProxyModel->setFilterRole(MessageModel::RoomId);
m_messageProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
m_messageProxyModel->setFilterRegExp(QRegExp::escape(roomId));
fetch_messages_in_room_from_server_async(roomId);
}
fetch_messages_in_room_from_server_async(roomId);
是一个向服务器请求新消息、接收 JSON 格式的响应负载、创建一个 QJsonArray
对象并调用 void 的函数MessageModel::insert_unique_data(QJsonArray new_data)
所有这些都发生在单独的工作线程中。
第一次调用时,数据实际上按降序排序(最旧的在底部,最新的在顶部)。但是,当第二次调用它时,当服务器有更多数据要提供时,客户端应该将所有新消息作为源模型中的行插入,并让代理模型按升序对其进行排序(最近的在插入新数据后,最旧的在顶部)。
当前模型仅按降序排序,这是第一次将数据插入模型时。但是,一旦模型第一次更新,它就不再对数据进行排序,并且新消息出现在 ListView
的底部而不是顶部,这意味着代理模型已停止对模型进行排序。
Here is an image of the ListView, after inserting a second time. Notice the timestamps This is what happens when I terminate the program, and insert all the messages at once
我想要的结果是让代理模型在每次更新/更改源模型时按升序对消息进行排序(最新的在底部,最旧的在顶部)。这意味着当调用 void MessageModel::insert_unique_data(QJsonArray new_data)
时,我期望新消息出现在底部,最新消息作为最后一条消息。
感谢您花时间阅读我这篇超长的帖子。我只是想介绍所有细节,因为将 C++ 模型暴露给 qml 需要很多步骤。
最佳答案
我的猜测是你的 lessThan
函数什么也没做。
当您调用QVariant leftData = sourceModel()->data(source_left);
时它调用 data
具有角色 Qt::DisplayRole
的功能返回无效的 QVariant
为你的模型。您的if(leftData.type() == QVariant::DateTime)
从来没有 true
.
您应该做的是使用 QDateTime leftTimestamp = m_data.at(source_left.row()).created;
显式获取时间戳source_right
也一样。您的if
那么就没用了,你可以这样做 return leftTimestamp < rightTimeStamp;
或者,如果您想从 QML 而不是 C++ 进行排序和过滤,您可以使用我的 SortFilterProxyModel像这样:
import QtQuick 2.0
import QtQuick.Controls 1.4
import SortFilterProxyModel 0.2
Rectangle{
property alias messageView: _messagePanelView
SortFilterProxyModel {
id: proxyMessageModel
sourceModel: sourceMessageModel // a context property you exposed
filters: ValueFilter {
roleName: "roomId"
value: currentRoomId // a property you could add somewhere
}
sorters : RoleSorter {
roleName: "created"
}
}
Component {
id: _messagePanelDelegate
Item{
id: _messagePanelDelegateItem;
width: root.width * 0.8
height: _messagePanelMessageColumn.height
Column{
id: _messagePanelMessageColumn;
height: children.height;
spacing: 20
Text{ text: "<b>" + personEmail + "</b> <t />" + created; font.pointSize: 7 + Math.log(root.width) }
Text{ text: messageText }
Rectangle{
width: parent.width
height: 20
color: "#FFFFFF"
}
}
}
}
ScrollView{
anchors.fill: parent
ListView {
id: _messagePanelView
height: root.height - 100
model: proxyMessageModel
delegate: _messagePanelDelegate
interactive: true
}
}
}
关于c++ - 使用 QSortFilterProxyModel 对 Qml ListView 的数据进行排序。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45563393/
初学者 android 问题。好的,我已经成功写入文件。例如。 //获取文件名 String filename = getResources().getString(R.string.filename
我已经将相同的图像保存到/data/data/mypackage/img/中,现在我想显示这个全屏,我曾尝试使用 ACTION_VIEW 来显示 android 标准程序,但它不是从/data/dat
我正在使用Xcode 9,Swift 4。 我正在尝试使用以下代码从URL在ImageView中显示图像: func getImageFromUrl(sourceUrl: String) -> UII
我的 Ubuntu 安装 genymotion 有问题。主要是我无法调试我的数据库,因为通过 eclipse 中的 DBMS 和 shell 中的 adb 我无法查看/data/文件夹的内容。没有显示
我正在尝试用 PHP 发布一些 JSON 数据。但是出了点问题。 这是我的 html -- {% for x in sets %}
我观察到两种方法的结果不同。为什么是这样?我知道 lm 上发生了什么,但无法弄清楚 tslm 上发生了什么。 > library(forecast) > set.seed(2) > tts lm(t
我不确定为什么会这样!我有一个由 spring data elasticsearch 和 spring data jpa 使用的类,但是当我尝试运行我的应用程序时出现错误。 Error creatin
在 this vega 图表,如果我下载并转换 flare-dependencies.json使用以下 jq 到 csv命令, jq -r '(map(keys) | add | unique) as
我正在提交一个项目,我必须在其中创建一个带有表的 mysql 数据库。一切都在我这边进行,所以我只想检查如何将我所有的压缩文件发送给使用不同计算机的人。基本上,我如何为另一台计算机创建我的数据库文件,
我有一个应用程序可以将文本文件写入内部存储。我想仔细看看我的电脑。 我运行了 Toast.makeText 来显示路径,它说:/数据/数据/我的包 但是当我转到 Android Studio 的 An
我喜欢使用 Genymotion 模拟器以如此出色的速度加载 Android。它有非常好的速度,但仍然有一些不稳定的性能。 如何从 Eclipse 中的文件资源管理器访问 Genymotion 模拟器
我需要更改 Silverlight 中文本框的格式。数据通过 MVVM 绑定(bind)。 例如,有一个 int 属性,我将 1 添加到 setter 中的值并调用 OnPropertyChanged
我想向 Youtube Data API 提出请求,但我不需要访问任何用户信息。我只想浏览公共(public)视频并根据搜索词显示视频。 我可以在未经授权的情况下这样做吗? 最佳答案 YouTube
我已经设置了一个 Twilio 应用程序,我想向人们发送更新,但我不想回复单个文本。我只是想让他们在有问题时打电话。我一切正常,但我想在发送文本时显示传入文本,以确保我不会错过任何问题。我正在使用 p
我有一个带有表单的网站(目前它是纯 HTML,但我们正在切换到 JQuery)。流程是这样的: 接受用户的输入 --- 5 个整数 通过 REST 调用网络服务 在服务器端运行一些计算...并生成一个
假设我们有一个名为 configuration.js 的文件,当我们查看内部时,我们会看到: 'use strict'; var profile = { "project": "%Projec
这部分是对 Previous Question 的扩展我的: 我现在可以从我的 CI Controller 成功返回 JSON 数据,它返回: {"results":[{"id":"1","Sourc
有什么有效的方法可以删除 ios 中 CBL 的所有文档存储?我对此有疑问,或者,如果有人知道如何从本质上使该应用程序像刚刚安装一样,那也会非常有帮助。我们正在努力确保我们的注销实际上将应用程序设置为
我有一个 Rails 应用程序,它与其他 Rails 应用程序通信以进行数据插入。我使用 jQuery $.post 方法进行数据插入。对于插入,我的其他 Rails 应用程序显示 200 OK。但在
我正在为服务于发布请求的 API 调用运行单元测试。我正在传递请求正文,并且必须将响应作为帐户数据返回。但我只收到断言错误 注意:数据是从 Azure 中获取的 spec.js const accou
我是一名优秀的程序员,十分优秀!