QFontMetrics
可以用下面的代码获得字符串的 bounding rect
QRect fontBoundingRect = QFontMetrics(font).boundingRect(tr("Qt"));
案例代码
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QPainterPath> #include <QComboBox> #include "renderarea.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void shapeChanged(int index); void transChanged(); private: Ui::MainWindow *ui; static constexpr int numOfTrans = 3; QList<QPainterPath> shapes; RenderArea* originalRenderArea; RenderArea* transRenderAreas[numOfTrans]; QComboBox* shapeComboBox; QComboBox* transComboBoxes[numOfTrans]; void setupShapes(); }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include "./ui_mainwindow.h" #include <QGridLayout> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); originalRenderArea = new RenderArea(this); shapeComboBox = new QComboBox(this); shapeComboBox->addItem("Clock"); shapeComboBox->addItem("House"); shapeComboBox->addItem("Text"); shapeComboBox->addItem("Truck"); connect(shapeComboBox, &QComboBox::activated, this, &MainWindow::shapeChanged); QGridLayout* layout = new QGridLayout; centralWidget()->setLayout(layout); layout->addWidget(originalRenderArea, 0, 0); layout->addWidget(shapeComboBox, 1, 0); for (int i = 0; i < numOfTrans; ++i) { transRenderAreas[i] = new RenderArea(this); transComboBoxes[i] = new QComboBox(this); transComboBoxes[i]->addItem(tr("No transformation")); transComboBoxes[i]->addItem(tr("Translate by (50, 50)")); transComboBoxes[i]->addItem(tr("Rotate by 60\xC2\xB0")); transComboBoxes[i]->addItem(tr("Scale to 75%")); connect(transComboBoxes[i], &QComboBox::activated, this, &MainWindow::transChanged); layout->addWidget(transRenderAreas[i], 0, i + 1); layout->addWidget(transComboBoxes[i], 1, i + 1); } setupShapes(); shapeChanged(0); } MainWindow::~MainWindow() { delete ui; } void MainWindow::shapeChanged(int index) { QPainterPath shape = shapes[index]; originalRenderArea->setShape(shape); for (auto renderArea : transRenderAreas) { renderArea->setShape(shape); } } void MainWindow::transChanged() { QList<RenderArea::Transformation> trans; for (int i = 0; i < numOfTrans; ++i) { int index = transComboBoxes[i]->currentIndex(); trans.append(RenderArea::Transformation(index)); transRenderAreas[i]->setTrans(trans); } } void MainWindow::setupShapes() { QPainterPath truck; truck.setFillRule(Qt::WindingFill); truck.moveTo(0.0, 87.0); truck.lineTo(0.0, 60.0); truck.lineTo(10.0, 60.0); truck.lineTo(35.0, 35.0); truck.lineTo(100.0, 35.0); truck.lineTo(100.0, 87.0); truck.lineTo(0.0, 87.0); truck.moveTo(17.0, 60.0); truck.lineTo(55.0, 60.0); truck.lineTo(55.0, 40.0); truck.lineTo(37.0, 40.0); truck.lineTo(17.0, 60.0); truck.addEllipse(17.0, 75.0, 25.0, 25.0); truck.addEllipse(63.0, 75.0, 25.0, 25.0); QPainterPath clock; clock.addEllipse(-50.0, -50.0, 100.0, 100.0); clock.addEllipse(-48.0, -48.0, 96.0, 96.0); clock.moveTo(0.0, 0.0); clock.lineTo(-2.0, -2.0); clock.lineTo(0.0, -42.0); clock.lineTo(2.0, -2.0); clock.lineTo(0.0, 0.0); clock.moveTo(0.0, 0.0); clock.lineTo(2.732, -0.732); clock.lineTo(24.495, 14.142); clock.lineTo(0.732, 2.732); clock.lineTo(0.0, 0.0); QPainterPath house; house.moveTo(-45.0, -20.0); house.lineTo(0.0, -45.0); house.lineTo(45.0, -20.0); house.lineTo(45.0, 45.0); house.lineTo(-45.0, 45.0); house.lineTo(-45.0, -20.0); house.addRect(15.0, 5.0, 20.0, 35.0); house.addRect(-35.0, -15.0, 25.0, 25.0); QPainterPath text; QFont font; font.setPixelSize(50); QRect fontBoundingRect = QFontMetrics(font).boundingRect(tr("Qt")); text.addText(-QPointF(fontBoundingRect.center()), font, tr("Qt")); shapes.append(clock); shapes.append(house); shapes.append(text); shapes.append(truck); connect(shapeComboBox, &QComboBox::activated, this, &MainWindow::shapeChanged); }
renderarea.h
#ifndef RENDERAREA_H #define RENDERAREA_H #include <QWidget> #include <QPainterPath> class RenderArea : public QWidget { Q_OBJECT public: enum class Operation { NoTransformation, Rotate, Scale, Translate }; explicit RenderArea(QWidget *parent = nullptr); void setShape(QPainterPath& shape); void setOperations(const QList<Operation>& operations); signals: // QWidget interface protected: void paintEvent(QPaintEvent *event) override; private: QPainterPath shape; QList<Operation> operations; private: void drawCoordinates(QPainter& painter); void drawOutline(QPainter& painter); void drawShape(QPainter& painter); void transformPainter(QPainter& painter); }; #endif // RENDERAREA_H
renderarea.cpp
#include "renderarea.h" #include <QPainter> #include <QPaintEvent> RenderArea::RenderArea(QWidget *parent) : QWidget{parent} { setFixedSize(232, 232); } void RenderArea::setShape(const QPainterPath &shape) { this->shape = shape; update(); } void RenderArea::setTrans(const QList<RenderArea::Transformation> trans) { this->trans = trans; update(); } void RenderArea::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.fillRect(event->rect(), Qt::white); painter.translate(66, 66); drawBoundingBox(painter); painter.save(); transformPainter(painter); drawCoordinates(painter); drawShape(painter); painter.restore(); } void RenderArea::drawBoundingBox(QPainter& painter) { painter.setPen(Qt::darkGreen); painter.setPen(Qt::DashLine); painter.setBrush(Qt::NoBrush); painter.drawRect(0, 0, 100, 100); } void RenderArea::drawCoordinates(QPainter& painter) { painter.setPen(Qt::red); painter.drawLine(0, 0, 50, 0); painter.drawLine(48, -2, 50, 0); painter.drawLine(48, 2, 50, 0); painter.drawText(55, 3, "x"); painter.drawLine(0, 0, 0, 50); painter.drawLine(-2, 48, 0, 50); painter.drawLine(2, 48, 0, 50); painter.drawText(-3, 60, "y"); } void RenderArea::drawShape(QPainter& painter) { painter.fillPath(shape, Qt::blue); update(); } void RenderArea::transformPainter(QPainter& painter) { for (auto tran : trans) { switch (tran) { case RenderArea::Transformation::Translate: painter.translate(50, 50); break; case RenderArea::Transformation::Scale: painter.scale(0.75, 0.75); break; case RenderArea::Transformation::Rotate: painter.rotate(60); break; case RenderArea::Transformation::NoTrans: default: break; } } }