PDA

View Full Version : QTableView perfomance 2



hml
25th March 2010, 16:33
Hi,

I have a QTableView with over 10000 entries.

I have derived from QAbstractTableModel a custom model with this data() member function


QVariant log_q_item_model::data(const QModelIndex& index, int role) const
{
if (index.isValid() && index.row()>=0 && static_cast<size_t>(index.row())<log_->size() && role==Qt::DisplayRole) {
const logentry& e = (*log_)[index.row()];

return (index.column()==0)?
QString(boost::gregorian::to_simple_string(e.get_d ate()).c_str()):
QString::number(e.get_total(),'f',2);
}

return QVariant();
}

The model has a private
shared_ptr< vector<logentry> > which points to a vector of
logentry.
The
get_date() and
get_total() are inline functions that return members of logentry.

I have commented out the implementation of the
data() function and the display of the TableView widget (all blanks) takes now half a second, instead of 5 seconds.

My bottleneck is definitely here.

I have replaced the return statement by

return QString::number(e.get_total(),'f',2);

and it takes half the time roughly.

It seems the QString functions are in my case quite slow.

Ideas for speeding this up are appreciated?

Regards,

ChrisW67
25th March 2010, 23:05
Normally data() would only be called when a cell was needed for display by the view. However, if you set the view to resize to contents then a fetch of every cell to allow calculation of an "optimal" size hint results. Given the reasonably fixed presentation of your values you could use the view delegate to pre-calculate a size hint and return a fixed value for the date column, and another for the number columns.

Other thoughts:
For the date, there's a conversion to UTF-8 in the QString::QString ( const char * str ) constructor that might avoided with QString::fromAscii() or one of the other equivalents.

There's also a conversion from QString to QVariant involved.

hml
26th March 2010, 13:44
Hi,

Thanks for your advice,


Other thoughts:
For the date, there's a conversion to UTF-8 in the QString::QString ( const char * str ) constructor that might avoided with QString::fromAscii() or one of the other equivalents.

Changing this didn't result in any change.


Normally data() would only be called when a cell was needed for display by the view. However, if you set the view to resize to contents then a fetch of every cell to allow calculation of an "optimal" size hint results. Given the reasonably fixed presentation of your values you could use the view delegate to pre-calculate a size hint and return a fixed value for the date column, and another for the number columns.
I've overriden the
int QTableView::sizeHintForColumn ( int column ) const method of QTableView to be an inline function that returns 100.
No change either. Is this what you meant?

Regards,

ChrisW67
26th March 2010, 23:11
.. or QStyledItemDelegate::sizeHint()

Exactly when is the long delay being seen?
First displaying the QTableView, while scrolling, some other time?
Are you calling QTableView::resizeColumnToContents ( int column ) or QTableView::resizeColumnsToContents()?
Do you have QHeaderView::ResizeToContents set on the horizontal header?

Have you tried giving columns a fixed width with QHeaderView::resizeSection() on the table's horizontal header?

Can you post the code that sets up your QTableView?

hml
27th March 2010, 10:16
I'll post the code now, and will answer more in details on monday.


class log_q_table_view : public QTableView {
public:
log_q_table_view(const log_ptr& log, QWidget* parent =0);
};


class log_q_item_model : public QAbstractTableModel {

Q_OBJECT

public:
log_q_item_model(const log_ptr& log)
: log_(log)
{}

int rowCount(const QModelIndex&) const
{
return log_->size();
}
int columnCount(const QModelIndex&) const
{
return 2;
}
QVariant data(const QModelIndex& index, int role) const;

QVariant headerData(int section, Qt::Orientation orientation, int role) const;

private:
const log_ptr log_;
};

log_q_table_view::log_q_table_view(const log_ptr& log, QWidget* parent)
: QTableView(parent)
{
setEditTriggers(QAbstractItemView::NoEditTriggers) ;
setModel(new log_q_item_model(log));
verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
}


thanks,

hml
28th March 2010, 12:17
.. or QStyledItemDelegate::sizeHint()
I will try.


Exactly when is the long delay being seen?
First displaying the QTableView, while scrolling, some other time?
Right before displaying and when resizing the parent widget. Scrolling is not slow.


Are you calling QTableView::resizeColumnToContents ( int column ) or QTableView::resizeColumnsToContents()?
No


Do you have QHeaderView::ResizeToContents set on the horizontal header?
Indeed. In the ctor. I will turn this off and see the effect.


Have you tried giving columns a fixed width with QHeaderView::resizeSection() on the table's horizontal header?
I will try this as well.

Thanks,

ChrisW67
28th March 2010, 22:51
The use of QHeaderView::ResizeToContents, in my experience, makes the start up time of a table view on a large model unacceptable. To achieve this, every value in the model is fetched, its width calculated, and the largest value in the row/column used to set the section width. For a 10,000 row by 10 column table this means that your model's data() method is called 100,000 times to fetch the display value, and probably a few more times for each cell to get formatting information (Font, decoration, size hint roles). It's possible that using it on both rows and columns repeats the table scan twice. If you can possibly live with a fixed width then you'll find this faster.