Qt绘制直线箭头

一.使用QPainter绘制

满足条件:

  • 任意角度直线都可绘制箭头(直线垂直时绘制可能出错,参考 QPainterPath 计算方法)
  • 所有箭头同样大小
void MainWindow::paintEvent(QPaintEvent*)
{
    QPainter painter(this);  // 创建QPainter对象,并指定绘制目标为当前的widget
    QLineF line(50,20,500,500);

    double distanceFromEnd1 = 20;
    qreal t = (line.length() - distanceFromEnd1) / line.length();
    QPointF point = line.pointAt(t);//与两端平行点

    double distanceFromEnd2 = 5;
    qreal z = (line.length() - distanceFromEnd2) / line.length();
    QPointF point_center=line.pointAt(z);//中心点

    qreal slope_line = (line.p2().y() - line.p1().y()) / (line.p2().x() - line.p1().x());  // 计算原直线斜率
    double slope = -1 / slope_line;  // 计算垂线的斜率
    double intercept = point.y() - slope * point.x();  // 计算垂线的截距
    const double m=5;//垂线上下两端距离
    double arrow1_x=(point.y()+m-intercept)/slope;
    double arrow2_x=(point.y()-m-intercept)/slope;
    QPointF arrow1(arrow1_x,slope*arrow1_x+intercept);
    QPointF arrow2(arrow2_x,slope*arrow2_x+intercept);
    painter.setRenderHint(QPainter::Antialiasing, true);  // 可选,抗锯齿设置
    painter.setPen(QPen(Qt::black, 2));  // 设置画笔颜色和宽度
    painter.drawLine(line);  // 绘制直线
    painter.setPen(QPen(Qt::green,3));
    painter.drawLine(arrow1,point_center);
    painter.drawLine(arrow2,point_center);
}

二.使用QPainterPath绘制

1.如何使用 GraphicsView 和 QGraphicsScene 绘制

创建一个类继承 GraphicsView
  • graphicsView.h
#ifndef GRAPHICSVIEW_H
#define GRAPHICSVIEW_H
#include <QGraphicsView>
#include <QMouseEvent>
#include <QGraphicsLineItem>
#include <QGraphicsPathItem>
#include <QPainterPath>
#include <QDebug>
#include <QObject>
#include <QPointF>
#include <QGraphicsEllipseItem>

class GraphicsView : public QGraphicsView
{
public:
     GraphicsView(QGraphicsScene *scene, QWidget *parent = nullptr);
     void setLineData();
private:
     QGraphicsScene *scene_;
};

#endif // GRAPHICSVIEW_H
  •  graphicsview.cpp
#include "graphicsview.h"

GraphicsView::GraphicsView(QGraphicsScene *scene,QWidget *parent ) : QGraphicsView(parent),scene_(scene)
{
    setScene(scene_);
    setLineData();
}
void GraphicsView::setLineData()
{
    QLineF line(100,100,600,400);
    QPen pen(Qt::red,3);
    scene_->addLine(line,pen);

}
主函数中添加私有对象:
private:
    Ui::MainWindow *ui;
    GraphicsView *graphics_view;
    QGraphicsScene *scene;
主函数中调用:
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);


    scene = new QGraphicsScene(this);


    // 创建 GraphicsView 对象并设置场景
    GraphicsView* graphicsView = new GraphicsView(scene, this);

    // 添加 GraphicsView 对象为中央部件
//    setCentralWidget(graphicsView);
    // 将 GraphicsView 添加到主窗口
//    setCentralWidget(graphicsView);

    setCentralWidget(graphicsView);

    // 设置场景大小为主窗口的大小
    QRectF rect(0, 0, width(), height());
    scene->setSceneRect(rect);

    // 根据视图大小调整窗口大小
    adjustSize();

}
图形显示:

2.在终点位置前绘制箭头

void GraphicsView::setLineData()
{
    QPen pen(Qt::red, 2);
    QPointF start(50, 50);
    QPointF end(50, 70);
    qreal arrowSize = 10;//箭头尺寸

    // 计算箭头方向和长度
    QLineF line(start, end);
    qreal angle = ::acos(line.dx() / line.length());箭头角度

    qreal distanceFromEnd = 5;//距离终点5处开始绘制
    QPointF arrowStart = line.pointAt(1 - distanceFromEnd / line.length());

    if (line.dy() >= 0)
        angle = 2 * M_PI - angle;
    QPointF arrowP1 = arrowStart + QPointF(sin(angle - M_PI / 3) * arrowSize,
                                    cos(angle - M_PI / 3) * arrowSize);
    QPointF arrowP2 = arrowStart + QPointF(sin(angle - M_PI + M_PI / 3) * arrowSize,
                                    cos(angle - M_PI + M_PI / 3) * arrowSize);

    // 创建路径并绘制
    QPainterPath path(start);
    path.lineTo(end);
    path.moveTo(arrowStart);
    path.lineTo(arrowP1);
    path.moveTo(arrowStart);
    path.lineTo(arrowP2);

    scene_->addPath(path, pen);
}

 满足条件:

  • 任意角度的直线都可以绘制
  • 固定箭头大小

3.在起点位置后绘制箭头

需修改:

  • 距离计算
  • 箭头的两个端点应该是减去相应值
