Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: _Vitaliy_ от Сентябрь 03, 2008, 21:38



Название: Проблемы новичка с QTableWidget [РЕШЕНО]
Отправлено: _Vitaliy_ от Сентябрь 03, 2008, 21:38
Только начал изучать Qt, стоит версия 4.3.1. Решил начать изучение с реального примера: необходимо считать файл данных следующего формата (вложение 102_2662.stf):

t,Hb,Vp,Xv,Xe,Xn ...
     79.000      81.633    -600.000     -23.333       5.333       0.000             
     79.250      81.633    -600.000     -23.333       5.333      -2.609       
     79.500      81.633    -600.000     -23.333       5.333      -2.609       
     79.750      81.633    -600.000     -23.333       5.333      -2.609   
     80.000      81.633    -600.000     -23.333       5.333      -2.609
...

В зависимости от кол-ва параметров (t,Hb,Vp,Xv,Xe,Xn ...) определяется кол-во столбцов QTableWidget"а, кол-во строк данных определяет кол-во строк QTableWidget"а соответственно и записать данные в QTableWidget, с которого потом будет осуществлятся считывание и дальнейшая обработка.         

Вроде смотрел на примеры, вроде "лазил" по форуму но проблему пока не решил, выкладываю то что наваял я, извиняйте но только учусь.

В файле mainform.cpp использую split(' '), как в книге Бланшет, но не могу сделать так что-бы данные записывались во все ячейки строки, а не в первую ячейку, это первая проблема.

Вторая заключается в том что не могу пока понять как при запуске программы (то что я написал) появляется новое окно
с QTableWidget"ом, вроде в "Десигнере" вставил на форму QTableWidget а как к нему программно обратиться не пойму...

Код:
mainform.cpp:

#include "mainform.h"
//
MainForm::MainForm( QWidget * parent, Qt::WFlags f)
: QMainWindow(parent, f)
{
setupUi(this);
connect(pushButton, SIGNAL(clicked()), this, SLOT(OpenFile()));
}
//


void MainForm::OpenFile()
{
QString fileName = QFileDialog::getOpenFileName(this);

QFile file (fileName);
if (file.open(QIODevice::ReadOnly))
{
QTextStream stream(&file);
QString str;
stream.setCodec("UTF-8");

QTableWidget* tbl = new QTableWidget;
tbl->setColumnCount(3);
    tbl->setRowCount(10);
   
   //   lst << "First" << "Second" << "Third";
    // tbl->setHorizontalHeaderLabels(lst);

    tbl->setColumnCount(20);
    tbl->setRowCount(2);
    int row=0,col=0;
while (!stream.atEnd())
{
str = stream.readLine();
QStringList fields = str.split(' ');

int f = fields.takeLast().toInt();
for (int i=0; i<=f; ++i)
{
QTableWidgetItem *item = new QTableWidgetItem;
item->setData(fields);
tbl->setItem(row, i, item);
}


}
if (stream.status() != QTextStream::Ok)
{
qDebug() << "Ошибка чтения файла";
}

file.close();
tbl->show();
}

}

mainform.h:
#ifndef MAINFORM_H
#define MAINFORM_H
//
#include <QMainWindow>
#include "ui_mainwindow.h"
#include <QtGui>
#include <QTextStream>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QStringList>
//
class MainForm : public QMainWindow, public Ui::MainWindow
{
Q_OBJECT
public:
MainForm( QWidget * parent = 0, Qt::WFlags f = 0 );
//QTableWidget *tbl;  // ???
//QTableWidgetItem ptwi = 0;
    QStringList       lst;

private slots:

void OpenFile();

};
#endif


Заранее признателен если кто укажет на мои "пробелы"...

Пользуйтесь тэгом КОД для форматирования исходного кода!

 


Название: Re: Проблемы новичка с QTableWidget
Отправлено: lit-uriy от Сентябрь 03, 2008, 22:28
Цитировать
не могу пока понять как при запуске программы (то что я написал) появляется новое окно
с QTableWidget"ом
ты его сам создаешь в void MainForm::OpenFile() :
QTableWidget* tbl = new QTableWidget;

