59 / 35 / 8
Регистрация: 06.06.2013
Сообщений: 145
1

QTableView с большим количеством ячеек

08.05.2017, 13:36. Показов 4408. Ответов 8
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Собственно, тормозит, не пойму, почему. Пока тестировал 3-5 столбцов и 5-10 строк - все работало отлично. Но когда работаю с 200 строками - все подвисает на несколько секунд прежде, чем отрисовывается. В будущем мне придется записывать таблицы в несколько тысяч строк и 10-20 столбцов. Допускаю, что программа при этом будет подтормаживать, но не настолько же.

Теперь поподробнее. Предполагается, что QTableWidget *wTable будет отображать вектор данных, который состоит из такой структуры.

C++ (Qt)
1
2
3
4
5
6
    struct DataStruct       //структура для хранения элементов таблицы
    {
        QPoint  coord;
        QVector <double> val;
    };
    QVector <DataStruct> data;
Первые два столбца - координаты QPoint, далее - несколько столбцов данных QVector <double>. Второй QVector <DataStruct> отвечает за каждую строку в таблице.

Для определенности привожу два метода. Первый добавляет столбец в таблицу, второй перерисовывает рабочую область таблицы. Установил, что проблема кроется во втором методе. Если оставить все как есть - новый столбец добавляется секунд за 10-12. Если закомментировать цикл - время сокращается вдвое. То есть просто стирание и запись новых координат уже требует огромного количества времени. Слышал, что для таблиц свыше 500 строк рекомендуют использовать QTableView, но пока я не приступил к переделке кода, хотелось бы понять причину проблемы и как грамотно написать через QTableView, чтобы работало быстрее готового виджета с таблицей.

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void ParametersTableWidgetClass::addColumn (void)
{
    QStringList title;
    for (int i=0; i<ui->wTable->columnCount(); i++)             
        title.append(ui->wTable->horizontalHeaderItem(i)->text());
    ui->wTable->setColumnCount(ui->wTable->columnCount()+1);        //в любом случае увеличиваем количество столбцов на 1
    if (columnindex >= 2 && columnindex < ui->wTable->columnCount()-1) //если кликнули в столбец данных - вставляем столбец на текущую позицию
    {
        title.insert(columnindex+1, "Выберите параметр");
        for (int i=0; i<data.size(); i++)
        {
            data[i].val.insert(columnindex-1, (double)-1E+308);
        }
    }
    else if (columnindex >= 0 && columnindex < 2)    //если в столбец координат - добавляем как первый столбец данных
    {
        title.insert(2, "Выберите параметр");
        for (int i=0; i<data.size(); i++)
        {
            data[i].val.insert(0, (double)-1E+308);
        }
    }
    else    //если кликнули вне области таблицы - добавляем столбец в конец таблицы
    {
        title.append("Выберите параметр");
        for (int i=0; i<data.size(); i++)
        {
            data[i].val.append((double)-1E+308);
        }
    }
    ui->wTable->setHorizontalHeaderLabels(title);
    refreshTable();
}

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
void ParametersTableWidgetClass::refreshTable (void)
{
    ui->wTable->clearContents();
    ui->wTable->setRowCount(data.size());
 
    for (int row=0; row<data.size(); row++)
    {
        QTableWidgetItem *x = new QTableWidgetItem;        //запись первого столбца с координатой X
        x->setText(QString("%1").arg(data[row].coord.x()));      
        x->setTextAlignment(Qt::AlignCenter);
        ui->wTable->setItem(row, 0, x);
 
        QTableWidgetItem *y = new QTableWidgetItem;        //запись второго столбца с координатой Y
        y->setText(QString("%1").arg(data[row].coord.y()));
        y->setTextAlignment(Qt::AlignCenter);
        ui->wTable->setItem(row, 1, y);
 
        for (int col=2; col<ui->wTable->horizontalHeader()->count(); col++)  //не забываем, что первые две колонки - под координаты.
        {
            if (col-2 < data[row].val.size())    //условие корректного обращения к вектору данных.
            {
                if(data[row].val[col-2] == -1E+308 || data[row].val[col-2] == 1E+308)   //если данные не корректны
                {
                    QTableWidgetItem *val = new QTableWidgetItem;
                    val->setText("-");
                    val->setTextAlignment(Qt::AlignCenter);
                    ui->wTable->setItem(row, col, val);
                }
                else        //если данные имеют осмысленное значение
                {
                    QTableWidgetItem *val = new QTableWidgetItem;
                    val->setText(QString("%1").arg(data[row].val[col-2]));
                    val->setTextAlignment(Qt::AlignCenter);
                    ui->wTable->setItem(row, col, val);
                }
            }
            else        //если таких данных нет
            {
                QTableWidgetItem *val = new QTableWidgetItem;
                val->setText("-");
                val->setTextAlignment(Qt::AlignCenter);
                ui->wTable->setItem(row, col, val);
            }
        }
    }
}
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
08.05.2017, 13:36
Ответы с готовыми решениями:

Qwt. График с большим количеством точек
Уверен, что проблема решается просто, но она есть: точек графика - 4 320 000 штук. Хочу смотреть...

Установить размер ячеек QTableView
Новая проблема. Никак не могу установить размер ячеек QTableView Tv-&gt;setColumnWidth() и...

QTableView::setSpan выделение объединенных ячеек
Никак не могу разобраться с выделением ячеек, объединенных при помощи setSpan. При выделении...

QTableView рамка для групп ячеек
Есть таблица с данными. Нужно рисовать рамку, которая будет окаймлять какую - то группу ячеек....

8
1070 / 652 / 229
Регистрация: 14.01.2016
Сообщений: 2,031
Записей в блоге: 9
08.05.2017, 15:51 2
Лучший ответ Сообщение было отмечено Anvis как решение

Решение

Anvis, Нет ничего удивительного, что у вас всё подвисает. Вы совершаете настолько огромное количество операций, что даже хороший компьютер будет их считать достаточно больше время.

QTableWidget предназначен для того, чтобы хранить данные в нём. Если данные хранятся где-то ещё, как у вас, то имеет смысл делать QTableView + переопределять QAbstractTableModel, где и хранить данные.

Касательно же приведённого кода, то ошибка тут в том, что вы вместо использования QTableWidget::insertColumn(и дальнейшего забивания данными только ячеек созданного столбца), делаете свой тормозной велосипед, где полностью пересоздаёте таблицу.
1
7803 / 6567 / 2988
Регистрация: 14.04.2014
Сообщений: 28,706
08.05.2017, 15:56 3
А зачем ты её всю очищаешь и перезаполняешь? Добавил столбец - его и заполняй.
0
59 / 35 / 8
Регистрация: 06.06.2013
Сообщений: 145
08.05.2017, 16:33  [ТС] 4
Цитата Сообщение от nmcf Посмотреть сообщение
А зачем ты её всю очищаешь и перезаполняешь? Добавил столбец - его и заполняй.
refreshTable() используется не только в этом методе. Плюс хотел сделать код более читаемым и даже не думал, что перерисовка таблицы с 600 ячейками будет занимать столько времени. Так или иначе, даже если просто добавлю еще один столбец - все равно при добавлении 400 итемов начнутся лаги, так?

Цитата Сообщение от Wyn Посмотреть сообщение
QTableWidget предназначен для того, чтобы хранить данные в нём. Если данные хранятся где-то ещё, как у вас, то имеет смысл делать QTableView + переопределять QAbstractTableModel, где и хранить данные.
Понятно, буду думать, как сделать через QAbstractTableModel. Может этот вопрос и отпадет сам собой, но пока мне не понятно, где именно у меня много операций. Операция создания итема? Удаление итемов?
0
7803 / 6567 / 2988
Регистрация: 14.04.2014
Сообщений: 28,706
08.05.2017, 17:01 5
Цитата Сообщение от Anvis Посмотреть сообщение
даже если просто добавлю еще один столбец - все равно при добавлении 400 итемов начнутся лаги, так?
Будет в любом случае быстрее в несколько раз.

