QGraphicsView::fitInView
- все, что вам нужно для выбора отображаемого диапазона и центра обзора.
Вот как вы можете это сделать. Это полный пример.
// https://github.com/KubaO/stackoverflown/tree/master/questions/scene-radar-40680065
#include <QtWidgets>
#include <random>
Во-первых, давайте получить случайные целевые позиции. Сцена масштабируется, например, Морские мили: таким образом, любая координата в сцене должна находиться в этих единицах.Это только соглашение: сцена в противном случае не волнует, равно как и представление. Исходная точка находится в 0,0: все диапазоны/подшипники относятся к началу координат.
QPointF randomPosition() {
static std::random_device dev;
static std::default_random_engine eng(dev());
static std::uniform_real_distribution<double> posDis(-100., 100.); // NM
return {posDis(eng), posDis(eng)};
}
Затем, чтобы помочь в превращении группы элементов сцены и выключаться (например КАРТОГРАФИЧЕСКАЯ СЕТКА), это помогает иметь пустой родительский элемент для них:
class EmptyItem : public QGraphicsItem {
public:
QRectF boundingRect() const override { return QRectF(); }
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override {}
};
Менеджер настроит дисплей , Пустые элементы действуют как коллекции элементов, и их можно легко сделать скрытыми/видимыми без необходимости изменять дочерние элементы. Они также применяют относительный Z-порядок своих детей.
class SceneManager : public QObject {
Q_OBJECT
Q_PROPERTY(bool microGraticuleVisible READ microGraticuleVisible WRITE setMicroGraticuleVisible)
QGraphicsScene m_scene;
QPen m_targetPen{Qt::green, 1};
EmptyItem m_target, m_center, m_macroGraticule, m_microGraticule;
Фильтр событий может быть установлен на вид, чтобы сигнализировать, когда изображение было изменено. Это может быть использовано, чтобы сохранить вид центрированный, несмотря на изменение размеров:
bool eventFilter(QObject *watched, QEvent *event) override {
if (event->type() == QEvent::Resize
&& qobject_cast<QGraphicsView*>(watched))
emit viewResized();
return QObject::eventFilter(watched, event);
}
Сцена имеет следующие Z-порядок: кросс-центр, макро- и микро-координатная сетка, а затем цели находятся на вершине.
public:
SceneManager() {
m_scene.addItem(&m_center);
m_scene.addItem(&m_macroGraticule);
m_scene.addItem(&m_microGraticule);
m_scene.addItem(&m_target);
m_targetPen.setCosmetic(true);
addGraticules();
}
Мы можем контролировать графический вид для изменения размера; мы также раскрываем видимость микрогранулы.
void monitor(QGraphicsView *view) { view->installEventFilter(this); }
QGraphicsScene * scene() { return &m_scene; }
Q_SLOT void setMicroGraticuleVisible(bool vis) { m_microGraticule.setVisible(vis); }
bool microGraticuleVisible() const { return m_microGraticule.isVisible(); }
Q_SIGNAL void viewResized();
Цели могут быть случайным образом сгенерированы. Цель имеет фиксированный размер в координатах вида. Его позиция, однако, подвержена любым преобразованиям с точки зрения зрения.
Ручки для целей и сетки - это косметические ручки: их ширина указывается в единицах устройства просмотра (в пикселях), а не в единицах сцены.
void newTargets(int count = 200) {
qDeleteAll(m_target.childItems());
for (int i = 0; i < count; ++i) {
auto target = new QGraphicsEllipseItem(-1.5, -1.5, 3., 3., &m_target);
target->setPos(randomPosition());
target->setPen(m_targetPen);
target->setBrush(m_targetPen.color());
target->setFlags(QGraphicsItem::ItemIgnoresTransformations);
}
}
В КАРТОГРАФИЧЕСКИХ СЕТКАХ представляют собой концентрические окружности с центром в начале координат (точках отсчета диапазона) и кросс в начале координат. Крест происхождения имеет фиксированный размер в единицах просмотра - это обозначается флагом ItemIgnoresTransformations
.
void addGraticules() {
QPen pen{Qt::white, 1};
pen.setCosmetic(true);
auto center = {QLineF{-5.,0.,5.,0.}, QLineF{0.,-5.,0.,5.}};
for (auto l : center) {
auto c = new QGraphicsLineItem{l, &m_center};
c->setFlags(QGraphicsItem::ItemIgnoresTransformations);
c->setPen(pen);
}
for (auto range = 10.; range < 101.; range += 10.) {
auto circle = new QGraphicsEllipseItem(0.-range, 0.-range, 2.*range, 2.*range, &m_macroGraticule);
circle->setPen(pen);
}
pen = QPen{Qt::white, 1, Qt::DashLine};
pen.setCosmetic(true);
for (auto range = 2.5; range < 9.9; range += 2.5) {
auto circle = new QGraphicsEllipseItem(0.-range, 0.-range, 2.*range, 2.*range, &m_microGraticule);
circle->setPen(pen);
}
}
};
Отображение между блоками сцены и представления сохраняется следующим образом:
Каждый раз, когда диапазон зрения изменяется (от, например, в поле со списком), метод QGraphicsView::fitInView
вызывается с прямоугольник в единицах сцены (морских миль). Это позаботится о все масштабирование, центрирование и т. Д.. Например. для выбора диапазона 10 Нм, мы бы назвали view.fitInView(QRect{-10.,-10.,20.,20.), Qt::KeepAspectRatio)
Грануляр (ы) можно отключить/включить, если необходимо, для заданного диапазона, чтобы развязать представление.
int main(int argc, char ** argv) {
QApplication app{argc, argv};
SceneManager mgr;
mgr.newTargets();
QWidget w;
QGridLayout layout{&w};
QGraphicsView view;
QComboBox combo;
QPushButton newTargets{"New Targets"};
layout.addWidget(&view, 0, 0, 1, 2);
layout.addWidget(&combo, 1, 0);
layout.addWidget(&newTargets, 1, 1);
view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view.setBackgroundBrush(Qt::black);
view.setScene(mgr.scene());
view.setRenderHint(QPainter::Antialiasing);
mgr.monitor(&view);
combo.addItems({"10", "25", "50", "100"});
auto const recenterView = [&]{
auto range = combo.currentText().toDouble();
view.fitInView(-range, -range, 2.*range, 2.*range, Qt::KeepAspectRatio);
mgr.setMicroGraticuleVisible(range <= 20.);
};
QObject::connect(&combo, &QComboBox::currentTextChanged, recenterView);
QObject::connect(&mgr, &SceneManager::viewResized, recenterView);
QObject::connect(&newTargets, &QPushButton::clicked, [&]{ mgr.newTargets(); });
w.show();
return app.exec();
}
#include "main.moc"
Я думаю, что идея «базового» размер сцены не требуется. Используйте любые единицы, имеющие смысл, например. морские мили, как ваши единицы сцены, и предположите, что ваше судно находится в начале координат. Затем поместите цели в координаты 'QPoint (диапазон * cos (подшипник), диапазон * sin (подшипник)'. Зум выбирает отображение между сценой и видом таким образом, чтобы заданное количество миль соответствовало виду. сцена будет позаботиться об остальном. –
Размер базовой сцены состоял в том, чтобы я помещал объекты в центр обзора перед смещением для преобразования диапазона и подшипника.Кроме того, это был элемент тестирования, который использовался, чтобы попытаться посмотреть, что изменит измерение единицы сцены. Как я могу использовать любые единицы, как мои единицы сцены? – bauervision
Просто для уточнения, 355 baseSize происходит из фактических размеров QGraphicsView в моем пользовательском интерфейсе. Если я не centerX = baseSceneSize/2; , тогда элементы создаются исходя из верхнего левого угла обзора, а не центра. – bauervision