Цитировать
вставил на форму QTableWidget а как к нему программно обратиться не пойму
т.к. у тебя множественное наследование класса MainForm, то обращайся в этом классе непосредственно, т.е. как он у тебя в дизайнере обозван


Название: Re: Проблемы новичка с QTableWidget
Отправлено: lit-uriy от Сентябрь 03, 2008, 22:53
вместо:
Код:
int f = fields.takeLast().toInt();
for (int i=0; i<=f; ++i)
{
QTableWidgetItem *item = new QTableWidgetItem;
item->setData(fields);  // <---------- Вставил весь список залпом !!!
tbl->setItem(row, i, item);
}
я бы использовал:
Код:
int i=0;
// для каждой строки из списка строк
foreach (QString str, fields)
{
QTableWidgetItem *item = new QTableWidgetItem;
item->setData(str);  // <---------- Вставил один элемент списка
tbl->setItem(row, i++, item);
}


Название: Re: Проблемы новичка с QTableWidget
Отправлено: _Vitaliy_ от Сентябрь 05, 2008, 17:49
lit-uriy, попробовал код который Вы предложили:
Код:
...
item->setData(str); 
...


В этом месте выбивает error: no matching function for call to 'QTableWidgetItem::setData(QStringList&)'

???


Название: Re: Проблемы новичка с QTableWidget
Отправлено: ритт от Сентябрь 05, 2008, 18:14
бред. ветку под снос
иди читай документацию


Название: Re: Проблемы новичка с QTableWidget
Отправлено: ритт от Сентябрь 05, 2008, 22:52
ну, какими тут ссылками поможешь, если наличествует банальное нежелание читать?
ни бланшет, ни шлее, ни папа римский не помогут, если не читать ассистант и/или http://doc.trolltech.com/

> QTableWidgetItem::setData(QStringList&)
а строкой ниже кандидатов не показали?

Цитировать
void QTableWidgetItem::setData ( int role, const QVariant & value )   [virtual]
Sets the item's data for the given role to the specified value.

> своими высказываниями я отбиваю желание учиться
мне кажется, своими высказываниями я прививаю необходимое качество любого кодера и даже, наверное, кастомера - привычку/умение читать документацию взамен привычки гуглить и занудствовать на форумах по каждому вопросу!

счастливого изучения документации...

с уважением, константин

з.ы. не только в языках программирования существует синтаксис и орфограция - в русском языке тоже


Название: Re: Проблемы новичка с QTableWidget
Отправлено: _Vitaliy_ от Сентябрь 18, 2008, 16:03
Немного разобрался по этому вопросу, наверное отвечу сам себе, может еще кому пригодится, тем более что модератор: "...ветку под снос" (за что спасибо) этого не сделал  :)