Уже сказали, что лучше использовать модель и QTableView.

Добавлено через 48 секунд
Чтобы определить, где там медленнее, надо замеры делать.
1
1070 / 652 / 229
Регистрация: 14.01.2016
Сообщений: 2,031
Записей в блоге: 9
09.05.2017, 07:17 6
Цитата Сообщение от Anvis Посмотреть сообщение
Так или иначе, даже если просто добавлю еще один столбец - все равно при добавлении 400 итемов начнутся лаги, так?
Даже если они и будут, они будут на порядок меньше, чем при пересоздании таблицы. Одно дело создать один столбец, другое - 10ть.
0
59 / 35 / 8
Регистрация: 06.06.2013
Сообщений: 145
10.05.2017, 01:54  [ТС] 7
Ну вот, пытаюсь въехать в логику моделей и что именно мне нужно переопределять. Допустим, есть горизонтальный хедер. Нужно ли мне переопределять setHeaderData при условии, что первые два столбца у меня с фиксированным названием, а остальные с изменяемым, причем их количество может меняться? А если надо - как быть со вторым параметром Qt::Orientation orientation? В смысле, если он вертикальный, а не горизонтальный. Игнорировать? Дописать еще одно поле, хранящее в себе номера строк и менять его? Хотелось бы оставить сквозную нумерацию строк.

То ли к этому надо привыкнуть, то ли с QTableWidget было проще.
0
7803 / 6567 / 2988
Регистрация: 14.04.2014
Сообщений: 28,706
10.05.2017, 10:54 8
setHeaderData() для вертикальной ориентации можно вообще не определять, если ты не собираешься там что-то специфическое выводить.
1
1070 / 652 / 229
Регистрация: 14.01.2016
Сообщений: 2,031
Записей в блоге: 9
10.05.2017, 12:56 9
Цитата Сообщение от Anvis Посмотреть сообщение
пытаюсь въехать в логику моделей и что именно мне нужно переопределять
Почитайте соответствующие статьи из документации по моделям Qt и посмотрите примеры. Сами найдёте или ссылку дать?
Цитата Сообщение от Anvis Посмотреть сообщение
Допустим, есть горизонтальный хедер. Нужно ли мне переопределять setHeaderData при условии, что первые два столбца у меня с фиксированным названием, а остальные с изменяемым, причем их количество может меняться? А если надо - как быть со вторым параметром Qt::Orientation orientation? В смысле, если он вертикальный, а не горизонтальный. Игнорировать? Дописать еще одно поле, хранящее в себе номера строк и менять его? Хотелось бы оставить сквозную нумерацию строк.
setHeaderData нужно переопределять только в случае, если вы изменяете данные в заголовке вне модели. Если хедеры изменяются только внутри модели, то вам нужно изменить их и вызвать соответствующий сигнал headerDataChanged, по которому кому надо подгрузят исправленные заголовки с помощью функции headerData.
Что вам непонятно насчёт параметра Qt::Orientation orientation и реализации нумерации строк в качестве вертикальных заголовков? Описание функции headerData читали? Там ведь всё понятно написано. Если с английским не знакомы, так всегда есть онлайн-переводчики. Более того, реализация данной функции неоднократно разобрана в примерах.
0
10.05.2017, 12:56
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
10.05.2017, 12:56
Помогаю со студенческими работами здесь

Как поменять размер ячеек в QTableView
Доброго времени суток. Имеется QTableView заполнял я его QStandardItem, теперь мне надо изменить...

Чтение содержимого ячеек из QTableView в QLineEdit
В общем. Использую QTableView и QSqlTableModel. По выделению строки в QTableView содержимое ячеек...

QTableView/QTableWidget drag drop перенос строк и ячеек
Вопросище, никак не иначе. Столкнулся с тем, что реализация переноса выделения строк ячеек да и...

Как выводить данные ячеек в их ToolTip-ы в QSqlQueryModel с QTableView?
model = new QSqlQueryModel; QString sqlquery = &quot;SELECT de.id as de_id, de.content as...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru