1
0
mirror of https://github.com/jaredtao/TaoQuick.git synced 2025-01-31 21:22:58 +08:00

update table performance

This commit is contained in:
jared 2020-11-08 21:53:28 +08:00
parent 78b73b1160
commit 9d09e37149
12 changed files with 235 additions and 175 deletions

View File

@ -12,23 +12,17 @@ class TAO_API TaoListItemBase : public QObject
public:
explicit TaoListItemBase(QObject *parent = nullptr);
~TaoListItemBase() override;
bool isChecked() const
{
return mIsChecked;
}
bool isChecked() const { return mIsChecked; }
bool isSelected() const
{
return mIsSelected;
}
bool isSelected() const { return mIsSelected; }
bool isVisible() const
bool isVisible() const { return mIsVisible; }
bool isAlternate() const { return mIsAlternate; }
// Model call this for search. return true if contents match key, others return false.
virtual bool match(const QString &key)
{
return mIsVisible;
}
bool isAlternate() const
{
return mIsAlternate;
Q_UNUSED(key)
return true;
}
public slots:
void setIsChecked(bool isChecked)
@ -59,8 +53,7 @@ public slots:
}
void setIsAlternate(bool isAlternate)
{
if (mIsAlternate == isAlternate)
{
if (mIsAlternate == isAlternate) {
return;
}
mIsAlternate = isAlternate;

View File

@ -1,52 +1,43 @@
#include "TaoListModel.h"
#include <algorithm>
TaoListModel::TaoListModel(QObject *parent)
: TaoListModelBase(parent)
#include <QDebug>
TaoListModel::TaoListModel(QObject *parent) : TaoListModelBase(parent)
{
connect(&mSearchTimer, &QTimer::timeout, this, &TaoListModel::onSearch);
mSearchTimer.setInterval(300);
mSearchTimer.setSingleShot(true);
}
TaoListModel::~TaoListModel()
{
}
TaoListModel::~TaoListModel() { }
void TaoListModel::check(int row, bool checked)
{
if (row < 0 || row >= mDatas.size())
{
if (row < 0 || row >= mDatas.size()) {
return;
}
mDatas.at(row)->setIsChecked(checked);
if (mDatas.at(row)->isSelected())
{
for (const auto &obj : mDatas)
{
if (obj->isVisible() && obj->isSelected())
{
if (mDatas.at(row)->isSelected()) {
for (const auto &obj : mDatas) {
if (obj->isVisible() && obj->isSelected()) {
obj->setIsChecked(checked);
}
}
}
bool allCheck = true;
if (checked == false || mDatas.count() <= 0)
{
if (checked == false || mDatas.count() <= 0) {
allCheck = false;
}
else
{
for (const auto &obj : mDatas)
{
if (obj->isVisible() && false == obj->isChecked())
{
} else {
for (const auto &obj : mDatas) {
if (obj->isVisible() && false == obj->isChecked()) {
allCheck = false;
break;
}
}
}
if (mAllChecked != allCheck)
{
if (mAllChecked != allCheck) {
mAllChecked = allCheck;
emit allCheckedChanged(mAllChecked);
}
@ -54,10 +45,8 @@ void TaoListModel::check(int row, bool checked)
}
void TaoListModel::setAllChecked(bool allChecked)
{
for (const auto &obj : mDatas)
{
if (obj->isVisible())
{
for (const auto &obj : mDatas) {
if (obj->isVisible()) {
obj->setIsChecked(allChecked);
}
}
@ -71,33 +60,28 @@ void TaoListModel::setAllChecked(bool allChecked)
void TaoListModel::search(const QString &searchKey)
{
mSearchkey = searchKey.simplified();
for (const auto &obj : mDatas)
{
if (mVisibleCallback && false == mVisibleCallback(obj))
{
obj->setIsVisible(false);
continue;
}
bool found = false;
for (const auto &role : mHeaderRoles)
{
if (obj->property(role.toStdString().c_str()).toString().contains(mSearchkey))
{
found = true;
break;
}
}
obj->setIsVisible(found);
}
updateCalcInfo();
mSearchTimer.start(300);
}
void TaoListModel::onSearch()
{
using namespace std::chrono;
auto c1 = high_resolution_clock::now();
for (const auto &obj : mDatas) {
obj->setIsVisible(obj->match(mSearchkey));
}
auto c2 = std::chrono::high_resolution_clock::now();
updateCalcInfo();
auto c3 = std::chrono::high_resolution_clock::now();
auto cost1 = std::chrono::duration_cast<std::chrono::milliseconds>(c2 - c1).count();
auto cost2 = std::chrono::duration_cast<std::chrono::milliseconds>(c3 - c2).count();
qWarning() << cost1 << cost2;
}
void TaoListModel::deselectAll()
{
for (const auto &obj : mDatas)
{
if (obj->isVisible())
{
for (const auto &obj : mDatas) {
if (obj->isVisible()) {
obj->setIsSelected(false);
}
}
@ -106,10 +90,8 @@ void TaoListModel::deselectAll()
void TaoListModel::selectAll()
{
for (const auto &obj : mDatas)
{
if (obj->isVisible())
{
for (const auto &obj : mDatas) {
if (obj->isVisible()) {
obj->setIsSelected(true);
}
}
@ -118,8 +100,7 @@ void TaoListModel::selectAll()
bool TaoListModel::isSelected(int row) const
{
if (row < 0 || row >= mDatas.size())
{
if (row < 0 || row >= mDatas.size()) {
return false;
}
return mDatas.at(row)->isSelected();
@ -127,8 +108,7 @@ bool TaoListModel::isSelected(int row) const
void TaoListModel::select(int row)
{
if (row < 0 || row >= mDatas.size())
{
if (row < 0 || row >= mDatas.size()) {
return;
}
mDatas.at(row)->setIsSelected(true);
@ -137,8 +117,7 @@ void TaoListModel::select(int row)
void TaoListModel::deselect(int row)
{
if (row < 0 || row >= mDatas.size())
{
if (row < 0 || row >= mDatas.size()) {
return;
}
mDatas.at(row)->setIsSelected(false);
@ -149,8 +128,7 @@ void TaoListModel::selectRange(int from, int to)
{
int minRow = qMin(from, to);
int maxRow = qMax(from, to);
for (int i = 0; i < mDatas.size(); ++i)
{
for (int i = 0; i < mDatas.size(); ++i) {
mDatas.at(i)->setIsSelected(mDatas.at(i)->isVisible() && minRow <= i && i <= maxRow);
}
updateSelectedCount();
@ -158,22 +136,17 @@ void TaoListModel::selectRange(int from, int to)
void TaoListModel::selectSingle(int row)
{
for (int i = 0; i < mDatas.size(); ++i)
{
for (int i = 0; i < mDatas.size(); ++i) {
mDatas.at(i)->setIsSelected(i == row);
}
updateSelectedCount();
}
void TaoListModel::doPress(int row, bool shift, bool ctrl, bool outRange)
{
if (outRange)
{
if (outRange) {
row = mDatas.size();
}
else
{
if (row < 0 || row >= mDatas.size())
{
} else {
if (row < 0 || row >= mDatas.size()) {
return;
}
}
@ -181,7 +154,7 @@ void TaoListModel::doPress(int row, bool shift, bool ctrl, bool outRange)
mIsPressed = true;
if (ctrl) {
mLastPressedRow = row;
if(isSelected(mLastPressedRow)) {
if (isSelected(mLastPressedRow)) {
deselect(mLastPressedRow);
} else {
select(mLastPressedRow);
@ -195,15 +168,11 @@ void TaoListModel::doPress(int row, bool shift, bool ctrl, bool outRange)
}
void TaoListModel::doMove(int row, bool outRange)
{
if (outRange)
{
if (outRange) {
row = mDatas.size();
}
else
{
} else {
if (row < 0 || row >= mDatas.size())
{
if (row < 0 || row >= mDatas.size()) {
return;
}
}
@ -219,59 +188,49 @@ void TaoListModel::doRelease()
void TaoListModel::sortByRole()
{
const static auto addRessStr = QStringLiteral("address");
if (mDatas.isEmpty())
{
if (mDatas.isEmpty()) {
return;
}
const auto &addressCallback = mSortCallbacks.value(addRessStr);
QList<TaoListItemBase *> copyObjs;
if (mSortRole == addRessStr)
{
if (addressCallback)
{
if (mSortRole == addRessStr) {
if (addressCallback) {
copyObjs = mDatas;
if (mSortOrder == Qt::SortOrder::AscendingOrder)
{
if (mSortOrder == Qt::SortOrder::AscendingOrder) {
std::sort(copyObjs.begin(), copyObjs.end(), addressCallback);
}
else
{
std::sort(copyObjs.begin(), copyObjs.end(), [=](TaoListItemBase *obj1, TaoListItemBase *obj2) -> bool { return addressCallback(obj2, obj1); });
} else {
std::sort(copyObjs.begin(), copyObjs.end(),
[=](TaoListItemBase *obj1, TaoListItemBase *obj2) -> bool {
return addressCallback(obj2, obj1);
});
}
beginResetModel();
mDatas = copyObjs;
endResetModel();
}
}
else
{
if (addressCallback)
{
} else {
if (addressCallback) {
copyObjs = mDatas;
if (mSortOrder == Qt::SortOrder::AscendingOrder)
{
if (mSortOrder == Qt::SortOrder::AscendingOrder) {
std::sort(copyObjs.begin(), copyObjs.end(), addressCallback);
}
else
{
std::sort(copyObjs.begin(), copyObjs.end(), [=](TaoListItemBase *obj1, TaoListItemBase *obj2) -> bool { return addressCallback(obj2, obj1); });
} else {
std::sort(copyObjs.begin(), copyObjs.end(),
[=](TaoListItemBase *obj1, TaoListItemBase *obj2) -> bool {
return addressCallback(obj2, obj1);
});
}
}
if (mSortCallbacks.value(mSortRole))
{
if (copyObjs.isEmpty())
{
if (mSortCallbacks.value(mSortRole)) {
if (copyObjs.isEmpty()) {
copyObjs = mDatas;
}
if (mSortOrder == Qt::SortOrder::AscendingOrder)
{
if (mSortOrder == Qt::SortOrder::AscendingOrder) {
std::sort(copyObjs.begin(), copyObjs.end(), mSortCallbacks.value(mSortRole));
}
else
{
std::sort(copyObjs.begin(), copyObjs.end(), [=](TaoListItemBase *obj1, TaoListItemBase *obj2) -> bool {
} else {
std::sort(copyObjs.begin(), copyObjs.end(),
[=](TaoListItemBase *obj1, TaoListItemBase *obj2) -> bool {
return mSortCallbacks.value(mSortRole)(obj2, obj1);
});
}
@ -314,7 +273,7 @@ void TaoListModel::updateAllCheck()
{
bool allCheck = true;
if (!mDatas.empty()) {
allCheck = std::all_of(mDatas.begin(), mDatas.end(), [](TaoListItemBase *obj){
allCheck = std::all_of(mDatas.begin(), mDatas.end(), [](TaoListItemBase *obj) {
return obj->isVisible() && obj->isChecked();
});
}
@ -327,15 +286,14 @@ void TaoListModel::updateAllCheck()
void TaoListModel::updateVisibleCount()
{
int count = std::count_if(mDatas.begin(), mDatas.end(), [](TaoListItemBase *obj){
return obj->isVisible();
});
int count = std::count_if(mDatas.begin(), mDatas.end(),
[](TaoListItemBase *obj) { return obj->isVisible(); });
setVisibledCount(count);
}
void TaoListModel::updateSelectedCount()
{
int count = std::count_if(mDatas.begin(), mDatas.end(), [](TaoListItemBase *obj){
int count = std::count_if(mDatas.begin(), mDatas.end(), [](TaoListItemBase *obj) {
return obj->isVisible() && obj->isSelected();
});
setSelectedCount(count);
@ -343,7 +301,7 @@ void TaoListModel::updateSelectedCount()
void TaoListModel::updateCheckedCount()
{
int count = std::count_if(mDatas.begin(), mDatas.end(), [](TaoListItemBase *obj){
int count = std::count_if(mDatas.begin(), mDatas.end(), [](TaoListItemBase *obj) {
return obj->isVisible() && obj->isChecked();
});
setCheckedCount(count);
@ -351,10 +309,8 @@ void TaoListModel::updateCheckedCount()
void TaoListModel::updateAlternate()
{
bool alter = false;
for (const auto &obj : mDatas)
{
if (obj->isVisible())
{
for (const auto &obj : mDatas) {
if (obj->isVisible()) {
obj->setIsAlternate(alter);
alter = !alter;
}

View File

@ -3,6 +3,7 @@
#include "TaoListModelBase.hpp"
#include "TaoListItemBase.h"
#include "TaoCommonGlobal.h"
#include <QTimer>
class TAO_API TaoListModel : public TaoListModelBase<TaoListItemBase *>
{
Q_OBJECT
@ -17,9 +18,10 @@ class TAO_API TaoListModel : public TaoListModelBase<TaoListItemBase *>
Q_PROPERTY(QString sortRole READ sortRole WRITE setSortRole NOTIFY sortRoleChanged)
public:
using Super = TaoListModelBase<TaoListItemBase *>;
explicit TaoListModel(QObject *parent = nullptr);
~TaoListModel() override;
Q_INVOKABLE QVariant data(int row) const { return Super::data(row); }
//[begin] check
bool allChecked() const { return mAllChecked; }
Q_INVOKABLE void check(int row, bool checked);
@ -27,9 +29,6 @@ public:
//[begin] search. control visible
Q_INVOKABLE void search(const QString &searchKey);
//控制显示隐藏的回调。返回true则show返回false则hide
using VisibleCallback = std::function<bool(TaoListItemBase *)>;
void setVisibleFilter(const VisibleCallback &callback) { mVisibleCallback = callback; }
//[end] search
//[begin] select
@ -101,7 +100,8 @@ signals:
void sortRoleChanged(const QString &sortRole);
void signalUpdateCalcCount();
private slots:
void onSearch();
private:
void updateAllCheck();
void updateVisibleCount();
@ -121,5 +121,5 @@ private:
QString mSortRole;
QMap<QString, SortCallback> mSortCallbacks;
QString mSearchkey;
VisibleCallback mVisibleCallback;
QTimer mSearchTimer;
};

View File

@ -13,8 +13,9 @@ public:
public:
//[begin] query data
int rowCount(const QModelIndex &parent) const override;
Q_INVOKABLE QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Q_INVOKABLE QVariant data(int row, int role = Qt::DisplayRole) const;
QVariant data(int row) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
//[end] query data
//[begin] reset data
@ -80,18 +81,9 @@ QVariant TaoListModelBase<T>::data(const QModelIndex &index, int role) const
return {};
}
template<class T>
QVariant TaoListModelBase<T>::data(int row, int role) const
QVariant TaoListModelBase<T>::data(int row) const
{
if (row < 0 || row >= mDatas.size()) {
return {};
}
if (role == Qt::DisplayRole || role == Qt::EditRole) {
auto data = mDatas.at(row);
return QVariant::fromValue(data);
}
return {};
data(index(row), Qt::DisplayRole);
}
template<class T>
void TaoListModelBase<T>::resetData(const QList<T> &datas)
@ -106,7 +98,11 @@ void TaoListModelBase<T>::resetData(const QList<T> &datas)
template<class T>
void TaoListModelBase<T>::append(const QList<T> &datas)
{
beginInsertRows({}, mDatas.count(), mDatas.count());
if (datas.count() <= 0)
{
return;
}
beginInsertRows({}, mDatas.count(), mDatas.count() + datas.count() -1);
mDatas.append(datas);
endInsertRows();
updateCalcInfo();
@ -114,7 +110,7 @@ void TaoListModelBase<T>::append(const QList<T> &datas)
template<class T>
void TaoListModelBase<T>::prepend(T data)
{
beginInsertRows({}, 0, 0);
beginInsertRows({}, 0, 1);
mDatas.prepend(data);
endInsertRows();
updateCalcInfo();
@ -122,10 +118,10 @@ void TaoListModelBase<T>::prepend(T data)
template<class T>
void TaoListModelBase<T>::insert(int row, const QList<T> &datas)
{
if (row < 0 || row >= mDatas.size()) {
if (row < 0 || row > mDatas.size()) {
return;
}
beginInsertRows({}, row, row);
beginInsertRows({}, row, row + datas.count() - 1);
int srow = row;
for (const auto &obj : datas) {
mDatas.insert(srow, obj);
@ -137,7 +133,11 @@ void TaoListModelBase<T>::insert(int row, const QList<T> &datas)
template<class T>
void TaoListModelBase<T>::clear()
{
beginRemoveRows({}, 0, mDatas.count());
if (mDatas.count() <= 0)
{
return;
}
beginRemoveRows({}, 0, mDatas.count() - 1);
qDeleteAll(mDatas);
mDatas.clear();
endRemoveRows();

View File

@ -75,7 +75,15 @@ Item {
onPressed: {
doPress(mouseX, mouseY)
}
onRightPressed: {
var index = indexAt(mouseX, mouseY + contentY)
if (index < 0 || index >= count) {
return
}
tableMenu.popup(mouseX, mouseY)
}
onReleased: {
doRelease()
}
onPositionChanged: {
@ -102,6 +110,55 @@ Item {
editInput.focus = true
}
}
Menu {
id: tableMenu
MenuItem {
text: qsTr("Edit row")
onTriggered: {
var mouseX = tableMenu.x
var mouseY = tableMenu.y
var index = cusView.indexAt(mouseX, mouseY + cusView.contentY)
if (index < 0 || index >= cusView.count) {
return
}
if (cusHeader.xList[1] <= mouseX && mouseX <= cusHeader.xList[2]) {
editInput.x = cusHeader.xList[1]
editInput.y = cusView.y + (parseInt(mouseY / CusConfig.fixedHeight)) * CusConfig.fixedHeight
editInput.width = cusHeader.widthList[1]
editInput.height = CusConfig.fixedHeight
editInput.index = index
var dataObj = deviceAddModel.data(index)
editInput.text = dataObj[deviceAddModel.headerRoles[0]]
editInput.visible = true
editInput.focus = true
}
}
}
MenuItem {
text: qsTr("Insert before row")
onTriggered: {
var mouseX = tableMenu.x
var mouseY = tableMenu.y
var index = cusView.indexAt(mouseX, mouseY + cusView.contentY)
if (index < 0 || index >= cusView.count) {
return
}
deviceAddModel.insertBeforeRow(index)
}
}
MenuItem {
text: qsTr("Remov row")
onTriggered: {
var mouseX = tableMenu.x
var mouseY = tableMenu.y
var index = cusView.indexAt(mouseX, mouseY + cusView.contentY)
if (index < 0 || index >= cusView.count) {
return
}
deviceAddModel.removeRow(index)
}
}
}
delegate: CusTableRow {
width: cusView.width
roles: cusView.model.headerRoles

View File

@ -4,3 +4,18 @@ DeviceAddItem::DeviceAddItem(QObject *parent)
: TaoListItemBase(parent)
{
}
bool DeviceAddItem::match(const QString &key)
{
if (key.isEmpty())
{
return true;
}
if (m_name.contains(key, Qt::CaseInsensitive)) {
return true;
} else if (m_address.contains(key, Qt::CaseInsensitive)) {
return true;
} else if (m_modelString.contains(key, Qt::CaseInsensitive)){
return true;
}
return false;
}

View File

@ -32,6 +32,8 @@ public:
{
return m_online;
}
bool match(const QString &key) override;
public slots:
void setName(const QString &name)
{

View File

@ -1,6 +1,8 @@
#include "DeviceAddModel.h"
#include "DeviceAddItem.h"
#include <QHostAddress>
#include <QCoreApplication>
#include <QEventLoop>
#include <chrono>
#include <random>
const static QString nameTemplate("item %1");
@ -50,6 +52,10 @@ void DeviceAddModel::initData()
for (int i = 0; i < N; ++i) {
auto item = genOne(i);
objs.append(item);
// if (i % 5 == 0)
// {
// qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
// }
}
auto c2 = std::chrono::high_resolution_clock::now();
@ -72,6 +78,10 @@ void DeviceAddModel::addMulti(int count)
for (int i = 0; i < count; ++i) {
auto item = genOne(d->u65535(d->randomEngine));
objs.push_back(item);
// if (i % 5 == 0)
// {
// qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
// }
}
append(objs);
}
@ -97,6 +107,12 @@ void DeviceAddModel::insertBeforeSelected()
}
}
void DeviceAddModel::insertBeforeRow(int row)
{
auto item = genOne(d->u65535(d->randomEngine));
insert(row, { item });
}
void DeviceAddModel::clearAll()
{
clear();
@ -130,6 +146,11 @@ void DeviceAddModel::removeChecked()
}
}
void DeviceAddModel::removeRow(int row)
{
removeAt(row);
}
DeviceAddItem *DeviceAddModel::genOne(uint32_t value)
{
auto item = new DeviceAddItem;

View File

@ -17,11 +17,15 @@ public slots:
void addOne();
void addMulti(int count);
void insertBeforeSelected();
void insertBeforeRow(int row);
void clearAll();
void removeSelected();
void removeChecked();
void removeRow(int row);
private:
DeviceAddItem *genOne(uint32_t value);
private:

View File

@ -7,11 +7,11 @@ import "../.."
Rectangle {
id: deviceRow
height: visible ? CusConfig.fixedHeight : 0
visible: dataObj["isVisible"]
visible: dataObj ? dataObj["isVisible"] : false
property bool isSelected: dataObj["isSelected"]
property bool isChecked: dataObj["isChecked"]
property bool isAlternate: dataObj["isAlternate"]
property bool isSelected: dataObj ? dataObj["isSelected"] : false
property bool isChecked: dataObj ? dataObj["isChecked"] : false
property bool isAlternate: dataObj ? dataObj["isAlternate"] : false
onIsCheckedChanged: {
checkBox.notify = false
checkBox.checked = isChecked
@ -55,7 +55,7 @@ Rectangle {
height: parent.height
CusLabel {
id: textLabel
text: qsTr(String(dataObj[roles[index]])) + CusConfig.transString
text: dataObj ? (qsTr(String(dataObj[roles[index]])) + CusConfig.transString) : ""
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter

View File

@ -8,6 +8,7 @@ ListView {
property real tableAreaX: CusTableConstant.column0Width
signal pressed(real mouseX, real mouseY)
signal rightPressed(real mouseX, real mouseY)
signal released()
signal positionChanged(real mouseX, real mouseY)
signal doubleClicked(real mouseX, real mouseY)
@ -123,6 +124,9 @@ ListView {
cusTableView.forceActiveFocus()
cusTableView.pressed(mouseX + tableAreaX, mouseY)
}
onRightPressed: {
cusTableView.rightPressed(mouseX + tableAreaX, mouseY)
}
onReleased: {
cusTableView.released()
}

View File

@ -11,6 +11,7 @@ Item {
property int drawW: Math.floor(drawRect.width)
property int drawH: Math.floor(drawRect.height)
signal pressed(real mouseX, real mouseY)
signal rightPressed(real mouseX, real mouseY)
signal released
signal positionChanged(real mouseX, real mouseY)
signal doubleClicked(real mouseX, real mouseY)
@ -21,12 +22,18 @@ Item {
id: drawArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: {
if (mouse.button === Qt.LeftButton) {
bPressed = true
oldX = Math.floor(mouseX)
oldY = Math.floor(mouseY)
drawRectItem.pressed(mouseX, mouseY)
} else if (mouse.button == Qt.RightButton) {
oldX = Math.floor(mouseX)
oldY = Math.floor(mouseY)
drawRectItem.rightPressed(mouseX, mouseY)
}
}
onReleased: {
drawRectItem.released()
@ -43,6 +50,7 @@ Item {
onWheel: {
drawRectItem.wheelEvent(wheel.angleDelta.y / 8)
}
}
Rectangle {
id: drawRect