Russian Qt Forum
Май 08, 2024, 07:08 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3 4   Вниз
  Печать  
Автор Тема: [РЕШЕНО]Создание модели на основе QAbstractTableView  (Прочитано 28128 раз)
Larry
Гость
« : Март 23, 2016, 10:42 »

Добрый день.
Все же QTableWidget не справился с работай и уже при 160 записях жутко тормозил, поэтому пришлось переходить на QTableView.
У меня есть QMap<int, struct> с данными, которые мне надо отображать...Вернее отображать не все, а некоторые по условию. Например, в первой и во второй колонке текст, а в остальных разные иконки при определенных условиях. Как мне это сделать?

структура имеет следующий вид:
Код:
struct status_t
{
    QDateTime datetime; // a datetime last point
    bool          state; // a state car in last point (move or stop)
    float         power; // a voltage network car in last point
    float         battery; // a voltage battery device in last point
    int            speed; // a speed car in last point
    QPointF     coord; // a coordinates last point
    int            sat; // a count sattelite in last point
    bool          communication; // a communication with car (active or inactive)
};

Спасибо.
« Последнее редактирование: Март 31, 2016, 16:01 от Larry » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Март 23, 2016, 10:48 »

Все же QTableWidget не справился с работай и уже при 160 записях жутко тормозил, поэтому пришлось переходить на QTableView.
Может при 160 тысячах записей? А если все-таки при "просто 160" - значит что-то не так делаете
Записан
Larry
Гость
« Ответ #2 : Март 23, 2016, 11:16 »

Узнать бы что делаю не так, а так реально 162 записи и прокрутка срабатывает через пару секунд. У меня там вставляются в ячейки виджеты с текстом и иконками и обновляются данные с сервера где-то раз в 10 секунд. Если бы заработал этот вариант, то было бы очень хорошо, т.к. там уже все сделано, а так придется менять Улыбающийся.

Есть класс наследник от QTableWidget:

Код:
#ifndef QTABLECARS_H
    #define QTABLECARS_H
    //---------------------
    #include <QTableWidget>
    #include <QHeaderView>
    #include <QHBoxLayout>
    #include <QLabel>
    #include <QToolTip>
    #include <QDebug>
    #include "qstatuscars.h"
    #include "qstatusitem.h"
    //-----------------------------------
    class QTableCars: public QTableWidget
    {
        Q_OBJECT

        public:
            QTableCars(QWidget* parent = nullptr);
            ~QTableCars();

        public slots:
            void slotUpdateStatusCars(QStatusCars::statuses_t& statuses);

        signals:
            void updateItem(int, QPointF, const QString&);

        private:
            void createItems(QStatusCars::statuses_t& statuses);
            void createItem(int row, int id, QStatusCars::status_t& status);
            int  findItem(int id);
            void updateStatus(int row, int id, QStatusCars::status_t& status);
    };
