Beyond QPainter::restore(): Alternative Approaches for State Management in Qt


What is QPainter?

  • It provides methods for drawing lines, shapes, text, images, and more.
  • In Qt, QPainter is a powerful class that allows you to draw various graphical elements on a widget or other paint device.

What does QPainter::save() do?

  • Internally, save() pushes the current state onto a stack.
  • This state includes all the aforementioned settings.
  • To avoid affecting subsequent drawing operations, you can use QPainter::save() to create a snapshot of the current painter state.
  • When you're drawing with QPainter, you might need to temporarily modify its settings, such as the pen (line style and color), brush (fill style and color), font, or transformation (rotation, scaling, etc.).

What does QPainter::restore() do?

  • Essentially, it undoes the effects of the most recent save().
  • This method pops the top state from the stack and restores the painter's settings to that state.
  • After you've made your temporary modifications and want to revert to the settings you had before the save(), you use QPainter::restore().

When to use QPainter::restore()

  • This is useful for drawing specific elements with different settings without affecting the overall drawing style.
  • You typically use restore() in conjunction with save() to create a temporary drawing context.
void MyWidget::paintEvent(QPaintEvent *event) {
    QPainter painter(this);

    // Draw a rectangle with a red pen and a blue brush
    painter.setPen(Qt::red);
    painter.setBrush(Qt::blue);
    painter.drawRect(10, 10, 100, 50);

    // Now, let's draw some text with a different font inside the rectangle
    painter.save(); // Save the current state

    QFont font("Arial", 16); // Create a new font
    painter.setFont(font);

    painter.drawText(QRect(20, 20, 80, 30), Qt::AlignCenter, "This is text");

    // Restore the previous state to use the original pen and brush
    painter.restore();

    // Draw another rectangle with the original settings
    painter.drawRect(150, 10, 100, 50);
}

In this example, save() preserves the initial pen and brush settings. The text is drawn with a different font, and then restore() brings back the original settings for the final rectangle.



Example 1: Drawing a rotated rectangle with restored original state

void MyWidget::paintEvent(QPaintEvent *event) {
  QPainter painter(this);

  // Draw a blue rectangle
  painter.setPen(Qt::blue);
  painter.drawRect(10, 10, 100, 50);

  // Save the current state
  painter.save();

  // Rotate the painter by 45 degrees
  painter.rotate(45);

  // Draw a red rectangle rotated
  painter.setPen(Qt::red);
  painter.drawRect(50, 25, 50, 25);

  // Restore the original state to draw other elements normally
  painter.restore();

  // Draw a green circle
  painter.setPen(Qt::green);
  painter.drawEllipse(150, 25, 30, 30);
}

Example 2: Drawing text with different fonts and styles within one paint event

void MyWidget::paintEvent(QPaintEvent *event) {
  QPainter painter(this);

  // Draw text with a bold font
  painter.setFont(QFont("Arial", 14, QFont::Bold));
  painter.drawText(10, 20, "Bold Text");

  // Save the current state
  painter.save();

  // Draw text with an italic style
  painter.setFont(QFont("Times New Roman", 12, QFont::Italic));
  painter.setPen(Qt::red);
  painter.drawText(10, 40, "Italic Text (Red)");

  // Restore the original state for subsequent drawing
  painter.restore();

  // Draw text with an underlined line
  painter.setPen(Qt::blue);
  painter.setFont(QFont("Courier", 10));
  painter.drawText(10, 60, "Underlined Text");
  painter.drawLine(10, 72, 80, 72);
}
void MyWidget::paintEvent(QPaintEvent *event) {
  QPainter painter(this);

  // Save the current state (initial settings)
  painter.save();

  // Translate to draw a rectangle at a specific location
  painter.translate(50, 20);

  // Draw a blue rectangle
  painter.setPen(Qt::blue);
  painter.drawRect(0, 0, 100, 50);

  // Save the state after drawing the rectangle
  painter.save();

  // Further translate and rotate for a smaller rectangle inside
  painter.translate(30, 15);
  painter.rotate(30);

  // Draw a green rectangle rotated and translated
  painter.setPen(Qt::green);
  painter.drawRect(0, 0, 50, 25);

  // Restore to the state before the inner rectangle
  painter.restore();

  // Draw a text label on top of the blue rectangle
  painter.setFont(QFont("Arial", 10));
  painter.drawText(10, 35, "Label");

  // Restore the initial state for further drawing
  painter.restore();

  // Draw another element at a different location
  // ... (code for other drawing)
}


    • If you need to maintain different painter states for a prolonged period or across multiple paint events, consider creating separate QPainter objects with the desired settings. This avoids the need for frequent save() and restore() calls.
    • However, this approach can increase memory usage, so be mindful if working with a large number of painters.
  1. Resetting Individual Properties

    • In certain cases, instead of restoring the entire state, you might only need to reset specific properties. For example, if you only changed the pen color, you can use painter.setPen(originalPen) instead of restore().
    • This approach can be more efficient for isolated changes but requires careful management of individual properties.
  2. Using a Scoped Painter (Qt 5.15+)

    • Qt 5.15 introduced the QScopedPainter class. This class automatically saves and restores the painter state when it goes out of scope. While it simplifies the use of save() and restore(), it might not be available in older Qt versions.
MethodProsCons
QPainter::restore()Simple, efficient for frequent state changesMay be less efficient for rarely needed state changes
Separate QPainterMaintains independent statesIncreased memory usage for many painters
Resetting PropertiesEfficient for isolated changesRequires managing individual properties
QScopedPainter (Qt 5.15+)Automatic state handlingRequires Qt 5.15 or later

Choosing the right approach depends on your specific needs

  • If you're using Qt 5.15 or later and need automatic state management, QScopedPainter can be helpful.
  • For resetting specific properties, use that property's setter method.
  • If you need to maintain independent states for a long time, consider separate QPainter objects.
  • If you frequently switch states within a single paint event, QPainter::restore() is the most straightforward option.