"Drawing" 在QT中使用完全透明的笔
"Drawing" with a totally transparent pen in QT
我正在用 QT 编写一个白板应用程序。我使用的是双层方法,所以我有一个包含绘图的 QPixmap,另一个包含背景。不出所料,绘图像素图带有 alpha 通道。
现在我想实现一个橡皮擦工具。无论在何处绘制,此工具都应将像素图的颜色恢复为 QColor(255, 255, 255, 0)
(即 - 完全透明)。然而,我的绘画方法并不适用于此。
这是我的绘制例程:
void WhiteBoardWidget::draw(QPointF pos, bool erase) {
QPainter painter( &underlyingImage );
QPen pen = painter.pen();
if( ! erase ) {
pen.setColor(penColor);
pen.setWidth(penWidth);
} else {
pen.setColor( QColor(255, 255, 255, 0) );
pen.setWidth(penWidth * EraserSizeFactor);
}
painter.setPen(pen);
painter.drawLine( lastPoint, pos );
lastPoint = pos;
update();
}
我明白为什么它不起作用(透明笔不会改变像素图,因为它是,等待它......透明)。我只是不确定什么是做我想做的事的好方法。
基于 I will just translate the code to c++
#ifndef DRAWER_H
#define DRAWER_H
#include <QWidget>
enum STATES{
DRAW_STATE,
CLEAR_STATE
};
class Drawer : public QWidget
{
Q_OBJECT
Q_PROPERTY(STATES currentState READ currentState WRITE setCurrentState NOTIFY currentStateChanged)
public:
explicit Drawer(QWidget *parent = nullptr);
STATES currentState() const;
void setCurrentState(STATES newCurrentState);
Q_SIGNALS:
void currentStateChanged();
protected:
void paintEvent(QPaintEvent *);
void resizeEvent(QResizeEvent *);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
private:
QImage background;
QImage foreground;
QPoint lastPoint;
QBrush brushColor;
int brushSize;
bool drawing;
int clearSize;
STATES m_currentState;
};
#endif // DRAWER_H
#include "drawer.h"
#include <QApplication>
#include <QImage>
#include <QMouseEvent>
#include <QPainter>
Drawer::Drawer(QWidget *parent) :
QWidget(parent), brushColor(Qt::black), brushSize(2), drawing(false), clearSize(10), m_currentState(DRAW_STATE)
{
background = QImage(100, 100, QImage::Format_ARGB32);
background.fill(Qt::white);
foreground = QImage(100, 100, QImage::Format_ARGB32);
foreground.fill(Qt::transparent);
}
STATES Drawer::currentState() const
{
return m_currentState;
}
void Drawer::setCurrentState(STATES newCurrentState)
{
if (m_currentState == newCurrentState)
return;
m_currentState = newCurrentState;
Q_EMIT currentStateChanged();
if(m_currentState == CLEAR_STATE){
QPixmap pixmap(QSize(1, 1)* clearSize);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setPen(QPen(Qt::black, 2));
painter.drawRect(pixmap.rect());
painter.end();
QCursor cursor(pixmap);
QApplication::setOverrideCursor(cursor);
}
else if (m_currentState == DRAW_STATE) {
QApplication::restoreOverrideCursor();
}
}
void Drawer::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawImage(QPoint(0, 0), background);
painter.drawImage(QPoint(0, 0), foreground);
}
void Drawer::resizeEvent(QResizeEvent *)
{
bool changeSize = (width() > foreground.width()) || (height() > foreground.height());
if(changeSize){
QSize s(std::max(width(), background.width()), std::max(height(), background.height()));
background = QImage(s, background.format());
background.fill(Qt::white);
QImage newForeground = QImage(s, foreground.format());
newForeground.fill(Qt::transparent);
QPainter painter(&newForeground);
painter.drawImage(QPoint(0, 0), foreground);
painter.end();
foreground = newForeground;
}
}
void Drawer::mousePressEvent(QMouseEvent *event)
{
if(event->buttons() & Qt::LeftButton){
drawing = true;
lastPoint = event->pos();
update();
}
}
void Drawer::mouseMoveEvent(QMouseEvent *event)
{
if(event->buttons() & Qt::LeftButton && drawing){
QPainter painter(&foreground);
painter.setPen(QPen(brushColor, brushSize, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
if(m_currentState == CLEAR_STATE){
QRect r(QPoint(), clearSize*QSize());
r.moveCenter(event->pos());
painter.save();
painter.setCompositionMode(QPainter::CompositionMode_Clear);
painter.eraseRect(r);
painter.restore();
}
else if(m_currentState == DRAW_STATE){
painter.drawLine(lastPoint, event->pos());
}
painter.end();
lastPoint = event->pos();
update();
}
}
void Drawer::mouseReleaseEvent(QMouseEvent *event)
{
if(event->buttons() & Qt::LeftButton){
drawing = false;
update();
}
}
#include "drawer.h"
#include <QApplication>
#include <QPushButton>
#include <QVBoxLayout>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton *button = new QPushButton("Clear");
button->setCheckable(true);
Drawer *drawer = new Drawer;
QObject::connect(button, &QPushButton::toggled, [drawer, button](bool checked){
if(checked){
drawer->setCurrentState(STATES::CLEAR_STATE);
button->setText("Draw");
}
else{
drawer->setCurrentState(STATES::DRAW_STATE);
button->setText("Clear");
}
});
QWidget widget;
QVBoxLayout *lay = new QVBoxLayout(&widget);
lay->addWidget(button);
lay->addWidget(drawer);
widget.resize(640, 480);
widget.show();
return a.exec();
}
这是 QPainter
的 composition mode 正在使用的问题。默认为 QPainter::CompositionMode_SourceOver
,因为当前的笔是透明的,所以它只离开地下。通过设置为 QPainter::CompositionMode_Clear
,您可以强制画家擦除任何内容。那时您甚至不必更改当前笔的颜色。
我正在用 QT 编写一个白板应用程序。我使用的是双层方法,所以我有一个包含绘图的 QPixmap,另一个包含背景。不出所料,绘图像素图带有 alpha 通道。
现在我想实现一个橡皮擦工具。无论在何处绘制,此工具都应将像素图的颜色恢复为 QColor(255, 255, 255, 0)
(即 - 完全透明)。然而,我的绘画方法并不适用于此。
这是我的绘制例程:
void WhiteBoardWidget::draw(QPointF pos, bool erase) {
QPainter painter( &underlyingImage );
QPen pen = painter.pen();
if( ! erase ) {
pen.setColor(penColor);
pen.setWidth(penWidth);
} else {
pen.setColor( QColor(255, 255, 255, 0) );
pen.setWidth(penWidth * EraserSizeFactor);
}
painter.setPen(pen);
painter.drawLine( lastPoint, pos );
lastPoint = pos;
update();
}
我明白为什么它不起作用(透明笔不会改变像素图,因为它是,等待它......透明)。我只是不确定什么是做我想做的事的好方法。
基于
#ifndef DRAWER_H
#define DRAWER_H
#include <QWidget>
enum STATES{
DRAW_STATE,
CLEAR_STATE
};
class Drawer : public QWidget
{
Q_OBJECT
Q_PROPERTY(STATES currentState READ currentState WRITE setCurrentState NOTIFY currentStateChanged)
public:
explicit Drawer(QWidget *parent = nullptr);
STATES currentState() const;
void setCurrentState(STATES newCurrentState);
Q_SIGNALS:
void currentStateChanged();
protected:
void paintEvent(QPaintEvent *);
void resizeEvent(QResizeEvent *);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
private:
QImage background;
QImage foreground;
QPoint lastPoint;
QBrush brushColor;
int brushSize;
bool drawing;
int clearSize;
STATES m_currentState;
};
#endif // DRAWER_H
#include "drawer.h"
#include <QApplication>
#include <QImage>
#include <QMouseEvent>
#include <QPainter>
Drawer::Drawer(QWidget *parent) :
QWidget(parent), brushColor(Qt::black), brushSize(2), drawing(false), clearSize(10), m_currentState(DRAW_STATE)
{
background = QImage(100, 100, QImage::Format_ARGB32);
background.fill(Qt::white);
foreground = QImage(100, 100, QImage::Format_ARGB32);
foreground.fill(Qt::transparent);
}
STATES Drawer::currentState() const
{
return m_currentState;
}
void Drawer::setCurrentState(STATES newCurrentState)
{
if (m_currentState == newCurrentState)
return;
m_currentState = newCurrentState;
Q_EMIT currentStateChanged();
if(m_currentState == CLEAR_STATE){
QPixmap pixmap(QSize(1, 1)* clearSize);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setPen(QPen(Qt::black, 2));
painter.drawRect(pixmap.rect());
painter.end();
QCursor cursor(pixmap);
QApplication::setOverrideCursor(cursor);
}
else if (m_currentState == DRAW_STATE) {
QApplication::restoreOverrideCursor();
}
}
void Drawer::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawImage(QPoint(0, 0), background);
painter.drawImage(QPoint(0, 0), foreground);
}
void Drawer::resizeEvent(QResizeEvent *)
{
bool changeSize = (width() > foreground.width()) || (height() > foreground.height());
if(changeSize){
QSize s(std::max(width(), background.width()), std::max(height(), background.height()));
background = QImage(s, background.format());
background.fill(Qt::white);
QImage newForeground = QImage(s, foreground.format());
newForeground.fill(Qt::transparent);
QPainter painter(&newForeground);
painter.drawImage(QPoint(0, 0), foreground);
painter.end();
foreground = newForeground;
}
}
void Drawer::mousePressEvent(QMouseEvent *event)
{
if(event->buttons() & Qt::LeftButton){
drawing = true;
lastPoint = event->pos();
update();
}
}
void Drawer::mouseMoveEvent(QMouseEvent *event)
{
if(event->buttons() & Qt::LeftButton && drawing){
QPainter painter(&foreground);
painter.setPen(QPen(brushColor, brushSize, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
if(m_currentState == CLEAR_STATE){
QRect r(QPoint(), clearSize*QSize());
r.moveCenter(event->pos());
painter.save();
painter.setCompositionMode(QPainter::CompositionMode_Clear);
painter.eraseRect(r);
painter.restore();
}
else if(m_currentState == DRAW_STATE){
painter.drawLine(lastPoint, event->pos());
}
painter.end();
lastPoint = event->pos();
update();
}
}
void Drawer::mouseReleaseEvent(QMouseEvent *event)
{
if(event->buttons() & Qt::LeftButton){
drawing = false;
update();
}
}
#include "drawer.h"
#include <QApplication>
#include <QPushButton>
#include <QVBoxLayout>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton *button = new QPushButton("Clear");
button->setCheckable(true);
Drawer *drawer = new Drawer;
QObject::connect(button, &QPushButton::toggled, [drawer, button](bool checked){
if(checked){
drawer->setCurrentState(STATES::CLEAR_STATE);
button->setText("Draw");
}
else{
drawer->setCurrentState(STATES::DRAW_STATE);
button->setText("Clear");
}
});
QWidget widget;
QVBoxLayout *lay = new QVBoxLayout(&widget);
lay->addWidget(button);
lay->addWidget(drawer);
widget.resize(640, 480);
widget.show();
return a.exec();
}
这是 QPainter
的 composition mode 正在使用的问题。默认为 QPainter::CompositionMode_SourceOver
,因为当前的笔是透明的,所以它只离开地下。通过设置为 QPainter::CompositionMode_Clear
,您可以强制画家擦除任何内容。那时您甚至不必更改当前笔的颜色。