Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: developer-nsk от Октябрь 06, 2009, 12:31



Название: Создание "легенды" на карте
Отправлено: developer-nsk от Октябрь 06, 2009, 12:31
Господа, вот в чём суть проблемы - есть некая карта (QGraphicsScene), которая отображается в QGraphicsView. Соответственно, эту карту можно вращать и т.д. Каким образом можно добавить на QGraphicsView виджет, который будет не подвержен трансформации? Т.е. необходимо сделать линейку изменения масштаба, компас примерно как в maps.google.ru, а также "легенду", которые будут постоянно отображаться не зависимо от состояния сцены. Искал в инете примеры - не нашёл. Заранее благодарен!


Название: Re: Создание "легенды" на карте
Отправлено: Khs от Октябрь 06, 2009, 12:41
Может быть добавить свой виджет с парентом QGraphicsView. Либо сделать свои айтемы сцены с флагами *без трансформации*, но это не есть гуд - доп нагрузка на сцену + перемещать их при перемещеннии контента карты.


Название: Re: Создание "легенды" на карте
Отправлено: developer-nsk от Октябрь 06, 2009, 12:47
Второй вариант уже пытался сделать - вообще не айс получается... Карта и так загружена айтемами, поэтому с перемещениями никак не получится. Делают же люди как-то легенды для всяких диаграмм :-) Вот мне что-то типа этого надо...


Название: Re: Создание "легенды" на карте
Отправлено: Khs от Октябрь 06, 2009, 12:56
Ну потому я и написал что вариант с айтемами не айс))
А что тебе не нравится 1й вариант?
Люди то делают, но они же не обязательно используют QGraphicsView-Scene :)


Название: Re: Создание "легенды" на карте
Отправлено: developer-nsk от Октябрь 06, 2009, 13:01
Спору нет, не обязательно... Просто лично я ещё не супер-ас в Qt, поэтому первый вариант слабо себе представляю, каким образом это можно сделать... Сейчас у меня мысли такие - создать QGraphicsItem для масштаба, для компаса и т.д. Причём не важно, кто у них будет парентом. Что дальше делать - не знаю, бьюсь уже дня два...


Название: Re: Создание "легенды" на карте
Отправлено: ufna от Октябрь 06, 2009, 13:07
вообще, можно пойти классическим путем, "компьютерных игрушек" - рисуй поверх графикс вью.


Название: Re: Создание "легенды" на карте
Отправлено: developer-nsk от Октябрь 06, 2009, 13:10
Спасибо за ответ, но есть ли какой-нибудь пример? Ибо как это делается конкретно в Qt - не до конца себе представляю по причине небольшого опыта в Qt...


Название: Re: Создание "легенды" на карте
Отправлено: ufna от Октябрь 06, 2009, 13:33
что за легенда у тебя будет? Какие виджеты ты хочешь сделать? Какая у них степень взаимодействия с пользователем?


Название: Re: Создание "легенды" на карте
Отправлено: Barmaglodd от Октябрь 06, 2009, 13:51
что за легенда у тебя будет? Какие виджеты ты хочешь сделать? Какая у них степень взаимодействия с пользователем?
Вот не пофиг?

Если не хочешь использовать не трансформируемые QGraphicsItem'ы, делай свои виджеты. Перегрузи paintEvent,  нарисуй линейку, компас, всё, что хочешь. Я сам так делаю для отображения выделения и редактирования объектов на карте.

Код:
#include <QWidget>

class MapView;

class CreatePolyLineTool : public QWidget
{
Q_OBJECT

protected:
void paintEvent(QPaintEvent* ev);
bool eventFilter(QObject *obj, QEvent *ev);
public:
CreatePolyLineTool(QWidget* parent);
};

Код:
#include "CreatePolyLineTool.h"
#include <QPainter>

CreatePolyLineTool::CreatePolyLineTool(QWidget*parent)
: QWidget(parent)
{
resize(parent->size());
parent->installEventFilter(this);
}


void CreatePolyLineTool::paintEvent(QPaintEvent* ev)
{
QPainter painter(this);
//Рисуем, что хотим
// painter.drawPolyline(_polygon);
}

bool CreatePolyLineTool::eventFilter(QObject* obj, QEvent* ev)
{
if(obj==parentWidget() && ev->type()==QEvent::Resize)
resize(parentWidget()->size());
return false;
}



Название: Re: Создание "легенды" на карте
Отправлено: developer-nsk от Октябрь 06, 2009, 14:20
что за легенда у тебя будет? Какие виджеты ты хочешь сделать? Какая у них степень взаимодействия с пользователем?

Степень взаимодействия с пользователем разная - от никакой (например, линейка, которая показывает текущий масштаб в метрах) до изменения масштаба... В общем, можно в гуглмапс увидеть часть того, что надо :-)


Название: Re: Создание "легенды" на карте
Отправлено: developer-nsk от Октябрь 06, 2009, 14:36
что за легенда у тебя будет? Какие виджеты ты хочешь сделать? Какая у них степень взаимодействия с пользователем?
Вот не пофиг?

