需求
在QGraphicsRectItem上绘制文字,有下述要求:
- 文字能够随着Item的尺寸的变化而缩放
- 若增加文字则要按照拉伸或者压缩后的比例增加或者删除文字
实现思路
实现文字的缩放只能通过painter.scale(sx,sy)缩放坐标系,从而将文字绘制到固定区域上。需要注意两点:
- 缩放比例的计算
利用QPainter->fontMetrics()计算文本的宽度和高度,并与Item->rect()的宽度和高度作比就是缩放的比例。 - drawText绘制区域以及对齐方式的设置
关于绘制大小。drawText(QRectF rect, QString text)中绘制区域rect,与当前Item->rect()大小并不相等,绘制区域rect与缩放没有关系,缩放只是视觉上呈现出来的文字占用的区域增加或者缩小,但是实际上的绘制区域rect仍然应该是QPainter->fontMetrics()得到的宽高。
关于绘制原点。QGraphicsItem::paint中绘制原点为Item的局部坐标系的原点,和QGraphicsItem在局部坐标系中的位置无关。因此若要将文字绘制到矩形上,或者移动Item,将矩形在局部坐标系中的位置转移到pos上,或者每次都要获取Item在局部坐标系的坐标,而后将painter移动到对应的位置。
对齐方式的设置和缩放的位置有关。缩放是以坐标原点为缩放中心进行缩放的,通过translate可平移坐标系,在缩放过程中,坐标系原点在Item中的相对位置不发生变化,但是其他的点都会发生变化。(就像把伞撑开,从垂直方向看,就中心点的位置不变,而其他点的位置都会变化,可将其看做以伞轴为中心的放大)
实现代码
- 初始化设置
设置item的位置和大小;三个按钮用于移动item的pos和rect。
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QGraphicsScene * scene = new QGraphicsScene;
ui->graphicsView->setScene(scene);
ui->graphicsView->setSceneRect(0, 0, 1000, 1000);
ui->graphicsView->setAlignment(Qt::AlignLeft|Qt::AlignTop);
item = new MyRect;
item->setFlag(QGraphicsItem::ItemIsMovable);
item->setFlag(QGraphicsItem::ItemIsSelectable);
item->setPos(50,40);//设置item的位置和大小
item->setRect(0, 0, 100, 100);
ui->graphicsView->scene()->addItem(item);
ui->graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
}
void Widget::on_pushButton_clicked()
{
item->setRect(20,20,50,200);
}
void Widget::on_pushButton_2_clicked()
{
item->setPos(100, 100);
item->setRect(100,10,50,50);
}
void Widget::on_pushButton_3_clicked()
{
item->setRect(10,150,150,20);
}
- QGraphicsItem::paint()
void MyRect::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->save();//很必要!执行QGraphicsItem::paint要恢复原本的paint
QString text = "未定义";
int size = 24;
QRectF curRect = this->rect();
QFont font;
font.setWeight(75);
font.setFamily("Microsoft YaHei");
font.setPixelSize(size);
painter->setFont(font);
painter->drawLine(0, 0, 200, 0);//绘制局部坐标系,用于观察
painter->drawText(200, -2, "x");
painter->drawLine(0, 0, 0, 200);
painter->drawText(-2, 200, "y");
QFontMetrics fm = painter->fontMetrics();//计算文本的高度和宽度
qreal height = fm.height();
qreal width = fm.horizontalAdvance(text);
qreal sx = curRect.width() * 1.0 / width;//计算缩放比例
qreal sy = curRect.height() * 1.0 / height;
painter->translate(curRect.x(), curRect.y());//重点!由于Item可能不在原点处,因此需要先将坐标系平移到对应位置,缩放后再移动回来,因为缩放时坐标原点不动
painter->scale(sx, sy);
painter->translate(-curRect.x(), -curRect.y());
QRectF newRect = curRect;//重点!设置绘制区域,绘制位置仍然是item的坐标,但是大小应该仍然是文本原本的大小,而后经过缩放正好装在item中
newRect.setWidth(width);
newRect.setHeight(height);
// newRect.setWidth(curRect.width() * 1.0 / sx);效果与上面两行代码相同
// newRect.setHeight(curRect.height() * 1.0 / sy);
painter->setPen(Qt::red);
painter->drawText(newRect, text, Qt::AlignLeft|Qt::AlignTop);
painter->drawRect(newRect);
painter->restore();//恢复paint
QGraphicsRectItem::paint(painter, option, widget);
}
标签:item,缩放,paint,curRect,QGraphicsItem,绘制,painter
From: https://www.cnblogs.com/wsw2022/p/16989024.html