Как изменить оттенок части сцены?

#c #qt #qt5

#c #qt #qt5

Вопрос:

У меня довольно сложный QGraphicsScene с кучей строк. Я хочу, чтобы очень определенная зона имела другой оттенок. Например, синяя линия, проходящая через эту зону, будет отображаться как красная внутри зоны, но останется синей снаружи.

Естественно, можно было бы просто нарисовать три линии вместо одной, но для этого требуется написать дополнительный код, который определял бы, проходит ли данная линия через определенную зону, и если да, то каковы координаты пересечения. Выполнимо, но не самая простая вещь для программирования. Поэтому, если Qt может сделать это для меня, это было бы очень хорошо.

Возможно ли это и как?

Комментарии:

1. Я не эксперт в этой области, но я хотел бы посмотреть, можете ли вы использовать QOpenGLWidget с эффектом шейдера, чтобы перекрасить область вашей сцены.

Ответ №1:

Решение

Мой подход к проблеме заключается в следующем:

  1. Подкласс QGraphicsRectItem , если зона должна быть прямоугольной, и переопределите его метод рисования
  2. Установите режим композиции QPainter на соответствующее значение, например QPainter::RasterOp_SourceAndNotDestination :
      painter->setCompositionMode(QPainter::RasterOp_SourceAndNotDestination);
     

Примечание: Для разных форм зоны используйте разные графические элементы. Вы также можете поэкспериментировать с режимами композиции, чтобы получить разные эффекты.

Пример

Вот пример, который я написал для вас, чтобы продемонстрировать, как можно реализовать предлагаемое решение:

 #include <QApplication>
#include <QMainWindow>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QPainter>

class HueZone : public QGraphicsRectItem
{
public:
    explicit HueZone(QGraphicsItem *parent = nullptr) :
        QGraphicsRectItem(parent) {}

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override {
        painter->save();
        painter->setPen(pen());
        painter->setBrush(brush());
        painter->setCompositionMode(QPainter::RasterOp_SourceAndNotDestination);
        painter->drawRect(rect());
        painter->restore();
    }
};

class MainWindow : public QMainWindow
{
public:
    MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
        auto *view = new QGraphicsView(this);
        auto *line = new QGraphicsLineItem(10, 20, 400, 300);
        auto *zone = new HueZone();

        line->setPen(QPen(Qt::blue));

        zone->setRect(100, 50, 200, 200);
        zone->setBrush(QBrush(Qt::red));
        zone->setPen(QPen(Qt::transparent));

        view->setScene(new QGraphicsScene(this));
        view->scene()->addItem(line);
        view->scene()->addItem(zone);

        setCentralWidget(view);
        resize(600, 480);
        setWindowTitle("Hue Zone");
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;

    w.show();

    return a.exec();
}
 

Результат

Приведенный выше пример дает следующий результат:

линия через зону оттенка