首页 文章

Qt - 绘制后在QGraphicsScene上调整文本大小

提问于
浏览
1

我和一群学生做了一个Plotting程序,我们在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

这将导致:

An Example of Plotting

我们正在使用:

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

确保QGraphicsView仅显示可见(非常重要) .

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

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

这将绘制一条非常长的线,这将使我们创建的Points Text变得如此之小,甚至无法看到:

Example of Plotting using Large numbers

所以我们需要的是以某种方式计算SceneRect(我认为)并找出我们应该用于Point和Text的半径值字体大小,这样无论Scene的大小如何,它们都保持相同的大小 .

EDIT : 这是新代码(根据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;
}

此代码根据固定的比例缩放点,但仍然会产生Scrollbars,这是我们必须解决的问题 . 它以某种方式忽略了fitInView(),或者它确实适合它但是当调整Points的大小时它会调整SceneRect或其他东西的大小

结果如下:

enter image description here

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

EDIT : Solved by vcloarec :解决方案是将点插入(-0.5,-0.5)而不是setPose(x,y),这将把Position设置为x,我们传递给AddPoint(x,y) . 无论场景的大小如何,点现在都保持相同的大小,它将显示一次创建的所有点,没有任何滚动条或任何东西 .

谢谢 !

1 回答

  • 1

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

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

    Edit :

    我试着打个比方:

    • QGraphicsView是一款相机

    • QGraphicScene是现实生活

    • QGraphicsItems是人们 Ant 的东西

    如果要查看场景的特定部分,请在 rect 定义的部件上使用 QGraphicsView::setSceneRect(const QRectF & rect) 至"zoom" . 当您使用相机对象时,此对象在现实生活中不会改变其大小,但在屏幕中大小会发生变化 . 它与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 )
    

相关问题