PDA

View Full Version : Timebar Widget - What is the best approach to implement this in Qt?



xdn
2nd November 2015, 12:34
Hi everyone,

I am in need of a Timebar widget and would like some advice on how to best implement this in Qt. To give you a better idea, I attached two rough drawings of the widget at two different zoom levels:
11491

The widget should provide the following main features:
- on top a basic timeline
- timestamps shown at regular intervals
- markers (and other things) that can be positioned and interacted with at various timepoints
- scrolling horizontally
- a zoom function (you can see in the picture that this should only increase the time-resolution and things like markers, timestamps etc are not changed in size)
- timestamps (and other things) are shown/hidden dynamically based on the zoom level

My first idea was to use a QGraphicsScene/-View for this, because those provide many of the elements I want.
I wrote a quick prototype and ran into the problem that the large number of timestamps and vertical time-point bars quickly causes performance issues.
Let's say I want to represent a timespan of only 1h up to miliseconds, that's already 3600000 timestamp objects that need to be shown/hidden based on the zoom level.
How could this be implemented in a less performance hungry way?

Thanks for any hints,
xdn

Cruz
2nd November 2015, 17:40
I would start with a blank QWidget and manually implement all the custom drawing in the QPaintEvent and the handling in the QMouseEvents and QKeyboardEvents. It doesn't seem like an overly complex widget, so it wouldn't be so much work, but you do have specific requirements that are not delivered out of the box by existing components. Most of the drawing can be done by drawing lines here and there. You would get maximum performance by knowing exactly what and where to draw at a specific zoom level as opposed to the graphics view framework's generic methods of object selection. Drawing more than three million lines will take forever, no matter which method you use, but if you do it yourself, you can intelligently compute which lines you do need to draw and which ones you do not. For example, your screen can only show maybe 2000 pixels in the horizontal direction depending on your resolution. There is no point to ever draw more lines than that.

xdn
3rd November 2015, 10:15
I see. Starting from scratch (as in QWidget) would certainly give me the greatest flexibility.
I've never done much in the way of using paintEvents and I'm sure there are quite a few mistakes one can make to cripple drawing performance.
Do you happen to know any good custom widget examples that I could look into to get me started?

Cruz
3rd November 2015, 16:57
Well, there is the Qt basic drawing example (http://doc.qt.io/qt-5/qtwidgets-painting-basicdrawing-example.html), but unfortunately it is anything but basic. It shows a lot of confusing things that you don't need for drawing, but it does not show the simplest possible use case: drawing a line. Here, I give you a simple example:

Subclass QWidget:



class YourWidget: public QWidget
{
Q_OBJECT

public:
YourWidget(QWidget* parent=0);
~YourWidget();

protected:
void paintEvent(QPaintEvent*);
};


Implement paintEvent:



void YourWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setPen(Qt::blue);
painter.drawLine(0, 0, width(), height()); // draws a diagonal line across your widget
painter.setFont(QFont("Arial", 30));
painter.drawText(rect(), Qt::AlignCenter, "Your Widget"); // writes text onto your widget
}


This should draw a diagonal line across your widget and writes some text onto it. You can construct your whole time line widget from lines and text. I can't imagine what you could possibly do so wrong that it entirely breaks performance. Once you have lines and text under control, you can study the
QPainter (http://doc.qt.io/qt-5/qpainter.html) documentation and proceed to more advanced drawing techniques. You can draw arcs and circles, rectangles, polygons, compound shapes, and use brushes and transparency for cool visuals. Happy studying.

Added after 39 minutes:

One more remark to your original question. When you learn how to draw lines, to do it fast means avoiding to draw unnecessary lines. For example, it does not make sense to draw three million lines on the millisecond resolution when you are showing a whole hour on your time line. Implement a zoom level based logic that decides when to draw down to the minute, second, or millisecond level. And as a more generic approach, you can determine if multiple vertical lines would be drawn on the same pixel. Say if you have 2000 pixels available in the horizontal direction, and you would want to draw three million lines onto them, then it is clear that many many lines would have to be drawn at the same horizontal coordinate. You can discard all but one of them and save yourself heaps of drawing time.

anda_skoa
3rd November 2015, 18:07
There is also QPainter::drawLines() which can be faster than multiple drawLine() calls.

Cheers,
_