PDA

View Full Version : Wacky QScrollBar behaviour: setSliderPosition vs sliderPosition



0null0
3rd February 2013, 13:22
Hi all. I'm new to Qt, just setup ver. 5.0.0. Good to be here.

I'm coding a small app, like a Ms Notepad with tabs for multiple documents. I have a single QPlainTextEdit and QTabBar to change contents of the text edit.

With each open document, to remember where the viewport was set, I save three parameters of its scrollbar: minimum, maximum, and position (tried both sliderPosition and value). When user goes back to the document, I set these values again - min, max, and then value. Problem is, the scrollbar sets itself to more or less offset values, immediately after the setters are called, so my ingenious method of preserving each document's viewport doesn't work. Could you please help me understand why the scrollbar behaves this way, and perhaps help me fix it? Thanks.

P.S. My app is really simple, so I attached the whole thing, should anyone be so kind as to have a look; hope it's alright.

Santosh Reddy
4th February 2013, 13:47
This should work


void MainWindow::changeActivePage(int d32Index) {
if (this->mapTabsToPages.contains(d32Index)) {
if (this->d32CurrentTab > -1) {
Page* pCurPage = this->mapTabsToPages.value(this->d32CurrentTab);
pCurPage->d32ScrollPosition = this->textEdit->verticalScrollBar()->value();
}

Page* pNewPage = this->mapTabsToPages.value(d32Index);
this->textEdit->setPlainText(pNewPage->getText());
this->d32CurrentTab = d32Index;
this->textEdit->verticalScrollBar()->setValue(pNewPage->d32ScrollPosition);
}
}


I see another problem in the code (may be you are aware of this). When page (tab) is changed, then content (modifications) are lost, and this change in the test content will make the scroll bars maximum value change, and may cause unexpected behaviour. So the suggested code will work for un-modified text / properly saved data only

0null0
4th February 2013, 14:13
Thanks for replying!

The code you posted is pretty much what I started with. Unfortunately, for some reason it doesn't work. Don't know if it's just my environment, but if I open a file that requires scrolling, scroll it, say, somewhere below the middle, then open another file and get back to the first file's tab, position goes anywhere from a few lines to half of the file below the correct, saved one. Now, if you switch a few times between those files without touching the scrollbar, pretty soon the document will scroll to the outer space, and beyond.

I checked values of scrollbar's minimum(), maximum() and value() right after setting them, and they're always different, with no apparent connection to correct values. I tried calling things like update() on both the scrollbar and the text edit, but it didn't help.

Does this code work for you, for example in a situation similar to what I desribed?


My application works only for opening files at the moment. But modifications to opened files are remembered across tabs when I test it. Strange.

EDIT: You were right about saving changes. One line of code got lost in the process of debugging:P Thanks for pointing that out.

Santosh Reddy
4th February 2013, 14:40
The code you posted with the modification I suggested works perfectly for me. (I am not editing any files).

You don't need to store min, max values, they will be calculated automatically. All you need to worry is about the value (the current position) of the scroll bar.

0null0
4th February 2013, 17:11
Now that's disturbing. On my machine, in debug (I'm using VS2010) the code obviously works buggy. Since it works for you, I tried compiling it with release settings, and the app builds allright, but doesn't start at all. It just dies immediately, no errors. Tried running it outside VS, same result. I'll investigate this further, perhaps it's some problem with my Qt installation? It would be strange, but it could be.

Added after 1 58 minutes:

Got release executable to work - just some missing libraries.

Unfortunately it behaves exactly like debug one - with scrollbar jumping all over the place. May I ask which Qt version and compiler you use? I'm running out of ideas where the culprit might be.

norobro
4th February 2013, 18:33
I see the behavior that you describe in files that have lines long enough to require wrapping.

Works fine with word wrapping turned off.

Santosh Reddy
4th February 2013, 18:50
Are you sure you are running the same code you posted with the modification suggested.

I checked this on Qt 4.8.1 MinGw 4.6.2

0null0
4th February 2013, 19:35
norobro, you're right. With line wrapping turned off everythings works fine. Certainly narrows down the spectrum of possible problems.

Santosh Reddy: same exact code, with your snippet replacng my function. Exactly same behaviour. I'm using Qt 5.0.0 with VS2010. But since norobro notices the problem too, now I doubt it's the version that causes the difference. If you have time, could you see if the code works with word wrapping on, on a document with long lines?

norobro
4th February 2013, 21:23
I see the behavior with Qt 4.8.0 and Qt 5.0.0.

Try using a QTextEdit in lieu of a QPlainTextEdit. That seems to work.

Santosh Reddy
5th February 2013, 17:11
Ok, with long (word warpped lines) I can see the problem.

But it make sense to me. Look you capture the scroll bar position when the text the visible (already rendered), but when you load the text again (note that you are calling setText() again) the new text has to be rendered, and it is only after rendering that it is possible to know the line warp is required or not, or at lest some metric calculation has to be done, but any such calculation is not triggered untill the widget is repainted.

- It is better to set the scroll position value in a slot connected to textChanged() signal
or
- Do not call setText() when the tab is selected, (then you don;t need to set the scroll value either)

0null0
10th February 2013, 14:30
Sorry for late reply.

QTextEdit works indeed. Unfortunately, automatically it looses QPlainTextEdit's property of scrolling line by line. I guess I'll try working on emulating this when I have more time. Still, it would be nice to have working QPlainTextEdit instead of implementing workarounds, and loosing performance of plain text control.

Santosh Reddy:
Well, if I don't call setText() when the tab is selected then I need a new text edit control for each open document, and that wouldn't be any good, IMO. Tried connecting to textChanged(), didn't help.

Your explanation makes sense. What doesn't is how QPlainTextEdit handles this. If scrollbar position is set then the only way it makes sense is to apply the value after everything's been measured - translate it accordingly right before painting the control. Otherwise we get what we get, which is ridiculous non-usable values.

I tried skimming through code and comparing both controls to see if I can code a quick fix for this, but it'll require more time and effort.

Thank you both for your help!