setAutoScroll with QTreeView and custom model does not work - c++

I have made a QTreeView to display a very large and continuous data set. Since the data set is continuous, I delete initial rows when the total number of rows is greater than a specified amount.
I have used a custom model for this purpose
The whole system is working correctly and displaying data.
But I want it to autoscroll to the bottom to display latest data. If i use scrollToBottom at row addition it completely slows down the entire view-model. But If i use m_pTreeView->setAutoScroll at the start, it has not effect.
Moreover if i click on the view, it completely slows down.
I am using Qt 4.7.1
How should I auto scroll to the bottom without compromising on performance?
And show I remove the lag/drastic performance hit when I click on the view?
the whole code is available at this repo:
https://github.com/daniyalyasin93/qt_qtreeview_hugedata/

Related

How to force QChartView to paint only part of itself

I'm building an application that plots measurement data using the QtCharts library. Some important things that should be mentioned are:
I am dealing with time series.
The measurement data is obtained offline, which means it has already been obtained. My program just reads it from the file and displays it.
I am working with a for-loop that takes the data points as chunks of a fixed size (say 10000) and adds them to the scatter series. This way, the data is being "replayed" and the user can see the progression of the measurement data at many intermediate time points and not just after all data points have been plotted.
I am working with a whole lot of data points, on the order of millions.
At every iteration of the loop a new QScatterSeries is created, data points are appended, the scatter series is added to the chart and then the chart view is repainted. In the beginning it is quite fast, but as time progresses the number of points to be painted increases and the painting process becomes slower and slower.
I know for a fact that I can reimplement the paintEvent of the chart view class to get it to redraw only part of itself. I think I can make it faster by updating only the parts that have new data points. I will just calculate the coordinates of the region where new data points were added and use the paintEvent. But how do I do it? I tried using the setClipRect() method of QPainter, but couldn't do it. Thanks in advance.
QGraphicsView/QGraphicsItem don't implement it.
They don't because it's unfortunately generally impossible: the displayed items (e.g. series) are scaled and antialiased. In the old days when everything was displayed in device units, and was drawn directly on the window, doing partial updates made sense: you'd first use a fast blit to shift the existing plot, and then draw new points.
Alas, in any non-trivial scene viewer, the relationship between the horizontal device (widget) units and the item (chart/series) units is not 1:1, so there's no general way to scroll the data in device units and have it still make sense in chart units.
There are is a workaround: Scroll by some larger-than-needed (rounded up) number of device units, then back-calculate what scroll it yields in chart units, and then offset the chart by such a number (i.e. move the X axis range accordingly).
This could be implemented with relative ease in the sources of the QGraphicsView system, as the chart builds on it. There's no way to "bolt this on" externally - you need to add such support directly to QGraphicsView and QGraphicsItem infrastructure, and then have the QChartView leverage it. If you're not in the habit of building your own Qt, you can of course copy the necessary classes over to your codebase and rename them.

How to provide a custom column width calculation for CListCtrl?

I'm using a CListCtrl with my own "DrawItem" to draw some custom graphics into the first column, in front of the text. The text is moved ~20 pixels to the right for this. That part works.
If the user double-clicks the column divider in the header, Windows calculates the best column width. But of course Windows doesn't know my custom drawing. So the result is ~20 pixels too small for the first column.
How can I correct that?
Found a workaround:
I can trick MFC into thinking that the list control uses checkboxes:
pMyList->SetExtendedStyle(pMyList->GetExtendedStyle() | LVS_EX_CHECKBOXES);
The user will never ever see the system's checkboxes (because of my custom drawing), but this gives me just the space that I need.

Infragistics UltraGrid rows displayed from bottom to top

I need to display rows in UltraGrid starting from bottom and going towards the top rather then normally where they are displayed from the top to the bottom.
Is there a setting of a property that needs to be set to achieve this display? I can't seem to find it.
Example of required layout
This functionality isn't built into the WinGrid control and you should log a new product idea on the NetAdvantage for Windows Forms product idea page for this if you are looking for this functionality.
You may be able to do something like this using a creation filter to move the existing rows if there are not enough rows to fill the grid. If you do pursue this you would still need to sort the rows so that they are already in the correct order first and they you would move the existing rows down when they don't fill the entire grid. There are more details on creation filters in the help.