Код:
void MainForm::OpenFile()
{
QString fileName = QFileDialog::getOpenFileName(this);

QFile file (fileName);
if (file.open(QIODevice::ReadOnly))
{
QTextStream stream(&file);

stream.setCodec("CP-866");

QTableWidget* tbl = new QTableWidget;
   
      lst << "First" << "Second" << "Third";
    tbl->setHorizontalHeaderLabels(lst);
   
    tbl->setColumnCount(5);
    tbl->setRowCount(5);
   
    int f=0, row=0,col=0, tt=0, vv=0;
   
    QString str;
    QString fff, ggg;
    QList<QString> gg;
    QStringList fields;
   
    while (!stream.atEnd())
{
str = stream.readLine(); //chtenie stroki
str = str.simplified();  //ubiraet pustie probeli v stroke
if (tt<=3) fields = str.split(",");
if (tt>3) fields = str.split(' ');

tbl->setColumnCount(f);
tbl->setRowCount(tt+1);
gg = fields;

f = fields.size();

for (int i=0; i<=(f-1); ++i)
{
fff = gg.at(i);
QTableWidgetItem *item = new QTableWidgetItem;
item->setText(QString(fff));
tbl->setItem(tt, i, item);
}

  ++tt;
     
}
if (stream.status() != QTextStream::Ok)
{
qDebug() << "Р_С_РёР+РєР° С╪С'РчР_РёС_ С"айР>Р°";
}

file.close();
tbl->show();
}

Единственное сопутствующий вопрос: это хорошо работает для открытия файлов небольшого объема, а если файл более 2 мегабайт "весит" то все очень сильно "тормозит". Вроде надо пользоваться вместо QTableWidget QTableView"ом если у кого-то есть наработки поделитесь плиз 


Название: Re: Проблемы новичка с QTableWidget
Отправлено: pastor от Сентябрь 18, 2008, 16:14
Чтобы интрефейс не "умирал" на время считывания данных из большого файла, добавьте в цикл следующее:


Код:
while (!stream.atEnd())
{
...
    qApp->processEvents();
...
}

Почитайте по этому поводу Бланшетте, глава "7.3. Сокращение времени отклика при длительной обработке данных."


Название: Re: Проблемы новичка с QTableWidget
Отправлено: Пантер от Сентябрь 18, 2008, 16:58
Причем чтобы время не сильно увеличилось, можно сделать так:
int i=0;
while(..........
{
    i++;
    if ((i/100)*100==i)
        qApp->processEvents();
.........
}
То бишь срабатывать будет на каждой сотой итерации. :)


Название: Re: Проблемы новичка с QTableWidget
Отправлено: _Vitaliy_ от Сентябрь 18, 2008, 17:19
Да, помогло, спасибо, но время открытия файла размером в 2 "метра" составляет более полутора минут, хотя таже самая программа, написанная в Билдере 6.0 это делает на порядок быстрее... может все-таки нужно использовать QTableView, по-моему или у Бланшет или у Шлее об этом сказано.   


Название: Re: Проблемы новичка с QTableWidget
Отправлено: Alex03 от Сентябрь 18, 2008, 17:26
Код:
str = stream.readLine();
Угадайте как оно работает. :)
Если читать блоками в память, вручную находить концы строк, и уже их потом обрабатывать то получится на порядок (порядки) быстрее.


Название: Re: Проблемы новичка с QTableWidget
Отправлено: Пантер от Сентябрь 18, 2008, 17:28
Можно отключить обновление, т.е. вначале setUpdatesEnabled(false) и в конце setUpdatesEnabled(true). Но через модель быстрее будет.


Название: Re: Проблемы новичка с QTableWidget
Отправлено: ритт от Сентябрь 18, 2008, 17:37
в моделях есть такая фича - fetchMore. я сомневаюсь, что у кого-то найдётся монитор такой диагонали чтобы вся таблица разом влезла в один экран.
QTableWidget - это а) для ленивых; б) для сверхпростых задач. если требуется приличная производительность для больших объёмов данных, пользуемся QTableView/QAbstractItemModel


Название: Re: Проблемы новичка с QTableWidget
Отправлено: Tonal от Сентябрь 18, 2008, 17:54
Не нужно читать блоками - там тормозов и без этого хватает.
Отключить обновление кардинально поможет, особенно, если стоит автоматический ресайз колонок.
В Eric4 так на порядок ускорили загрузку данных профилера.
Ну и переход на свою модель тоже даст существенный выигрыш и не только в скорости. :)


Название: Re: Проблемы новичка с QTableWidget
Отправлено: ритт от Сентябрь 18, 2008, 18:02
Не нужно читать блоками
это про fetchMore ?


Название: Re: Проблемы новичка с QTableWidget
Отправлено: Tonal от Сентябрь 18, 2008, 19:29
Это про stream.readLine(). :)


Название: Re: Проблемы новичка с QTableWidget
Отправлено: _Vitaliy_ от Октябрь 09, 2008, 18:50
Решил продолжить здесь, если я не прав то прошу модератора перекинуть в новую ветку.
Подсказали добрые люди  ;) как пользоваться моделью для решаемого вопроса, ниже привожу код:

