Qt编辑图片组合一般是QPainter+QImage,但若是要实时显示往往不能直接随鼠标所在位置进行缩放,需要添加QScrollArea以及进行各种函数重写,接触到Qt中场景和图元概念后发现可以直接把图片作为一个图元,在场景中进行缩放对用户更友好,且不用写多余代码,废话不多说,直接上代码
Item.cpp
class ImageItemPrivate
{
public:
ImageItemPrivate(int id,ImageItem * ptr);
~ImageItemPrivate();
void draw(QPainter * p);
QRectF sceneRect();
bool savImage(QString fileName );
// 宿主
ImageItem * m_qPtr;
private:
QImage m_image;//实际画布
double m_dPicScale;//画布像素比 1cm-2pixel
int m_id;
QString m_title;
private:
QColor penColor(int type);
QBrush penBrush(int type);
QFont textFont(int type);
void buildImage();
};
ImageItemPrivate::ImageItemPrivate(int id,ImageItem * ptr) : m_qPtr(ptr)
{
m_id = id;
m_dPicScale = 2;//1cm-2pixel
m_verlimit = 75;//75cm - 150pixel
m_horlimit = 100;//100cm - 200pixel
m_cenlimit = 80;//80cm - 160pix
m_cubiclimit = 200;
m_title = QString::number(id) + QStringLiteral("号图片信息") ;
buildImage();
}
//实际位置转为图片位置 像素比:1cm-2pixel
QPolygonF ImageItemPrivate::scaleTrans(QPolygonF ply)
{
QPolygonF polygon;
foreach (QPointF pos, ply) {
polygon.push_back(pos*m_dPicScale);
}
return polygon;
}
bool ImageItemPrivate::savImage(QString fileName)
{
//这里我初始直接用左下作为原点绘图,绘图结果当然不对,转图倒转就可以了;但后来又需要加文字等对方向敏感的图元就不行了,所以我又重新修改了各种数据直接以图片坐标系进行绘制,so sad.
// QImage img = m_image.mirrored(false,true);
return m_image.save(fileName);
}
//用于确定当前绘图大小,根据实际需求制定就好
QRectF ImageItemPrivate::sceneRect()
{
double min_x,max_x;
getCubiclesLimitSize(min_x,max_x);
double dW = max_x;
double dH = m_cubiclimit*2 + 2*m_verlimit + 2*m_cenlimit;
return QRectF( 0, 0, dW, dH );
}
//图片绘制事件
void ImageItemPrivate::draw(QPainter * p)
{
if( !m_image.isNull() )
{
p->drawImage(m_qPtr->boundingRect(), m_image);
}
}
void ImageItemPrivate::buildImage()
{
int w = sceneRect().width() * m_dPicScale;
int h = sceneRect().height() * m_dPicScale;
m_image = QImage(w, h, QImage::Format_ARGB32);//图片确定宽和高
m_image.fill(Qt::white);//默认白色画布
QPainter p(&m_image);
p.setRenderHint(QPainter::Antialiasing);//防锯齿
//画外框线
p.setPen(QPen(penColor(ImageItem::IT_CUBICLESLINE), 2));
//使用scaleTrans统一完成实际位置和图片像素点位置转换
p.drawPolygon(scaleTrans(m_cubicleLineF));//正面
p.drawPolygon(scaleTrans(m_cubicleLineB));//背面
p.drawPolygon(scaleTrans(m_cubicleLineT));//顶
p.drawPolygon(scaleTrans(m_cubicleLineL));//左
p.drawPolygon(scaleTrans(m_cubicleLineR));//右
……
}
QRectF ImageItem::sceneRect()
{
return m_dPtr->sceneRect();
}
bool ImageItem::savImage(QString fileName)
{
return m_dPtr->savImage(fileName);
}
QPainterPath ImageItem::shape() const
{
QPainterPath path;
path.addRect(boundingRect());
return path;
}
QRectF ImageItem::boundingRect() const
{
QRectF sceneRct = m_dPtr->sceneRect();
return QRectF(0, 0, sceneRct.width(), sceneRct.height() );
}
void ImageItem::paint( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
m_dPtr->draw(painter);
}
Item.h
class ImageItemPrivate;
class ImageItem : public QObject, public QGraphicsItem
{
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
public:
enum ItemTypes{
IT_CUBICLES = 0,
IT_CUBICLESLINE,
IT_LEGENDTEXT,
IT_TITLETEXT,
IT_UHF,
IT_US,
IT_CUBICLETEXT
};//绘制图元类型,用于确定画笔,画刷颜色和字体属性
ImageItem(int id);
~ImageItem();
//用于区分场景中图元类型以及图元转qgraphicsitem_cast()
int type() const { return QGraphicsItem::UserType+14 ;}
QRectF sceneRect();//可用于场景中坐标转换
bool savImage(QString fileName );
void paint( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 );
QPainterPath shape() const;
QRectF boundingRect() const;
private:
ImageItemPrivate * m_dPtr;
};
注意:
即使是不需要界面的控制台程序,当涉及桌面设置,风格,字体,调色板,光标等界面操作时,必须使用QApplication而非QCoreApplication!!
这里简直是一个大坑,在某个控制台小项目中用到了这个图元,想直接绘制并保存图片就好,结果一跑就崩!!
当初开发在windows系统,复用时在ubuntu系统,转了n圈找编码,系统字体,Qt版本,Ubuntu版本,编译器……最后发现QCoreApplication,想死……
因为当前图元涉及drawText,所以涉及到字体设置,而这些直接找帮助文档很难具体对应内容,发现之后再回头看倒是可以(然而有什么用呢TAT)经历分享给大家,望大家不要犯这种错误!