Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QT - best painting "canvas" for different purposes

Tags:

c++

graphics

qt

I'm programming my bachelor's thesis application and there will be three different types of drawings. I need to render/draw/paint fractal structures made by:

  1. Iterated function systems (draw line or simple path, make copy of the drawing (or part of it), do a few transformations with the copy and draw it iteratively)
  2. Escape time algorithm (go through each pixel of the canvas, calculate its color and color the pixel in)
  3. Elliot waves samples (path through given points - time sequence graph; graph will be made by many points and it won't fit on the screen, so I'll need some simple control of move (two buttons with click event are good enough))

Now, my question is, can you please recommend some Qt method, which suits my purposes (the easiest one, if it's be possible)?

I found these ones:

  1. Qt Graphics View Framework (I think, this is too "heavy")
  2. Draw into the pixmap
  3. Inherit widget and override paintEvent (as it is showed in the Basic Drawing Example of Qt)
  4. Qt Canvas of Qt Quick (but I don't know anything about it)

Should I choose some of these options or anything else?
Thank you very much, you'll be very helpful.

like image 986
Honza Avatar asked Apr 04 '14 16:04

Honza


1 Answers

Re 1. QPainter on anything (a widget, a pixmap, a printer,...) is a simple choice.

Re 2. Work on pixels in the QImage, then draw the image on a painter.

Re 3. Painting on a widget is sufficient. You can base your widget on QAbstractScrollArea.

The biggest point of the Graphics View Framework is interactivity with items in the scene. It makes life much easier then, and should be used to one's advantage.

If your view is non-interactive, then the only benefit would be the binary space partitioning index that culls the amount of work needed to do partial updates or updates when zoomed in. Unless you allow zooming in/panning, or do partial changes, it's pointless, since Qt windows are double-buffered and you essentially never do partial painting. For partial changes, the changed items need to be reindexed unless their geometry remains constant.

With panning/zooming, you should only use the graphics view if you have no easy way of iterating a subset of items to be drawn. The "hard" but generic way of doing it is to have a BSP index, and the Graphics View system provides this. I think in your case it should be easy to iterate over items/primitives that are within a given scene rectangle.

For drawing using QPainter, it doesn't matter really what you draw on, it's a minor detail. You can factor out your drawing into a class that holds the data that needs to be drawn, for example:

class IRenderable {
protected:
  /// Implementation of rendering.
  virtual void renderImpl(QPainter & painter, QRect target) = 0;
public:
  /// Draws all data (or the current view of it) 
  /// on the \a target rectangle of the \a painter.
  void render(QPainter & painter, QRect target) {
    renderImpl(painter, target);
  }
};

class IteratedFunctionSystem : public IRenderable {
  ... // members describing the IFS etc.

  /// Draws the entire IFS on the \a target rectangle of the \a painter.
  void renderImpl(QPainter & painter, QRect target) Q_DECL_OVERRIDE;
public:
  ...
};

You can then use it in a generic widget:

class RenderableVisualizer : public QWidget {
  QSharedPointer<IRenderable> m_renderable;
  void paintEvent(QPaintEvent * ev) {
    QPainter painter(this);
    m_renderable->render(painter, rect());
  }
public:
  RenderableVisualizer(
    QSharedPointer<IRenderable> renderable, QWidget * parent = 0
  ) : QWidget(parent), m_renderable(renderable)
  {}
};

This approach could be extended to add an option to RenderableVisualizer to have a local backing store and render to it from a separate thread. It'd provide smoother GUI operation if the rendering were to be lengthy.

like image 113
Kuba hasn't forgotten Monica Avatar answered Oct 07 '22 12:10

Kuba hasn't forgotten Monica