我和一群学生做了一点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
这将导致:
我们正在使用:
ui->graphicsView->fitInView(ui->graphicsView->scene()->sceneRect() , Qt::KeepAspectRatio);
确保QGraphicsView仅显示可见(非常重要)。
所以这里的问题是,如果我们要将绘图放大,比如说:
AddPoint(0 , 0 , "P1");
AddPoint(0 , 1000 , "P2"); // y = 1000
这将绘制一条非常长的行,这将使我们创建的Points + Text变得如此之小,甚至无法看到:
所以我们需要的是以某种方式计算SceneRect(我认为)并找出我们应该用于Point和Text的半径值+字体大小,以便它们保持相同的大小而不管场景&#39 ; s尺寸。
编辑: 这是新代码(根据vcloarec'解决方案):
GraphicsWindow.h(QGraphicsView Subclass):
#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;
}
此代码根据固定的比例缩放Points,但仍会产生Scrollbars,这是我们必须解决的问题。 它以某种方式忽略了fitInView(),或者它实际上适合它,但是当调整Points的大小时,它会调整SceneRect或其他东西的大小
结果如下:
PS:我们将QGraphicsView子类化,因为稍后我们将需要MouseEvents和其他东西。
编辑:由vcloarec解决: 解决方案是将点插入(-0.5,-0.5)而不是setPose(x,y),这将把Position设置为x,y我们传递给AddPoint(x,y)。 无论场景的大小如何,点数现在保持相同的大小,并且它将显示一次创建的所有点数,没有任何滚动条或任何内容。
谢谢!
答案 0 :(得分:1)
文本的点的尺寸在场景坐标中定义,而不是在视口(窗口)坐标中定义。
如果您希望点和文字在显示屏上保留其尺寸,则必须根据视口的“缩放”更新尺寸。
修改:
我尝试类比:
如果您想要查看场景的特定部分,可以使用QGraphicsView::setSceneRect(const QRectF & 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 )