Если не хочешь использовать не трансформируемые QGraphicsItem'ы, делай свои виджеты. Перегрузи paintEvent,  нарисуй линейку, компас, всё, что хочешь. Я сам так делаю для отображения выделения и редактирования объектов на карте.


Спасибо большое! Вот это уже похоже на то, что нужно! Только не перехватывал бы ещё этот виджет wheelEvent у QGraphicsView, было бы вообще классно... :-)


Название: Re: Создание "легенды" на карте
Отправлено: Barmaglodd от Октябрь 07, 2009, 08:07
Код:
void CreatePolyLineTool::wheelEvent ( QWheelEvent * event ) 
{
     event->ignore();
}

Хотя у меня и без этого не перехватывается. Может parent выставлен не на QGraphicsView?


Название: Re: Создание "легенды" на карте
Отправлено: developer-nsk от Октябрь 12, 2009, 17:20
Код:
void CreatePolyLineTool::wheelEvent ( QWheelEvent * event ) 
{
     event->ignore();
}

Хотя у меня и без этого не перехватывается. Может parent выставлен не на QGraphicsView?

Нет, parent точно выставлен на QGraphicsView, а вот предложенное Вами решение помогло. Спасибо большое!


Название: Re: Создание "легенды" на карте
Отправлено: mell от Октябрь 18, 2009, 15:14
что-то у меня пример Barmaglodd-а мало того, что перехватывает wheelEvent у QGraphicsView, так и мышь полностью не работоспособна в QGraphiscScene... может есть у кого примеры поподробнее?


Название: Re: Создание "легенды" на карте
Отправлено: Barmaglodd от Октябрь 18, 2009, 15:32
Может стоит и на другие события мыши повесить повесить аналогичные обработчики? ;)


Название: Re: Создание "легенды" на карте
Отправлено: mell от Октябрь 18, 2009, 16:21
мне почему-то такая вещь не помогает, как собственно и другие мышиные обработчики
Код:
void wheelEvent ( QWheelEvent * event ) 
{
     event->ignore();
}



Название: Re: Создание "легенды" на карте
Отправлено: Barmaglodd от Октябрь 19, 2009, 07:36
parent точно QGraphicsView?


Название: Re: Создание "легенды" на карте
Отправлено: mell от Октябрь 19, 2009, 22:03
Вот как я это делаю:

GraphicsScene.h:
Код:
#include "GraphicsLegend.h"

#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsTextItem>

class GraphicsScene : public QGraphicsScene
{
public:
    GraphicsScene();
QGraphicsView *getView() { return &view; }

private:
QGraphicsView view;
GraphicsLegend legend;

void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent);

};

GraphicsScene.cpp:
Код:
#include "GraphicsScene.h"

GraphicsScene::GraphicsScene()
: legend (&view)
{
view.setScene(this);
QGraphicsTextItem *text = this->addText("text");
text->setPos(200,200);
}

void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *)
{
exit(1);
}

соответственно в классе легенды:

GraphicsLegend.h:
Код:
#include <QWidget>
#include <QPainter>
#include <QMouseEvent>

class GraphicsLegend : public QWidget
{
Q_OBJECT
public:
GraphicsLegend(QWidget* parent);

protected:
void paintEvent(QPaintEvent* ev);
bool eventFilter(QObject *obj, QEvent *ev);

virtual void mousePressEvent ( QMouseEvent * event )
{
event->ignore();
}

void wheelEvent ( QWheelEvent * event )
{
event->ignore();
}
};

ни клики, ни колесико в GraphicsScene не обрабатывается....


Название: Re: Создание "легенды" на карте
Отправлено: Barmaglodd от Октябрь 20, 2009, 08:29
Текст конструктора GraphicsScene можно? Меня терзают смутные сомнения, что у legend конструктор вызван с parent=0.


Название: Re: Создание "легенды" на карте
Отправлено: mell от Октябрь 20, 2009, 12:24
текст конструктора привел во втором листинге (GraphicsScene.cpp)

соответственно то-же самое, если в конструкторе написать :
Код:
GraphicsLegend *legend = new GraphicsLegend(&view);


Название: Re: Создание "легенды" на карте
Отправлено: Barmaglodd от Октябрь 21, 2009, 08:34
У меня всё работает, не знаю в чём проблема.
Версия Qt какая?


Название: Re: Создание "легенды" на карте
Отправлено: mell от Октябрь 21, 2009, 14:10
Barmaglodd, в твоем примере не передается парент в базовый класс... поэтому и воводиться легенда не будет
Код:
GraphicsLegend(QWidget* parent)
{
    resize(parent->size());
    parent->installEventFilter(this);
 }

