4.QPixmap,QTransform,绘图函数的使用

本文介绍了一个使用Qt进行自定义绘图的示例项目,详细展示了如何通过Qt的绘图API来绘制图形、文本等元素,并应用了多种绘图技巧如抗锯齿、坐标变换等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


  1. 新建一个项目Painter

MyWidget.h

#ifndef MYWIDGET_H

#define MYWIDGET_H

 

#include <QWidget>

 

class MyWidget : public QWidget

{

    Q_OBJECT

public:

    explicit MyWidget(QWidget *parent = 0);

    void paintEvent(QPaintEvent *);

 

signals:

 

public slots:

 

};

 

#endif // MYWIDGET_H

MyWidget.cpp

#include "MyWidget.h"

#include <QPainter>

#include <QPixmap>

#include <QApplication>

 

MyWidget::MyWidget(QWidget *parent) :

    QWidget(parent)

{

}

 

void MyWidget::paintEvent(QPaintEvent *)

{

    QPixmap pixmap(size());

 

    QPainter p(&pixmap);

 

    //p.translate(100, 100);

    //p.scale();

    //消除锯齿

    p.setRenderHint(QPainter::Antialiasing);

    //转换

    QTransform transform;

    transform.translate(50,50);

    //旋转30

    transform.rotate(30);

   // transform.scale(.5, .5);

    p.setTransform(transform);

#if 1

    //下面的transform可以覆盖上面的一个transform的效果

    QTransform transform2;

    //对整个效果进行缩放

    transform2.scale(.5, .5);

    //最后一个参数实现和上面一个transform实现组合

    p.setTransform(transform2, true);

#endif

    //通过两个点实现画线

    p.drawLine(QPoint(0, 0), QPoint(100, 100));

 

    //p.translate(-100, -100);

    //钢笔

    p.setPen(QPen(Qt::red, 2, Qt::DashLine));

    //使用刷子

    p.setBrush(Qt::yellow);

    //设置刷子

    p.setFont(QFont("aaa", 40, 700, true));

 

    p.drawEllipse(QPoint(95, 333), 50, 50);

    //里面写上文字

    p.drawText(QPoint(300, 50), "Hello world");

    //p.drawPixmap(QPoint(40, 40), QPixmap("../aaa.png"));

    //p.drawRect(QRect(40, 60, 100, 50));

    //下面的方式实现画一个圆角矩形

    p.drawRoundRect(QRect(40, 60, 100, 50));

 

    p.end();

 

    p.begin(this);

    //通过下面的方式实现画图,之所以运行的结果是黑丝的图,是因为加的是pixmap

    p.drawPixmap(0, 0, pixmap);

}

 

int main(int argc, char** argv)

{

    QApplication app(argc, argv);

 

    MyWidget w;

    w.show();

 

    return app.exec();

}

运行结果:

 

 

 

 

 

