【问题标题】:Qt - Resize Text on QGraphicsScene after drawingQt - 绘制后在 QGraphicsScene 上调整文本大小
【发布时间】:2018-06-02 01:50:55
【问题描述】:

我正在和一群学生一起做一个小绘图程序,我们在 QGraphicsView 上使用 Qt 的 QGraphicsScene 让用户在特定位置 (x , y) 上绘制自定义点,每个点上面都必须有一个文本.

这是负责将点添加到场景的函数:

void MainWindow::AddPoint(float x, float y, QString name)
{
    y = y * -1; // To Flip Y-Axis
    float Radius = 1; // Point's (Eclipse) Radius
    QGraphicsItem *Point = p_Scene->addEllipse(x , y , Radius , Radius , QPen(QColor(Qt::red)) , QBrush(QColor(Qt::red))); // Creates a Red Colored Point on the given Coordinates (x , y) 
    /*
    QGraphicsTextItem *Text = p_Scene->addText(name); // Creates a Text
    Text->setDefaultTextColor(QColor(Qt::red)); // Sets Text's Color to Red
    Text->setFont(QFont("Courier New" , 4)); // Sets Text's Font Size
    Text->setPos(x , y - 10); // Set Text's Position (On top of the Point)
    ui->graphicsView->setScene(p_Scene); // Adds Text to the Scene
    */
}

所以实现会是这样的:

AddPoint(0 , 0 , "P1"); // Point 1
AddPoint(50 , 100 , "P2"); // Point 2
AddPoint(100 , 0 , "P3"); // Point 3 

这将导致:

我们正在使用:

ui->graphicsView->fitInView(ui->graphicsView->scene()->sceneRect() , Qt::KeepAspectRatio);

确保 QGraphicsView 只显示可见的内容(非常重要)。

所以这里的问题是,如果我们要使绘图更大,例如:

AddPoint(0 , 0 , "P1");
AddPoint(0 , 1000 , "P2"); // y = 1000

这将绘制一条很长的线,这将使我们创建的点 + 文本变得非常小,甚至无法看到:

因此,我们需要以某种方式计算 SceneRect(我认为)并找出我们应该为 Point 和 Text 使用的半径值 + 字体大小,以便无论场景大小如何,它们都保持相同的大小。

编辑: 这是新代码(根据 vcloarec 的解决方案):

GraphicsWindow.h(QGraphicsView 子类):

#ifndef GRAPHICSVIEW_H
#define GRAPHICSVIEW_H

#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsItem>
#include <QDebug>

class GraphicsView : public QGraphicsView
{
    Q_OBJECT

public:
    explicit GraphicsView(QWidget *parent = 0);
    void AddPoint(float x , float y , QString name = "");
    void resize();

private:
    QGraphicsScene *p_Scene;
    int p_SizeInView;
};

#endif // GRAPHICSVIEW_H

GraphicsWindow.cpp:

#include "GraphicsView.h"

GraphicsView::GraphicsView(QWidget *parent) : QGraphicsView(parent)
{
    p_PointRadius = 0.0;
    p_PointsLastN = 0;
    p_SizeInView = 5;
    p_Scene = new QGraphicsScene(this);

    this->setScene(p_Scene);
}

void GraphicsView::AddPoint(float x, float y, QString name)
{
    y = y * -1;

    QGraphicsItem *_Point = p_Scene->addEllipse(x , y , 1 , 1 , QPen(QColor(Qt::red)) , QBrush(QColor(Qt::red)));

    this->fitInView(scene()->sceneRect() , Qt::KeepAspectRatio);
    resize();
}

void GraphicsView::resize()
{
    qreal scale = p_SizeInView / this->transform().m11();

    for(int i = 0; i < this->scene()->items().count(); i++)
    {
        this->scene()->items().at(i)->setScale(scale);
    }
}

MainWindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    ui->toolBar->addWidget(ui->ZoomUp_Button);
    ui->toolBar->addWidget(ui->ZoomDown_Button);

    setCentralWidget(ui->graphicsView);

    ui->graphicsView->AddPoint(0 , 0);
    ui->graphicsView->AddPoint(1000 , 0);
    ui->graphicsView->AddPoint(1000 , 50);
    ui->graphicsView->AddPoint(0 , 50);
}

MainWindow::~MainWindow()
{
    delete ui;
}

此代码根据固定比例缩放点,但仍会导致滚动条,这是我们必须解决的问题。 不知何故,它忽略了 fitInView() ,或者它确实适合它,但是当调整点的大小时,它会调整 SceneRect 或其他东西的大小

结果如下:

PS : 我们将 QGraphicsView 子类化了,因为稍后我们将需要 MouseEvents 和其他东西。

编辑:由 vcloarec 解决: 解决方案是在 (-0.5 , -0.5) 处插入点,然后 setPose(x , y) 将位置设置为 x , y 我们传递给 AddPoint(x , y)。 无论场景的大小如何,点现在都保持相同的大小,并且它将显示一次创建的所有点,而没有任何滚动条或任何东西。

谢谢!