Blinking issue when using QListWidget in batched mode

When using a QListWidget in batched layout mode, whenever more items are added than the batch size, the list widget blinks for a short time when switching from the old list to the new list. This means, the list widget shows no items, and the scroll bar handle is set to a seemingly random size.
Have you ever encountered this, can this be resolved somehow? I'm using Qt 4.7.4. I should probably add that I'm not using any hidden items.
I had this issue also and spent hours combing through the sea that is Qt widget rendering. Ultimately, like you, I traced the problem back to the batch processing of the QListView. It appears, that when batch processing is enabled, Qt fires off an internal timer to perform incremental layout adjustments of the underlying scroll view. During these incremental layouts, when the scroll bar is visible, the update region is not computed correctly (it's too big and does not account for the regions occupied by the scroll widget(s) themselves). The result is a bad update region that subsequently finds its way into the viewport update which has the unfortunate side-effect of clearing the entire client area without rendering any of the ListViewItems.
Once the batch processing is complete, the final viewport update correctly computes the layout geometry (with the scroll bar) and produces a valid update region; the visible elements in the list are then redrawn.
The behavior worsens as the number of items in the list grows (relative to the batch size). For example, if your list grows from 500 to 50000 items and a batch size of 50, there is a proportionate increase in the number of "bad repaint" events which are triggered causing the view to visibly flicker even more. :(
These incremental (and failed) viewport updates also appear to be cause the apparent spazmodic behavior in the scrollbar handle position that you describe.
The root of this issue appears related to this "hack" that was added to
QListView::doItemsLayout() as commented here:
// showing the scroll bars will trigger a resize event,
// so we set the state to expanding to avoid
// triggering another layout
QAbstractItemView::State oldState = state();
setState(ExpandingState);
I suppose you could override QListView::doItemsLayout() and provide your own batch processing which handles scroll bars properly, but personally I'm too old and lazy to be cleaning up someone else's poo. Switching to SinglePass eliminated the problem entirely. Seamless flicker-free rendering and the scroll bar behavior you've come to expect and love. Yay.

How to display scrollbar for a list view whose contents keep changing?

I have a ListView-like control that displays a list of items of various heights. The contents of the list, and the heights of the items can change – a background thread is populating the list and calculating the layout of each item, possibly even while the user is scrolling the content.
Which brings me to my question: How do I display a useful vertical scrollbar for this view? I’ve seen cases (notably web browsers) where the slider “jumps away” from the mouse cursor while the user is dragging it, the result of the underlying content growing in height. I don’t want that.
So far
Instead of the slider representing the viewport height relative to the content height, maybe it could represent a point in a timeline instead? (The items are sorted by timestamp). This would at least prevent the scrollbar from changing as item layouts are calculated.
Get rid of the scrollbar altogether and use a forward/backward rocker switch like the one used in Picasa (the further the slider is pulled upwards or downwards, the faster the view is scrolled, until the user releases the slider). If I take this route, are there any controls you can recommend?
I am using Qt, but this applies to UI design in general.
IMO the fundamental problem with a classic scrollbar is that due to background population, the valid range is changing - and thus, the meaning of a scrollbar position changes.
If you can predict the full range of items, you can still provide a scrollbar and replace yet-unknown items with "loading...".
Otherwise, a rocker (is that an official name?) would be the next best thing to use.
However, since you have a dedicated scale (timeline), it might be better to have separate buttons that jump a dedicated time (e.g. one minute, one hour, one day, ..). For a fancier look, you could create a rocker with "hot" areas that jump for a specific time, whereas the areas inbetween are interpolated (linear or or logarithmic, depending on the scale to cover).
i.e. line this (drawing just the "backward" half):
--------------------------
|##|XXXXXXX|##|XXXXXXX|##|
--------------------------
-1h -1m -1s