это mainform.h
Код:
#include <QtGui>
#include <QTextStream>
#include <QTableWidget>
#include <QStandardItemModel>
//#include <QTableWidgetItem>
#include <QStringList>
//
class MainForm : public QMainWindow, public Ui::MainWindow
{
Q_OBJECT
public:
MainForm( QWidget * parent = 0, Qt::WFlags f = 0 );
QStringList       lst;
QStandardItemModel* model;

private slots:

void OpenFile();

};
#endif


mainform.cpp
Код:
#
include "mainform.h"
//
MainForm::MainForm( QWidget * parent, Qt::WFlags f)
: QMainWindow(parent, f)
{
setupUi(this);
connect(pushButton, SIGNAL(clicked()), this, SLOT(OpenFile()));
model=new QStandardItemModel(this);
view->setModel(model);
}
//


void MainForm::OpenFile()
{
QString fileName = QFileDialog::getOpenFileName(this);

QFile file (fileName);
if (file.open(QIODevice::ReadOnly))
{
QTextStream stream(&file);

stream.setCodec("CP-866");

int siz=0, size_file=0, f=0, row=0, col=0;
   
    QString str;
    QString fff, ggg;
    QList<QString> gg;
    QStringList fields;
   
     
    // dlya sozdaniya okna progressa
    siz = file.size();
    size_file = siz/190; // razmer % dlya progressDialog
   
    QProgressDialog* pprd =
new QProgressDialog(tr("Progressing the data..."), tr("&Cancel"), 0, size_file,this);
pprd->setModal(true);  // ustanovka modalnosti okna
pprd->setMinimumDuration(0);
pprd->setWindowTitle("Please Wait");

    model->clear();
model->setColumnCount(f);
view->setUpdatesEnabled(false);

QTime timer(0,0,0,0);
QTime tim(0,0,0,0);
timer.start();
   //char buf[256];
 
   
    while (!stream.atEnd())
{
str = stream.readLine();
///qint64 lineLength = file.readLine(buf, sizeof(buf));
///str = buf;
//str = stream.readLine(); //chtenie stroki
str = str.simplified();  //ubiraet pustie probeli v stroke
if (row<=3) fields = str.split(",");
if (row>3) fields = str.split(' ');

model->setRowCount(row+1);
gg = fields;

for (col=0; col<=(fields.size()-1); ++col)
{
fff = gg.at(col);
QStandardItem *item = new QStandardItem(QString(fff));
model->setItem(row, col, item);
}
pprd->setValue(row) ;  // progress
qApp->processEvents();
if (pprd->wasCanceled()) break;

  ++row;
}

if (stream.status() != QTextStream::Ok)
{
qDebug() << "╨Ю╤И╨╕╨▒╨║╨░ ╤З╤В╨╡╨╜╨╕╤П ╤Д╨░╨╣╨╗╨░";
}

tim = tim.addMSecs(timer.elapsed());
this->setWindowTitle(QString(tim.toString("m:s:z")));

delete pprd; //unichtozhenie okna  QProgressDialog

view->setUpdatesEnabled(true);
file.close();
}


однако скорость к моему глубокому сожалению не возросла  :(, пробовал через буфер, в принципе эффект тот-же, если кто-то сталкивался с такой проблемой подскажите плиз


Название: Re: Проблемы новичка с QTableWidget
Отправлено: Karl-Philipp от Октябрь 09, 2008, 19:36
Мне кажется, что в твоем случае все дело в создании модели.

Для ускорения создания (заполнения) модели сделай наследника от QAbstractItemModel. Пример можно посмотреть в Simple Tree Model.


Название: Re: Проблемы новичка с QTableWidget
Отправлено: ритт от Октябрь 09, 2008, 23:03
я сотню раз уже писал, что QStandardItemModel медленная и для больших объёмов данных тролли советуют пользоваться оптимизированными наследниками QAbstractItemModel!


Название: Re: Проблемы новичка с QTableWidget
Отправлено: _Vitaliy_ от Октябрь 10, 2008, 17:29
спасибо за подсказку, будем пробовать, как сделаю (при наличии времени) обязательно отпишу, может еще кому сгодиться  ;)


Название: Re: Проблемы новичка с QTableWidget
Отправлено: _Vitaliy_ от Январь 31, 2009, 17:46
Доброго времени суток всем.
Наконец-то добрался до кьютов и разобрался наконец с QTableWidget. Поэтому отвечу сам себе  ;)