【问题讨论】:

    标签: c++ qt


    【解决方案1】:

    文本结束点的尺寸是在场景坐标中定义的,而不是在视口(窗口)坐标中。

    如果您希望点和文本在显示屏上保持其尺寸,则必须根据视口的“缩放”更新尺寸。

    编辑:

    我试着打个比方:

    • QGraphicsView 是一个摄像头
    • QGraphicScene 是真实的生活
    • QGraphicsItems 是人和事

    如果您想查看场景的特定部分,请使用QGraphicsView::setSceneRect(const QRectF &amp; rect)rect 定义的部分进行“缩放”。 当您使用相机对对象“缩放”或“取消缩放”时,这些对象在现实生活中不会改变它们的大小,但在屏幕上会改变大小。与 QGraphicsView 的行为相同。

    如果您想要对象表示的固定大小,则必须根据场景的比例调整对象的大小。在您使用addPoint(0 , 0 , "P1"); addPoint(0 , 1000 , "P2") 的示例中,两个点彼此相距很远,与此距离相比,点和文本非常小。

    您的问题的解决方案取决于您想要的表示类型(动态、静态...)

    也许您可以使用QTransform QGraphicsView::transform() const 返回的矩阵及其对角线元素来找到要使用的比例。

    看看这个:

        class MyView:public QGraphicsView
    {
    public:
        MyView(QWidget *parent):QGraphicsView(parent),sizeInView(5) {}
    
        void resize();
    
    protected:
        void wheelEvent(QWheelEvent *event);
    
    private:
        int sizeInView;
    
    };
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
        void putPoint();
    
    private:
    
        Ui::MainWindow *ui;
        QGraphicsScene *scene;
        MyView *view;
    };
    

       MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
       ui->setupUi(this);
       view=new MyView(this);
       centralWidget()->setLayout(new QHBoxLayout());
       centralWidget()->layout()->addWidget(view);
    
       scene=new QGraphicsScene(this);
       view->setScene(scene);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::putPoint()
    {
        QGraphicsEllipseItem *point1= new QGraphicsEllipseItem(-0.5,-0.5,1,1);
        point1->setPos(0,0);
        QGraphicsEllipseItem *point2= new QGraphicsEllipseItem(-0.5,-0.5,1,1);
        point2->setPos(0,100);
        QGraphicsEllipseItem *point3= new QGraphicsEllipseItem(-0.5,-0.5,1,1);
        point3->setPos(0,1000);
        QGraphicsEllipseItem *point4= new QGraphicsEllipseItem(-0.5,-0.5,1,1);
        point4->setPos(100,0);
        QGraphicsEllipseItem *point5= new QGraphicsEllipseItem(-0.5,-0.5,1,1);
        point5->setPos(100,100);
        QGraphicsEllipseItem *point6= new QGraphicsEllipseItem(-0.5,-0.5,1,1);
        point6->setPos(100,1000);
    
        scene->addItem(point1);
        scene->addItem(point2);
        scene->addItem(point3);
        scene->addItem(point4);
        scene->addItem(point5);
        scene->addItem(point6);
    
        view->fitInView(scene->sceneRect(),Qt::KeepAspectRatio);
        view->resize();
    }
    
    
    void MyView::resize()
    {
        qreal scale=sizeInView/transform().m11();
        for (int i=0;i<scene()->items().count();++i)
            scene()->items().at(i)->setScale(scale);
    }
    
    void MyView::wheelEvent(QWheelEvent *event)
    {
        float fact=1.5;
        if (event->delta()>=120)
        {
            setTransform(transform()*fact);
            resize();
        }
    
        if (event->delta()<=-120)
        {
           setTransform(transform()/fact);
           resize();
        }
    }
    

    注意,你的 QGraphicsItem 在场景中的插入点是由 QGraphicsItem::setPos 定义的。创建点时使用的 (x,y) 是局部坐标系中的位置,而不是场景坐标系中的位置,它不是您点的中心,而是包含椭圆的左上角矩形。

    因此,如果您的点的中心不在插入点上,当您调整大小时,该点会移动......这就是为什么我将点放置在 (-0.5,-0.5) 的局部坐标中,高度和宽度等于1。然后,我将带有setPos的点放在场景坐标中。

    如果你想禁用滚动条:

    setHorizontalScrollBarPolicy ( Qt::ScrollBarAlwaysOff )
    

    【讨论】:

    • 是的,我确实对我将如何做到这一点有一点想法,并且必须有一个变量来帮助在不同的 SceneRects 上保持点看起来相同的大小,我尝试了 transfom() ,如一个小测试我从 transform() 尝试了不同的 Sizes (SceneRects) 和 qDebug() 但它永远不会改变(来自 transform 的值),无论我的场景大小如何,所以我认为这不是我需要的。
    • 变换函数给我不同的值取决于视图适合的sceneRect。我有一些代码可以让我在屏幕上获得相同大小的点。这不是完美的解决方案,因为椭圆的缩放是基于不是椭圆中心的插入点,因此该点的中心并不是真正固定的。我认为解决方案必须通过子类化 QGraphicsItems 来根据他的大小或缩放来移动点。 PS:抱歉我的英语不好
    • 我尝试了代码并且它可以工作(缩放视图),这将导致滚动条和所有内容(因为缩放后将场景适合视图),但我绑定到固定大小,除非用户想要手动缩放(这将导致滚动条)......但我开始认为这个问题有点超出我的想象,看看我们真正想要的是给用户所有的点,不管距离如何,所以: Line : (0,0),(100,0) 和 Line : (0,0),(1000,0) 在用户看来是一样的,所以我开始认为问题根本不是缩放问题!告诉我你的想法?
    • 最后,它没有我之前说的那么复杂,我是寻找解决方案太复杂的专家……无需子类化,只需将插入点放在其中心即可。我已经更改了上面的代码以将缩放与滚轮集成。如您所见,无论距离如何,该点都保持相同的大小。我不确定是否理解您的问题,但也许会有所帮助。四个你的线:(0,0),(100,0)和线:(0,0),(1000,0),如果您适合每种情况的场景视图,则两条线看起来相同。
    • 我已经添加了一些解释
    猜你喜欢
    • 1970-01-01
    • 2021-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 1970-01-01
    相关资源
    最近更新 更多