а вот так выводиться, он не работает мышь
Код:
class GraphicsLegend : public QWidget
{
Q_OBJECT
public:
GraphicsLegend(QWidget* parent)
: QWidget (parent)
    {
        resize(parent->size());
        parent->installEventFilter(this);
    }

protected:
void paintEvent(QPaintEvent* ev)
    {
QPainter painter(this);
painter.drawText(50, 50, "!!");
    }

bool eventFilter(QObject *obj, QEvent *ev)
    {
        if(obj==parentWidget() && ev->type()==QEvent::Resize)
            resize(parentWidget()->size());
        return false;
    }
};

Qt 4.5.0 linux/windows


Название: Re: Создание "легенды" на карте
Отправлено: Barmaglodd от Октябрь 22, 2009, 08:43
Нашёл в чём косяк. Я работаю не с QGraphicsView, а со своим виджетом. Если отдебажить обработку нажатия мыши, то видно, что QAbstractScrollArea в методе event тупо съедает все события от мыши, и не вызывает QFrame::event, где должен быть вызов QWidget::event, где уже вызываются конкретные обработчики mousePressEvent и т.п. Так что, либо реализовывать корректно event в наследнике от QGraphicsView, либо искать какие-то другие решения.


Название: Re: Создание "легенды" на карте
Отправлено: mell от Октябрь 22, 2009, 11:13
спасибо, помогли разобраться:)
Если в GraphicsScene использовать такой GraphicsView:
Код:
#include <QGraphicsView>
#include <QEvent>

class GraphicsView : public QGraphicsView
{
public:
    GraphicsView();

protected:
virtual bool event(QEvent *event)
{
if (event->type() == QEvent::MouseButtonPress) {
this->mousePressEvent((QMouseEvent *)event);
return false;
}
else if ( event->type() == QEvent::Wheel ) {
this->wheelEvent((QWheelEvent *)event);
return false;
}
// else if ... и т.д.

return QGraphicsView::event(event);
}
};
то все работает. Надеюсь решение "красивое".


Название: Re: Создание "легенды" на карте
Отправлено: Igors от Октябрь 22, 2009, 12:26
то все работает. Надеюсь решение "красивое".
switch (event->type()) смотрится лучше и править удобнее


Название: Re: Создание "легенды" на карте
Отправлено: developer-nsk от Октябрь 23, 2009, 13:25
что-то у меня пример Barmaglodd-а мало того, что перехватывает wheelEvent у QGraphicsView, так и мышь полностью не работоспособна в QGraphiscScene... может есть у кого примеры поподробнее?


Чёрт, на самом деле я тоже ошибся... В действительности пример Barmaglodd-а у меня не заработал... Господа, подскажите, пожалуйста, как бороться с проблемой того, что виджет перехватывает на себя все события, типа wheelEvent, хотя очень хочется, чтобы их обрабатывал parentWidget? Заранее спасибо!


Название: Re: Создание "легенды" на карте
Отправлено: mell от Октябрь 23, 2009, 15:01
чуть выше приведен пример наследника QGraphicsView


Название: Re: Создание "легенды" на карте
Отправлено: developer-nsk от Октябрь 23, 2009, 17:04
Спасибо, сейчас попробую :-)


Название: Re: Создание "легенды" на карте
Отправлено: fuCtor от Октябрь 28, 2009, 12:18
Чтобы не плодить темы задам вопрос здесь.

Можно ли тоже самое реализовать, но используя QStackedLayout? Если выставить:
stackLayout_->setStackingMode(QStackedLayout::StackAll);
И первым добавить карту, а потом все остальное поверх, то видно и то и то, но как сделать, чтобы сообщения прокидывались на карту, а не перехватывались верхним.
Если для верхнего виджета установить атрибут "прозрачный для мыши", то карта получает сообщения, но элементы лежащие над картой нет.


Название: Re: Создание "легенды" на карте
Отправлено: mell от Октябрь 28, 2009, 15:21
попробуй где-нибудь перехватывать QEvent, как в моем примере выше, и пересылать их на виджет-карту


Название: Re: Создание "легенды" на карте
Отправлено: fuCtor от Октябрь 28, 2009, 22:02
Ставил фильтр и через postEvent отправлял в карту. Как результат дедлок. Есть еще вариант сделать класс дружественным и отправлять напрямую в QWidget::event.


Название: Re: Создание "легенды" на карте
Отправлено: zalivaha от Ноябрь 06, 2009, 23:59
Тут похожее решение http://wiki.crossplatform.ru/index.php/%D0%A0%D0%B8%D1%81%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%B2%D0%B5%D1%80%D1%85_%D0%B4%D0%BE%D1%87%D0%B5%D1%80%D0%BD%D0%B8%D1%85_%D0%B2%D0%B8%D0%B4%D0%B6%D0%B5%D1%82%D0%BE%D0%B2 (http://wiki.crossplatform.ru/index.php/%D0%A0%D0%B8%D1%81%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%B2%D0%B5%D1%80%D1%85_%D0%B4%D0%BE%D1%87%D0%B5%D1%80%D0%BD%D0%B8%D1%85_%D0%B2%D0%B8%D0%B4%D0%B6%D0%B5%D1%82%D0%BE%D0%B2)