PDA

View Full Version : Scrolling tableview and updating via QThread



steg90
8th May 2007, 10:15
Hi all,

I'm new to Qt having come from MFC. I have created a custom model to be used with a table view (it has to be quick). I have a seperate thread which updates the model and hence the table, problem is, if I scroll to the last item in the tableview in the thread, the whole gui thread is 'hogged' cannot do anything else? Is this a problem of updating a widget from within a seperate thread?

This is how I scroll to last item added to tableview within the thread :



QModelIndex index = treeModel->index(nCount-2,0);
m_pCanList->scrollTo(index);


It is the scrollTo function which seems to 'hog' the main gui thread.

I have got round this problem by using a timer event to update the table every millisecond, but thought the thread would be quicker.

Any help, suggestions is much appreciated.

Thanks,
Steve

marcel
8th May 2007, 10:35
Don't scroll from the thread. Instead emit a signal and let the GUI thread scroll the table.
Widgets must not be modified from other threads than the main thread.

That is why the interface gets "hogged" :).

Regards

steg90
8th May 2007, 10:51
Thanks,

Does this mean I need to connect a signal from the thread to some slot in the gui?

For example within my thread I would have :



signals:
void scrolltable( QModelIndex index );


This function would emit a signal, such as:



QModelIndex index = treeModel->index( nCount, 0 );
emit scrolltable( index );


And within my main gui thread, I would have a slot as :



public slots:
void scrollthetable( QModelIndex index );


Which would scroll the table.


How do I connect these signals, would it be something along the lines of ( this would be in main gui thread ) :



connect( tableThread, SIGNAL(scrolltable(QModelIndex)), this,
SLOT(scrollthetable(QModelIndex)) );


Thanks again,
Steve

marcel
8th May 2007, 11:09
Yes, that's it!

Regards

steg90
8th May 2007, 11:47
Thanks again,

I did this but when I call emit from my thread the table still does not scroll?

The code to scroll the table is just :



void CanView::scrolltable( QModelIndex index )
{
ui.tableView->scrollTo( index );
}


The model index is passed in from the thread as follows :



QModelIndex index = m_ptreeModel->index( nCount - 2, 0 );
emit scrolltable( index );


I'm at a loss as to why this does not work?

Any help is appreciated.

Regards,
Steve

marcel
8th May 2007, 11:57
You said


connect( tableThread, SIGNAL(scrolltable(QModelIndex)), this,SLOT(scrollthetable(QModelIndex)) );


but the slot is called scrolltable...
Are you sure the connect is correct? Take a look at it again?
If it is correct, could you look if the slot gets called?

Regards

steg90
8th May 2007, 12:00
Sorry Marcel,

I changed the slot and signal names to scrolltable and yes, the slot does indeed get called. In fact, no data is displayed in the tableview unless I click on it??

Regards,
Steve

marcel
8th May 2007, 12:04
You shouldn't keep the reference to the model in the thread either. Maybe the model index is not valid. Instead passing a QModelIndex, pass an integer ( nCount - 2 ) if you can.

Things should work fine, so the only question is if the model index passed was valid...

marcel
8th May 2007, 12:07
You were creating the model index on the stack. Emitting a signal from a thread will post an event in the thread in which the slot is implemented, it will not call the slot directly.

So the model index you pass gets destroyed before the slot gets called.
Either pass a pointer to a model index, which you will delete in the slot, either a integer and compute the model index in the GUI thread.

steg90
8th May 2007, 12:18
Thanks again Marcel,

I have now done this :



void CanView::scrolltable( int nCount )
{
QModelIndex index = m_pCanReadThread->m_ptreeModel->index( nCount, 0 );
ui.tableView->scrollTo( index );
}


But sadly again, the whole gui is 'hogged'?!

Maybe my design is all wrong?

Regards,
Steve

marcel
8th May 2007, 12:20
Why are you holding the model in the thread? You should keep it in the GUI thread, and modify it via signals/slots.

The thread should only do additional work, not hold interface elements.

Regards

jpn
8th May 2007, 12:21
May I ask what is the thread actually doing? :) I'm not convinced that storing pointers to various GUI objects in a thread object is a good idea (even if you did not actually modify them).

marcel
8th May 2007, 12:21
How often the signal gets emitted anyway?
If it gets really, really often, then you will kill the GUI event handler.
Perhaps you should not emit the scroll signal if the specified index is already visible.

steg90
8th May 2007, 12:33
Hi,

The signal will get emitted something like every millisecond.

How do you work out if the specified index is already visible?

The model is within the thread as the thread updates the model data, is this wrong? I just wanted the thread to read a signal from a car which gives data back and update the model, maybe I should just store the data in a buffer within the thread and send this back to the gui and let the gui update the model?

Example of the run() method :


while( nCount < 10000 )
{
m_ptreeModel->setCanData( QString("0xfea" ) );
m_ptreeModel->setCanData( QString("----" ) );
m_ptreeModel->setCanData( QString("222222222222" ) );
QString strCount;
strCount.sprintf( "%i", nCount );
m_ptreeModel->setCanData( strCount );
// QModelIndex index = m_ptreeModel->index( nCount , 0 );
emit scrolltable( nCount );
nCount++;
}



As you can see, it doesn't do much at the moment...

Thanks,
Steve

marcel
8th May 2007, 12:42
Yes, it is wrong, especially because the signal is emitted 1000 times/second ( this means 1000 events posted each second in the GUI event handler ).

I really don't know how to see if an item is visible, but you should take a look at the implementation of QTableView::scrollTo(). This should give you an idea.

Once you solve this, you solve your problem.


BTW: you shouldn't modify the model in the worker thread. Instead emit a signal with a structure with the data that need to be inserted.

steg90
8th May 2007, 12:46
Thanks again,

It is the scrollto function which seems to take ages, but I know of no other way of making sure the last item inserted is visible...

I put all this stuff into a timer and it works fine, I guess for what I am trying to do, the timer event is the better option.

Thanks for all your help :)

Steve