Код
C++ (Qt)
void MainWindow::OpenFile()
{
QString fileName = QFileDialog::getOpenFileName(this);
 
QFile file (fileName);
if (file.open(QIODevice::ReadOnly))
       {
              QTextStream stream(&file);
              stream.setCodec("CP-866");
int RowC=0; // kol-vo strok
while (!stream.atEnd())
       {
               stream.readLine();
               RowC++;
       }
 
stream.seek(0);//Go to begin of file
 
QTableWidget* tbl = new QTableWidget;
 
QStringList fields;
QString str1 = stream.readLine(); //chtenie stroki
QString str2 = stream.readLine(); //chtenie stroki
QString str3 = stream.readLine(); //chtenie stroki
QString str4 = stream.readLine(); //chtenie stroki
fields = str4.split(",");
int f = fields.size();
 
tbl->setColumnCount(f);
tbl->setRowCount(RowC-4);
tbl->setHorizontalHeaderLabels(fields);
 
QProgressDialog* pprd =
new QProgressDialog(tr("Progressing the data..."), tr("&Cancel"), 0, RowC,this);
pprd->setModal(true);  // ustanovka modalnosti okna
pprd->setMinimumDuration(0);
pprd->setWindowTitle("Please Wait");
 
QTime timer(0,0,0,0);
QTime tim(0,0,0,0);
timer.start();
 
RowC = 0;
 
while (!stream.atEnd())
{
  QString str = stream.readLine(); //chtenie stroki
  str = str.simplified();  //ubiraet pustie probeli v stroke
  fields = str.split(' ');
       for (int i=0; i<16; ++i)
       {
            QString fff = fields.at(i);
            QTableWidgetItem *item = new QTableWidgetItem;
            item->setText(fff);
            tbl->setItem(RowC, i, item);
       }
   ++RowC;
   pprd->setValue(RowC) ;  // progress
       if (pprd->wasCanceled()) break;
   qApp->processEvents(); // chtobi prilozhenie ne zavisalo
}
   if (stream.status() != QTextStream::Ok)
               {
                       qDebug() << "Ошибка чтения файла";
               }
   file.close();
 
   tim = tim.addMSecs(timer.elapsed());
       this->setWindowTitle(QString(tim.toString("m:s:z")));
 
       delete pprd; //unichtozhenie okna  QProgressDialog
 
   tbl->show();
       } // if fileopen
 
}


При этом время открытия файла в 10000 строк порядка 7-8 секунд. Код не идеален но работоспособен. Спасибо всем кто подсказывал.
Модератору предлагаю перенести ветку в раздел для новичков, там ей самое место.
Будем считать что тема закрыта.


Название: Re: Проблемы новичка с QTableWidget [РЕШЕНО]
Отправлено: Dendy от Январь 31, 2009, 18:08
Раздел для новичков? Ну что вы, не стоит рисковать неокрепшей психикой юных программистов. Предлагаю поместить код в раздел "Комната пыток" и принудительно показывать тем кто нарушает правила форума.


Название: Re: Проблемы новичка с QTableWidget
Отправлено: panAlexey от Январь 31, 2009, 19:43
я сотню раз уже писал, что QStandardItemModel медленная и для больших объёмов данных тролли советуют пользоваться оптимизированными наследниками QAbstractItemModel!
Как насчет создание раздела: "Грабли" или "Грабли Qt" или "Туда не ходи, снег башка попадет...."?
Имхо много полезнее будет, чем "я сотню раз уже писал"...
Я тока сегодня 2 темы под это дело присмотрел: эту и по производительности гиф анимации.
Что скажете?