#endif // QTABLECARS_H
Код:
#include "qtablecars.h"
//--------------------------------------
QTableCars::QTableCars(QWidget* parent):
    QTableWidget(parent)
{
    setSelectionBehavior(QAbstractItemView::SelectRows);
    setSelectionMode(QAbstractItemView::SingleSelection);
    setShowGrid(false);
    horizontalHeader()->hide();
    verticalHeader()->hide();

    setStyleSheet("QTableWidget::item { background-color: white; border: 1px solid #e0e0e0; }"
                  "QTableWidget::item:selected { background-color: #c0c0c0; }");
}
//-----------------------
QTableCars::~QTableCars()
{

}
//----------------------------------------------------------------------
void QTableCars::slotUpdateStatusCars(QStatusCars::statuses_t& statuses)
{
    if(this->rowCount() == 0)
    {
        createItems(statuses);
        return;
    }

    for(int key: statuses.keys())
    {
        int row = findItem(key);

        if(row != -1)
        {
            updateStatus(row, key, statuses[key]);
        }
        else
        {
            row = rowCount();
            insertRow(row);

            createItem(row, key, statuses[key]);
        }
    }

    resizeColumnsToContents();
    resizeRowsToContents();
}
//-------------------------------------------------------------
void QTableCars::createItems(QStatusCars::statuses_t& statuses)
{
    if(statuses.isEmpty())
        return;

    setRowCount(statuses.size());
    setColumnCount(6);

    int rowCount = 0;

    for(int id: statuses.keys())
    {
        createItem(rowCount, id, statuses[id]);

        rowCount++;
    }

    resizeColumnsToContents();
    resizeRowsToContents();
}
//-------------------------------------------------------------------------
void QTableCars::createItem(int row, int id, QStatusCars::status_t& status)
{
    QStatusItem* item_id            = new QStatusItem(QStatusItem::QTextRole);
    QStatusItem* item_speed         = new QStatusItem(QStatusItem::QTextRole);
    QStatusItem* item_state         = new QStatusItem;
    QStatusItem* item_battery       = new QStatusItem;
    QStatusItem* item_satellite     = new QStatusItem;
    QStatusItem* item_communication = new QStatusItem;

    setCellWidget(row, 0, item_id);
    setCellWidget(row, 1, item_speed);
    setCellWidget(row, 2, item_state);
    setCellWidget(row, 3, item_battery);
    setCellWidget(row, 4, item_satellite);
    setCellWidget(row, 5, item_communication);

    updateStatus(row, id, status);
}
//------------------------------
int QTableCars::findItem(int id)
{
    for(int row = 0; row < rowCount(); row++)
    {
        QStatusItem* wgt = qobject_cast<QStatusItem*>(cellWidget(row, 0));

        if(wgt && id == wgt->text().toInt())
            return row;
    }

    return -1;
}
//---------------------------------------------------------------------------
void QTableCars::updateStatus(int row, int id, QStatusCars::status_t& status)
{
    emit updateItem(id, status.coord, QString::number(status.speed));

    QStatusItem* item_id            = static_cast<QStatusItem*>(cellWidget(row, 0));
    QStatusItem* item_speed         = static_cast<QStatusItem*>(cellWidget(row, 1));
    QStatusItem* item_state         = static_cast<QStatusItem*>(cellWidget(row, 2));
    QStatusItem* item_battery       = static_cast<QStatusItem*>(cellWidget(row, 3));
    QStatusItem* item_satellite     = static_cast<QStatusItem*>(cellWidget(row, 4));
    QStatusItem* item_communication = static_cast<QStatusItem*>(cellWidget(row, 5));

    if(item_id)
    {
        item_id->setContent(QString::number(id));
        QString tooltip = "ID: " + QString::number(id) + "\n";
        tooltip += "Speed: " + QString::number(status.speed) + "km/h" + "\n";
        tooltip += "Fixed satellite: " + QString::number(status.sat) + "\n";
        tooltip += "Last position: " + QString::number(status.coord.y()) + ", " + QString::number(status.coord.x()) + "\n";
        tooltip += "Last point: " + status.datetime.toString("dd.MM.yyyy - hh:mm:ss");

        item_id->setToolTip(tooltip);
        item_id->setStyleSheet("background: white; color: black;");
    }
    else
        return;

    QString str;

    if(item_speed && status.speed > 0)
    {
        if(status.communication)
        {
            item_speed->setStyleSheet("color: green;");
            str = tr("Last state: movement");
        }
        else
        {
            item_speed->setStyleSheet("color: red;");
            str = tr("Last state: movement (no communication)");
        }

        item_speed->setContent(QString::number(status.speed) + "km/h");
    }
    else if(item_speed)
    {
        item_speed->setContent("");
        str = tr("Last state: stop");
    }

    if(status.state && item_state)
        item_state->setContent(":/icons/icons/move.png");
    else if(item_state)
        item_state->setContent(":/icons/icons/stop.png");

    item_state->setToolTip(str);
    item_state->setStyleSheet("background: white;");

    if(status.power < 10.0f && item_battery)
        item_battery->setContent(":/icons/icons/battery.png");
    else if(item_battery)
        item_battery->setContent("");

    if(status.sat == 0 && item_satellite)
    {
        item_satellite->setContent(":/icons/icons/satellite.png");
        str = tr("No satellites");
    }
    else if(item_satellite)
    {
        item_satellite->setContent("");
        str = tr("Fixed: ") + QString::number(status.sat) + tr(" satellites");
    }

    item_satellite->setToolTip(str);
    item_satellite->setStyleSheet("background: white;");

    if(!status.communication && item_communication)
    {
        item_communication->setContent(":/icons/icons/disconnected.png");
        str = tr("No connection\nLast point: ") + status.datetime.toString("dd.MM.yyyy - hh:mm:ss");
    }
    else if(item_communication)
    {
        item_communication->setContent("");
        str = tr("Last point: ") + status.datetime.toString("dd.MM.yyyy - hh:mm:ss");
    }

    item_communication->setToolTip(str);
    item_communication->setStyleSheet("background: white;");

    setRowHeight(row, item_state->width());
    setColumnWidth(0, item_id->width());
    setColumnWidth(1, item_speed->width());
    setColumnWidth(2, item_state->width());
    setColumnWidth(3, item_battery->width());
    setColumnWidth(4, item_satellite->width());
    setColumnWidth(5, item_communication->width());
}

И есть класс итема наследник от QWidget:
Код:
#ifndef QSTATUSITEM_H
    #define QSTATUSITEM_H
    //----------------
    #include <QWidget>
    #include <QLabel>
    #include <QHBoxLayout>
    #include <QHelpEvent>
    #include <QToolTip>
    #include <QDebug>
    //-------------------
    class QStatusTooltip;
    //-------------------------------
    class QStatusItem: public QWidget
    {
        Q_OBJECT

        public:
            enum Role{QIconRole = Qt::UserRole + 100, QTextRole};

        public:
            explicit QStatusItem(Role role = QIconRole, QWidget* parent = nullptr);
            ~QStatusItem();

            void    setContent(const QString& name);
            QSize   sizeHint() const;
            QString text() const;

        private:
            QLabel*         m_item;
            QHBoxLayout*    m_layout;
            Role            m_role;
            QStatusTooltip* m_tooltip;
    };
#endif // QSTATUSITEM_H

Код:
#include "qstatusitem.h"
//---------------------------------------------------
QStatusItem::QStatusItem(Role role, QWidget* parent):
    QWidget(parent),
    m_item(nullptr),
    m_layout(nullptr),
    m_role(role),
    m_tooltip(nullptr)
{
    m_item   = new QLabel(this);
    m_layout = new QHBoxLayout;

    m_layout->setContentsMargins(0, 0, 0, 0);
    m_layout->setMargin(0);
    m_layout->setSpacing(0);
    m_layout->addWidget(m_item);
    m_layout->setAlignment(Qt::AlignCenter);

    setLayout(m_layout);

    m_item->setStyleSheet("background: none");
}
//-------------------------
QStatusItem::~QStatusItem()
{
    if(m_item)
        delete m_item;

    if(m_layout)
        delete m_layout;
}
//-----------------------------------------------
void QStatusItem::setContent(const QString& name)
{
    QSize size_item;

    if(m_role == QIconRole)
    {
        m_item->setPixmap(QPixmap(name));

        const QPixmap* pixmap_item = m_item->pixmap();

        if(pixmap_item)
            size_item = pixmap_item->size();
        else
            size_item = QSize(0, 0);
    }
    else
    {
        QFont        font = m_item->font();
        QFontMetrics fm(font);

        size_item = QSize(fm.width(name)*1.2, fm.height()*1.2);

        m_item->setAlignment(Qt::AlignCenter);
        m_item->setText(name);
    }

    resize(size_item);
}
//---------------------------------
QSize QStatusItem::sizeHint() const
{
    return size();
}
//-------------------------------
QString QStatusItem::text() const
{
    return m_item->text();
}

Подскажите где может быть узкое место. Спасибо.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Март 23, 2016, 11:23 »

Выложите виде компилируемого проекта (запакованного в zip)
Записан
Larry
Гость
« Ответ #4 : Март 23, 2016, 11:38 »

К сожалению не могу, т.к. там присутствуют данные для подключения к серверу с данными клиента. Тормоза происходят в этом методе:
Код:
void QTableCars::updateStatus(int row, int id, QStatusCars::status_t& status)
{
    emit updateItem(id, status.coord, QString::number(status.speed));

    QStatusItem* item_id            = static_cast<QStatusItem*>(cellWidget(row, 0));
    QStatusItem* item_speed         = static_cast<QStatusItem*>(cellWidget(row, 1));
    QStatusItem* item_state         = static_cast<QStatusItem*>(cellWidget(row, 2));
    QStatusItem* item_battery       = static_cast<QStatusItem*>(cellWidget(row, 3));
    QStatusItem* item_satellite     = static_cast<QStatusItem*>(cellWidget(row, 4));
    QStatusItem* item_communication = static_cast<QStatusItem*>(cellWidget(row, 5));

    if(item_id)
    {
        item_id->setContent(QString::number(id));
        QString tooltip = "ID: " + QString::number(id) + "\n";
        tooltip += "Speed: " + QString::number(status.speed) + "km/h" + "\n";
        tooltip += "Fixed satellite: " + QString::number(status.sat) + "\n";
        tooltip += "Last position: " + QString::number(status.coord.y()) + ", " + QString::number(status.coord.x()) + "\n";
        tooltip += "Last point: " + status.datetime.toString("dd.MM.yyyy - hh:mm:ss");

        item_id->setToolTip(tooltip);
        item_id->setStyleSheet("background: white; color: black;");
    }
    else
        return;

    QString str;

    if(item_speed && status.speed > 0)
    {
        if(status.communication)
        {
            item_speed->setStyleSheet("color: green;");
            str = tr("Last state: movement");
        }
        else
        {
            item_speed->setStyleSheet("color: red;");
            str = tr("Last state: movement (no communication)");
        }

        item_speed->setContent(QString::number(status.speed) + "km/h");
    }
    else if(item_speed)
    {
        item_speed->setContent("");
        str = tr("Last state: stop");
    }

    if(status.state && item_state)
        item_state->setContent(":/icons/icons/move.png");
    else if(item_state)
        item_state->setContent(":/icons/icons/stop.png");

    item_state->setToolTip(str);
    item_state->setStyleSheet("background: white;");

    if(status.power < 10.0f && item_battery)
        item_battery->setContent(":/icons/icons/battery.png");
    else if(item_battery)
        item_battery->setContent("");

    if(status.sat == 0 && item_satellite)
    {
        item_satellite->setContent(":/icons/icons/satellite.png");
        str = tr("No satellites");
    }
    else if(item_satellite)
    {
        item_satellite->setContent("");
        str = tr("Fixed: ") + QString::number(status.sat) + tr(" satellites");
    }

    item_satellite->setToolTip(str);
    item_satellite->setStyleSheet("background: white;");

    if(!status.communication && item_communication)
    {
        item_communication->setContent(":/icons/icons/disconnected.png");
        str = tr("No connection\nLast point: ") + status.datetime.toString("dd.MM.yyyy - hh:mm:ss");
    }
    else if(item_communication)
    {
        item_communication->setContent("");
        str = tr("Last point: ") + status.datetime.toString("dd.MM.yyyy - hh:mm:ss");
    }

    item_communication->setToolTip(str);
    item_communication->setStyleSheet("background: white;");

    setRowHeight(row, item_state->width());
    setColumnWidth(0, item_id->width());
    setColumnWidth(1, item_speed->width());
    setColumnWidth(2, item_state->width());
    setColumnWidth(3, item_battery->width());
    setColumnWidth(4, item_satellite->width());
    setColumnWidth(5, item_communication->width());
}
Записан
Larry
Гость
« Ответ #5 : Март 23, 2016, 11:47 »