import os import sys import numpy as np from PyQt5.QtWidgets import (QGraphicsView, QGraphicsScene, QGraphicsPixmapItem, QRubberBand, QApplication, QGraphicsPathItem, QMenu) from PyQt5.QtGui import (QPixmap, QImage, QPainter, QPen, QColor, QBrush, QKeyEvent, QTransform, QPainterPath, QCursor, QPolygonF) from PyQt5.QtCore import (Qt, QPoint, QRect, QSize, QEvent, QPointF, QRectF, pyqtSignal, QTimer, QLineF, QVariantAnimation) class ImageCanvas(QGraphicsView): # 信号定义 zoom_changed = pyqtSignal(float) image_changed = pyqtSignal(QImage) mouse_position_changed = pyqtSignal(QPointF, str) selection_changed = pyqtSignal(QRectF) tool_changed = pyqtSignal(int) # 工具枚举 TOOL_SELECT = 0 TOOL_CROP = 1 TOOL_BRUSH = 2 TOOL_SHAPE = 3 TOOL_TEXT = 4 TOOL_ERASER = 5 def __init__(self, parent=None): super().__init__(parent) self.parent_window = parent self.setRenderHint(QPainter.Antialiasing) self.setRenderHint(QPainter.SmoothPixmapTransform) self.setDragMode(QGraphicsView.ScrollHandDrag) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QGraphicsView.AnchorUnderMouse) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setInteractive(True) self.viewport().setCursor(Qt.CrossCursor) # 创建场景 self.scene = QGraphicsScene(self) self.setScene(self.scene) self.scene.setBackgroundBrush(QBrush(QColor(50, 50, 50))) # 初始化变量 self.zoom_factor = 1.0 self.min_zoom = 0.05 self.max_zoom = 50.0 self.original_image = QImage() self.displayed_image = QImage() self.current_image_item = None self.saved_transforms = None # 工具相关状态 self.rubber_band = QRubberBand(QRubberBand.Rectangle, self.viewport()) self.rubber_band.hide() self.selection_rect = QRectF() self.selection_active = False self.selection_start = QPointF() # 当前工具状态 self.current_tool = self.TOOL_SELECT self.tool_settings = { 'brush_size': 5, 'brush_color': QColor(255, 0, 0, 255), 'eraser_size': 20, 'shape_type': 0, # 0:矩形, 1:圆形, 2:直线 'antialias': True, 'opacity': 1.0 } # 绘制相关状态 self.drawing_active = False self.drawing_path = None self.drawing_item = None self.drawing_start = QPointF() self.current_layer = 0 self.layers = [] # 初始化默认图层 self.add_new_layer("Background", QColor(255, 255, 255)) # 历史记录快照 self.snapshots = [] self.current_snapshot = -1 # 安装事件过滤器 self.viewport().installEventFilter(self) # 状态提示定时器 self.status_timer = QTimer(self) self.status_timer.setSingleShot(True) self.status_timer.timeout.connect(self._clear_status) # ==================== 图层管理功能 ==================== def add_new_layer(self, name, fill_color=QColor(0, 0, 0, 0)): """添加新图层""" layer = { 'name': name, 'visible': True, 'locked': False, 'opacity': 1.0, 'image': QImage(self.displayed_image.size(), QImage.Format_ARGB32), 'item': None } layer['image'].fill(fill_color) self.layers.append(layer) self.current_layer = len(self.layers) - 1 self._render_layers() return self.current_layer def remove_layer(self, index): """移除指定图层""" if 0 <= index < len(self.layers): if self.layers[index]['item']: self.scene.removeItem(self.layers[index]['item']) del self.layers[index] if index <= self.current_layer: self.current_layer = max(0, self.current_layer - 1) self._render_layers() def set_current_layer(self, index): """设置当前活动图层""" if 0 <= index < len(self.layers): self.current_layer = index return True return False def toggle_layer_visibility(self, index): """切换图层可见性""" if 0 <= index < len(self.layers): self.layers[index]['visible'] = not self.layers[index]['visible'] self._render_layers() def _render_layers(self): """渲染所有可见图层到显示图像""" if not self.layers: return # 创建一个临时图像来合成所有图层 size = self.displayed_image.size() composite = QImage(size, QImage.Format_ARGB32) composite.fill(Qt.transparent) painter = QPainter(composite) for layer in self.layers: if not layer['visible']: continue painter.setOpacity(layer['opacity']) painter.drawImage(0, 0, layer['image']) painter.end() # 更新显示 self.displayed_image = composite self._show_image(composite) # 更新UI self.image_changed.emit(self.displayed_image) # ==================== 图像管理功能 ==================== def set_image(self, image): """设置要显示的图像""" if image.isNull(): self.clear() return self.original_image = image.copy() self.displayed_image = image.copy() self._clear_layers() self.add_new_layer("Background", Qt.white) self.layers[0]['image'] = image.copy() self.reset_view() self.image_changed.emit(self.displayed_image) self.take_snapshot() def update_image(self): """更新显示的图像""" if not self.displayed_image.isNull(): self._show_image(self.displayed_image) self.image_changed.emit(self.displayed_image) def clear(self): """清除画布""" self.scene.clear() self.current_image_item = None self.displayed_image = QImage() self.original_image = QImage() self.zoom_factor = 1.0 self.zoom_changed.emit(self.zoom_factor) self.resetTransform() self._clear_layers() def reset_view(self): """重置视图到初始状态""" if not self.displayed_image.isNull(): self._show_image(self.displayed_image) self.fit_to_view() def get_current_image(self): """获取当前显示的图像""" return self.displayed_image def get_original_image(self): """获取原始未编辑图像""" return self.original_image def get_pixel_at(self, pos): """获取指定位置的像素颜色""" if self.displayed_image.isNull(): return None if not self.current_image_item: return None # 转换到图像坐标 img_pos = self.map_to_image(pos) x = int(img_pos.x()) y = int(img_pos.y()) # 检查边界 if 0 <= x < self.displayed_image.width() and 0 <= y < self.displayed_image.height(): color = QColor(self.displayed_image.pixel(x, y)) return color return None def map_to_image(self, scene_pos): """将场景坐标映射到图像坐标""" if not self.current_image_item: return QPointF() return self.current_image_item.mapFromScene(scene_pos) # ==================== 缩放功能 ==================== def zoom_in(self): """放大图像""" self.set_zoom(self.zoom_factor * 1.2) def zoom_out(self): """缩小图像""" self.set_zoom(self.zoom_factor * 0.8) def fit_to_view(self): """适应窗口大小""" if self.current_image_item: self.fitInView(self.scene.itemsBoundingRect(), Qt.KeepAspectRatio) self._update_zoom_factor() def set_zoom(self, factor): """设置特定缩放级别""" factor = max(self.min_zoom, min(factor, self.max_zoom)) if abs(factor - self.zoom_factor) > 0.01: self.zoom_factor = factor self.resetTransform() self.scale(factor, factor) self.zoom_changed.emit(self.zoom_factor * 100) def _update_zoom_factor(self): """更新缩放因子""" view_rect = self.transform().mapRect(QRectF(0, 0, 1, 1)) self.zoom_factor = 1.0 / view_rect.width() self.zoom_changed.emit(self.zoom_factor * 100) # ==================== 工具控制功能 ==================== def set_tool(self, tool_id): """设置当前工具""" self.current_tool = tool_id self.tool_changed.emit(tool_id) self._update_cursor() def set_tool_setting(self, key, value): """设置工具参数""" if key in self.tool_settings: self.tool_settings[key] = value self._update_cursor() def _update_cursor(self): """根据当前工具更新光标""" if self.current_tool == self.TOOL_SELECT: self.viewport().setCursor(Qt.CrossCursor) elif self.current_tool == self.TOOL_CROP: self.viewport().setCursor(Qt.CrossCursor) elif self.current_tool == self.TOOL_BRUSH: # 创建画笔形状的光标 size = self.tool_settings['brush_size'] * self.zoom_factor size = max(6, min(int(size), 100)) pixmap = QPixmap(size, size) pixmap.fill(Qt.transparent) painter = QPainter(pixmap) painter.setPen(QPen(Qt.black, 1)) painter.setBrush(QBrush(self.tool_settings['brush_color'])) painter.drawEllipse(1, 1, size - 2, size - 2) painter.end() self.viewport().setCursor(QCursor(pixmap, size / 2, size / 2)) elif self.current_tool == self.TOOL_ERASER: # 创建橡皮擦形状的光标 size = self.tool_settings['eraser_size'] * self.zoom_factor size = max(6, min(int(size), 100)) pixmap = QPixmap(size, size) pixmap.fill(Qt.transparent) painter = QPainter(pixmap) painter.setPen(QPen(Qt.black, 1)) painter.setBrush(QBrush(Qt.white)) painter.drawRect(1, 1, size - 2, size - 2) painter.end() self.viewport().setCursor(QCursor(pixmap, size / 2, size / 2)) elif self.current_tool in [self.TOOL_SHAPE, self.TOOL_TEXT]: self.viewport().setCursor(Qt.CrossCursor) # ==================== 历史记录功能 ==================== def take_snapshot(self): """创建当前状态的快照""" # 只保留最近的20个快照 if self.current_snapshot < len(self.snapshots) - 1: self.snapshots = self.snapshots[:self.current_snapshot + 1] # 保存图层状态 snapshot = { 'layers': [], 'current_layer': self.current_layer } for layer in self.layers: snapshot['layers'].append({ 'image': layer['image'].copy(), 'visible': layer['visible'], 'opacity': layer['opacity'] }) self.snapshots.append(snapshot) self.current_snapshot = len(self.snapshots) - 1 return True def restore_snapshot(self, index=None): """恢复指定快照""" if index is None: index = self.current_snapshot if 0 <= index < len(self.snapshots): snapshot = self.snapshots[index] # 恢复图层状态 self.layers = [] for layer_data in snapshot['layers']: self.layers.append({ 'image': layer_data['image'].copy(), 'visible': layer_data['visible'], 'opacity': layer_data['opacity'], 'locked': False, 'name': f"Layer {len(self.layers)}", 'item': None }) self.current_layer = snapshot['current_layer'] self._render_layers() self.current_snapshot = index return True return False def undo(self): """撤销上一步操作""" if self.current_snapshot > 0: self.restore_snapshot(self.current_snapshot - 1) return True return False def redo(self): """重做上一步操作""" if self.current_snapshot < len(self.snapshots) - 1: self.restore_snapshot(self.current_snapshot + 1) return True return False # ==================== 绘图功能 ==================== def start_drawing(self, scene_pos): """开始绘图操作""" if self.current_tool in [self.TOOL_BRUSH, self.TOOL_ERASER]: self.drawing_active = True self.drawing_start = scene_pos self.drawing_path = QPainterPath() self.drawing_path.moveTo(self.map_to_image(scene_pos)) if self.current_tool == self.TOOL_BRUSH: pen = QPen(self.tool_settings['brush_color'], self.tool_settings['brush_size']) pen.setCapStyle(Qt.RoundCap) pen.setJoinStyle(Qt.RoundJoin) else: # 橡皮擦 pen = QPen(QColor(255, 255, 255, 255), self.tool_settings['eraser_size']) pen.setCapStyle(Qt.RoundCap) if self.tool_settings['antialias']: pen.setCosmetic(True) self.drawing_item = QGraphicsPathItem() self.drawing_item.setPen(pen) self.drawing_item.setPath(self.drawing_path) self.drawing_item.setOpacity(self.tool_settings['opacity']) self.scene.addItem(self.drawing_item) elif self.current_tool == self.TOOL_SHAPE: self.drawing_active = True self.drawing_start = scene_pos self.drawing_item = self._create_shape(scene_pos, scene_pos) if self.drawing_item: self.scene.addItem(self.drawing_item) elif self.current_tool == self.TOOL_TEXT: # 文本输入通过专用方法处理 pass def continue_drawing(self, scene_pos): """继续绘图操作""" if not self.drawing_active: return if self.current_tool in [self.TOOL_BRUSH, self.TOOL_ERASER]: # 添加路径点 new_point = self.map_to_image(scene_pos) self.drawing_path.lineTo(new_point) self.drawing_item.setPath(self.drawing_path) elif self.current_tool == self.TOOL_SHAPE: # 更新形状 if self.drawing_item: self.scene.removeItem(self.drawing_item) self.drawing_item = self._create_shape(self.drawing_start, scene_pos) if self.drawing_item: self.scene.addItem(self.drawing_item) def stop_drawing(self): """完成绘图操作并应用到图层""" if not self.drawing_active: return if self.drawing_item: # 创建绘制到图层的画家 painter = QPainter(self.layers[self.current_layer]['image']) painter.setRenderHint(QPainter.Antialiasing, self.tool_settings['antialias']) painter.setCompositionMode(QPainter.CompositionMode_SourceOver) painter.setOpacity(self.tool_settings['opacity']) # 从绘图项获取路径 path = self.drawing_item.path() # 根据工具应用不同绘制 if self.current_tool == self.TOOL_BRUSH: painter.setPen(QPen( self.tool_settings['brush_color'], self.tool_settings['brush_size'], Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin )) painter.setBrush(Qt.NoBrush) painter.drawPath(path) elif self.current_tool == self.TOOL_ERASER: # 使用橡皮擦 painter.setCompositionMode(QPainter.CompositionMode_Clear) painter.setPen(QPen( Qt.transparent, self.tool_settings['eraser_size'], Qt.SolidLine, Qt.RoundCap )) painter.drawPath(path) 这个代码吗给全
最新发布
06-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涂作权的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值