void GraphicsView::setLineData()
{
    QPen pen(Qt::red, 2);
    QPointF start(50, 600);
    QPointF end(50, 200);
    qreal arrowSize = 10;

    // 计算箭头方向和长度
    QLineF line(start, end);
    qreal angle = ::acos(line.dx() / line.length());

    qreal distanceFromEnd = 5;
    QPointF arrowStart = line.pointAt(distanceFromEnd / line.length());

    if (line.dy() >= 0)
        angle = 2 * M_PI - angle;
    QPointF arrowP1 = arrowStart - QPointF(sin(angle - M_PI / 3) * arrowSize,
                                    cos(angle - M_PI / 3) * arrowSize);
    QPointF arrowP2 = arrowStart - QPointF(sin(angle - M_PI + M_PI / 3) * arrowSize,
                                    cos(angle - M_PI + M_PI / 3) * arrowSize);

    // 创建路径并绘制
    QPainterPath path(start);
    path.lineTo(end);
    path.moveTo(arrowStart);
    path.lineTo(arrowP1);
    path.moveTo(arrowStart);
    path.lineTo(arrowP2);

    scene_->addPath(path, pen);

}

4.绘制双向箭头

void GraphicsView::setLineData()
{
    QPen pen(Qt::red, 2);
    QPointF start(50, 600);
    QPointF end(50, 200);
    QLineF line(start, end);
    qreal arrowSize = 10;//可以根据直线的长短进行箭头的限制
    // 计算箭头方向和长度
    qreal angle = ::acos(line.dx() / line.length());

    qreal distanceFromEnd = 5;
    QPointF arrowEndStart = line.pointAt(1 - distanceFromEnd / line.length()),arrowStartEnd=line.pointAt(distanceFromEnd / line.length());



    if (line.dy() >= 0)
        angle = 2 * M_PI - angle;
    QPointF arrowP1 = arrowEndStart + QPointF(sin(angle - M_PI / 3) * arrowSize,
                                    cos(angle - M_PI / 3) * arrowSize);
    QPointF arrowP2 = arrowEndStart + QPointF(sin(angle - M_PI + M_PI / 3) * arrowSize,
                                    cos(angle - M_PI + M_PI / 3) * arrowSize);
    QPointF arrowP3,arrowP4;

    QPainterPath path(start);
    path.lineTo(end);
    path.moveTo(arrowEndStart);
    path.lineTo(arrowP1);
    path.moveTo(arrowEndStart);
    path.lineTo(arrowP2);
    arrowP3 = arrowStartEnd - QPointF(sin(angle - M_PI / 3) * arrowSize,
                                          cos(angle - M_PI / 3) * arrowSize);
    arrowP4 = arrowStartEnd - QPointF(sin(angle - M_PI + M_PI / 3) * arrowSize,
                                          cos(angle - M_PI + M_PI / 3) * arrowSize);
    path.moveTo(arrowStartEnd);
    path.lineTo(arrowP3);
    path.moveTo(arrowStartEnd);
    path.lineTo(arrowP4);


    // 创建路径并绘制

    scene_->addPath(path, pen);

}

 

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的示例,演示如何在Qt中使用鼠标绘制直线图: ```cpp #include <QtGui> #include <Widgets> class Line : public QGraphicsLineItem { public: Line(const QLineF& line) : QGraphicsLineItem(line) {} QRectF boundingRect() const override { return pen().widthF() + 20.0 + QGraphicsLineItem::boundingRect(); } QPainterPath shape() const override { QPainterPath path = QGraphicsLineItem::shape(); path.addRect(boundingRect()); return path; } void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override { if (option->state & QStyle::State_Selected) { painter->setPen(QPen(option->palette.windowText(), 0, Qt::DotLine)); painter->drawRect(boundingRect()); } QGraphicsLineItem::paint(painter, option, widget); } }; class GraphicsView : public QGraphicsView { public: GraphicsView(QWidget* parent = nullptr) : QGraphicsView(parent), m_isDrawing(false), m_line(nullptr) { setRenderHint(QPainter::Antialiasing); setDragMode(QGraphicsView::RubberBandDrag); setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing); setViewportUpdateMode(QGraphicsView::SmartViewportUpdate); setSelectionMode(QGraphicsView::SingleSelection); } protected: void mousePressEvent(QMouseEvent* event) override { if (event->button() == Qt::LeftButton) { m_startPos = mapToScene(event->pos()); m_isDrawing = true; } QGraphicsView::mousePressEvent(event); } void mouseMoveEvent(QMouseEvent* event) override { if (m_isDrawing) { if (!m_line) { m_line = new Line(QLineF(m_startPos, mapToScene(event->pos()))); scene()->addItem(m_line); } else { m_line->setLine(QLineF(m_startPos, mapToScene(event->pos()))); } } QGraphicsView::mouseMoveEvent(event); } void mouseReleaseEvent(QMouseEvent* event) override { if (event->button() == Qt::LeftButton && m_isDrawing) { m_isDrawing = false; m_line = nullptr; } QGraphicsView::mouseReleaseEvent(event); } private: bool m_isDrawing; QPointF m_startPos; Line* m_line; }; int main(int argc, char* argv[]) { QApplication app(argc, argv); QGraphicsScene scene; GraphicsView view(&scene); view.setRenderHint(QPainter::Antialiasing); view.setScene(&scene); view.setDragMode(QGraphicsView::RubberBandDrag); QGraphicsLineItem* line = new QGraphicsLineItem(QLineF(0.0, 0.0, 100.0, 100.0)); line->setPen(QPen(Qt::red, 2)); scene.addItem(line); QGraphicsEllipseItem* ellipse = new QGraphicsEllipseItem(QRectF(0.0, 0.0, 100.0, 100.0)); ellipse->setPen(QPen(Qt::blue, 2)); ellipse->setBrush(QBrush(Qt::green)); scene.addItem(ellipse); view.setSceneRect(-150, -150, 300, 300); view.setFixedSize(300, 300); view.show(); return app.exec(); } ``` 该示例演示了如何使用QGraphicsView和QGraphicsScene来绘制直线。在鼠标按下时,记录起始位置,并在鼠标移动时绘制直线。在鼠标释放时,停止绘制。该示例还演示了如何添加其他类型的图元,如椭圆和直线

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值