Отключил вывод изображений, оставил только надписи на QLabel, работать стало быстрее, но все равно подтормаживает при прокрутке.
Записан
Bepec
Гость
« Ответ #6 : Март 23, 2016, 12:06 »

Ковырять куски кода, без цельной картины бессмысленно. Вот будет конкретика, тогда посмотрим Улыбающийся
Записан
Larry
Гость
« Ответ #7 : Март 23, 2016, 12:11 »

Спасибо, а не подскажите как установить свою роль на колонку в QTableView?
Записан
Larry
Гость
« Ответ #8 : Март 23, 2016, 12:50 »

Что-то никак не въеду. Свою роль можно только через setData вставить? Но setData это для изменения данных при редактировании или я неправильно понимаю? Просто мне надо ввести несколько дополнительных ролей, чтобы брать данные и отрисовывать их как мне надо. Но как-то не въеду как добавить роль ячейке...Подскажите плиз...
Записан
Bepec
Гость
« Ответ #9 : Март 23, 2016, 12:59 »

добавить свою роль и её обработку нужно в модели. А вот уже изменять можно в setData.
Записан
Larry
Гость
« Ответ #10 : Март 23, 2016, 13:16 »

Так изначально как установить роль? Н-р, я добавил роли:
enum ModelRole
{
        StateRole = Qt::UserRole + 1,
        PowerRole
};

и как теперь эти роли назначить колонкам?
Записан
Larry
Гость
« Ответ #11 : Март 23, 2016, 17:54 »

Пытаюсь вставить пустую строку, но ничего не вставляется...Что может быть?
Код:
void QModelCars::addCar(int id, QStatusCars::status_t& status)
{
    if(m_statuses.keys().contains(id))
        return;

    int row = rowCount();
    insertRow(row);
}
Записан
Bepec
Гость
« Ответ #12 : Март 23, 2016, 18:14 »

Хз. Мы же не знаем что в insertRow происходит.
Нака пару вариантов:
1) всё добавляется, но view не дают сигналы о добавлении и он не обновляется.
2) ничего не добавляется, всё рушится на условии.
3) всё добавляется, испорчена система отображения данных.
Записан
Larry
Гость
« Ответ #13 : Март 23, 2016, 18:23 »

Все разобрался. Переопределил insertRows() и все создается.
Спасибо.
Записан
Larry
Гость
« Ответ #14 : Март 24, 2016, 17:03 »

Подскажите пожалуйста, где у меня проблемы. Во вложении минимальный компилируемый пример. Только данные одни и те же и обновляются по таймеру раз в 10 секунд. При работе QTableWidget тормоза начинались при 162 объектах. При работе с QTableView на 162 работает нормально, но при количестве объектов 2000 снова тормоза.
Спасибо.
Записан
Страниц: [1] 2 3 4   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.051 секунд. Запросов: 22.