Стирание закрашенных областей с полупрозрачных виджетов в Qt

Я столкнулся с проблемой стирания ранее окрашенных областей виджета Qt.

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

Заголовок

class ClearBack : public QWidget
{
    Q_OBJECT
public:
    explicit ClearBack(const QPoint &startingPos);

    bool eventFilter(QObject *obj, QEvent *event);
    void paintEvent(QPaintEvent *);
    void mouseMoveEvent(QMouseEvent *event);

signals:
    void regionSelected(const QRect &);

private:
    QRect currentRegion;
};

Реализация

ClearBack::ClearBack(const QPoint &startingPos)
{
    setBackgroundRole(QPalette::Base);
    installEventFilter(this);
    currentRegion.setTopLeft(startingPos);
    currentRegion.setBottomRight(startingPos);
    this->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);
    this->showMaximized();
}

void ClearBack::paintEvent(QPaintEvent * event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(Qt::black);
    painter.drawRect(currentRegion);
}

void ClearBack::mouseMoveEvent(QMouseEvent *event)
{
    QPoint currentPos(event->globalX(), event->globalY());   
    currentRegion.setBottomRight(currentPos);
    this->repaint();
}

На виджете со сплошным фоном эффект работает довольно хорошо, создавая один прямоугольник.

введите здесь описание изображения

Однако, когда фон установлен на setAttribute(Qt::WA_TranslucentBackground);, происходит следующее.

введите здесь описание изображения

Прямоугольники, которые были нарисованы ранее, не "стираются"

Есть ли способ стереть нарисованные ранее прямоугольники на полупрозрачном фоне, и если да, то как?

Также для "бонусных баллов" почему этот эффект возникает на полупрозрачном фоне, а не на сплошном?


person robbmj    schedule 30.12.2013    source источник
comment
Непрозрачный фон ни для чего не использует существующее содержимое экрана. На полупрозрачном фоне нарисованный цвет зависит от текущего цвета на экране.   -  person Ben Voigt    schedule 31.12.2013
comment
Одним из распространенных решений этой проблемы является использование обратимого выделения, например XOR или NOT.   -  person Ben Voigt    schedule 31.12.2013
comment
это звучит интересно, не могли бы вы уточнить?   -  person robbmj    schedule 31.12.2013
comment
Рисунок в режиме XOR описан здесь Qt, кажется, имеет режим XOR.   -  person Ben Voigt    schedule 31.12.2013
comment
спасибо @Ben Voigt, я посмотрю на это.   -  person robbmj    schedule 31.12.2013


Ответы (1)


Виджеты с атрибутом WA_TranslucentBackground не очищают фон автоматически. Вы должны:

  1. Измените режим композиции с SourceOver по умолчанию на Source,

  2. Явно очищаем старый прямоугольник прозрачной кистью,

  3. Закрасьте новый прямоугольник.

Ниже приведен рабочий пример, проверенный под Qt 5. Вы должны нажать мышь, чтобы нарисовать первоначальный прямоугольник и перетащить его; программа завершает работу, когда вы отпускаете кнопку мыши.

#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QMouseEvent>

class ClearBack : public QWidget
{
    Q_OBJECT
    QRect m_currentRegion, m_lastRegion;
public:
    explicit ClearBack(const QPoint &startingPos) :
        m_currentRegion(startingPos, startingPos)
    {
        setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);
        setAttribute(Qt::WA_TranslucentBackground);
        showMaximized();
    }
    Q_SIGNAL void regionSelected(const QRect &);
protected:
    void paintEvent(QPaintEvent *) {
        QPainter painter(this);
        painter.setCompositionMode(QPainter::CompositionMode_Source);
        painter.setRenderHint(QPainter::Antialiasing);
        painter.setPen(QPen(Qt::transparent, 3));
        painter.drawRect(m_lastRegion);
        m_lastRegion = m_currentRegion;
        painter.setPen(Qt::black);
        painter.drawRect(m_currentRegion);
    }
    void mouseMoveEvent(QMouseEvent *event) {
        m_currentRegion.setBottomRight(event->globalPos());
        update();
    }
    void mouseReleaseEvent(QMouseEvent *) {
        emit regionSelected(m_currentRegion);
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ClearBack back(QPoint(200,200));
    a.connect(&back, SIGNAL(regionSelected(QRect)), SLOT(quit()));
    return a.exec();
}

#include "main.moc"
person Kuba hasn't forgotten Monica    schedule 31.12.2013