Russian Qt Forum
Май 03, 2024, 23:34 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: QGraphicsView/Scene  (Прочитано 21893 раз)
Khs
Гость
« : Декабрь 21, 2008, 23:13 »

Привет всем! Вроде просмотрел все топики в этом форуме касающиеся данного вопроса, но нормального ответа не нашел.

1. Чем отличается setBackgroundBrush(...) у QGraphicsView от аналогичной функции setBackgroundBrush(...) у QGraphicsScene, и что является предпочтительнее. Например в моем случае, я делаю карту страны, на которой буду размещать объекты - дороги, города и тп. И я хотел в background поместить пустую карту страны (чтобы на ней уже потом размещать магистрали и тп.).

2. При установке изображения в background QGraphicsView/QGraphicsScene, изображение множество раз повторяется (тоесть как будто матрица изображений получается). А я хотел бы чтобы оно отображалось 1 раз. Как это реализовать?

3. Какой тип карты лучше использовать, векторный или растровый?!

4. В случае растрового изображения, поместить его в background QGraphicsView/QGraphicsScene не проблема вроде. А как быть с векторным изображением?
Записан
Rcus
Гость
« Ответ #1 : Декабрь 21, 2008, 23:47 »

1. отличие в том что у сцены может быть несколько отображений. Метод QGraphicsScene::setBackgroundBrush() задает кисть для всей сцены, метод QGraphicsView::setBackgroundBrush() задает кисть для конкретного отображения. В описанном случае я бы вообще использовал ::drawBackground()

2. см. п.1

3. "this depends on.." Ваша задача не нова, можно изучить решения предшественников.

4. если изображение в формате svg, то в Qt есть модуль его поддержки
Записан
Khs
Гость
« Ответ #2 : Декабрь 21, 2008, 23:52 »

п.1 Ну а если сцена одна и вид один, есть ли разница где рисовать фон?!

п.3, Я в курсе что вопрос не новый, просто хотел услышать совета от людей которые этим сами занимались.

п.4, Да, я видел классы для svg, но не совсем понял, как мне все это дело потом отобразить в QGraphicsView. Надо будет еще разок посмотреть.
Кто еще что посоветует?!

-

Такс, ну вроде разобрался Улыбающийся
« Последнее редактирование: Декабрь 23, 2008, 11:21 от log1c » Записан
AAXEE
Гость
« Ответ #3 : Декабрь 25, 2008, 17:05 »

1. Вроде так:
Представь, что сцена квадратная, и она целиком внутри прямоугольной(не квадратной) view.
Так вот фон у сцены будет занимать квадрат, а фон view будет тот, что вне сцены, но внутри view( полоски по краям).
Записан
Khs
Гость
« Ответ #4 : Декабрь 25, 2008, 22:36 »

Ага, я уже разобрался, но все равно спасибо Подмигивающий

Буду задавать здесь другие вопросы по мере разработки проги Улыбающийся
Записан
Khs
Гость
« Ответ #5 : Декабрь 26, 2008, 14:47 »

Такс, назрел еще один вопрос.
Во всяких геосистемах есть такая функция, как увеличение определенного участка карты (тоесть выделяешь мышкой какой то прямоугольник на карте и экран автоматически центруется на этом участке и он увеличивается..).
Так же хочу сделать и я у себя, я так полагаю, после выделения участка, необходимо чтобы он отцентровался на области, и там уже применить scale(). Или это делается как то проще?!
Записан
QCasper
Гость
« Ответ #6 : Декабрь 26, 2008, 14:53 »

QGraphicsView::centerOn() ?
Записан
Khs
Гость
« Ответ #7 : Декабрь 26, 2008, 15:10 »

Точно! Спасибо! Улыбающийся
Записан
Khs
Гость
« Ответ #8 : Декабрь 27, 2008, 13:50 »

Имею 3 своих класса, например, classMainWindow (главное окно, на нем размещен тулбар) унаследован от QMainWindow, classGraphicsView (отображается в главном окне) унаследован от QGraphicsView , classGraphicsScene (сцена своего отображения) унаследован от QGraphicsScene.
Так вот, на тулбаре допустим 3 кнопки (b1, b2, b3) - Они являются переключателями режима редактирования для GraphicsView/Scene, тоесть режим поворота, зума и тп.
Так вот, как лучше сделать связь.

Я предполагаю так, на сигнал нажатия кнопки, вызывается соответствующий слот (например slot_rotate(), slot_zoom() и тп).
Рассмотрю на одном слоте.
Допустим
slot_zoom()
{
   // В классе classMainWindow имеются указатели на объект класса classGraphicsView/Scene
   // m_view, m_scene например...

   // здесь меняю курсор у сцены на соответствующий режиму зума через m_scene->setCursor()
   // теперь нужно чтобы при клике на Scene, выполнялось действие соответствующее
   // включенному режиму.
   // Здесь собственно и хотел бы узнать как лучше сделать.

   // Я думаю сделать так, создать какие то флаги - соответствующие режимам, создать в
   // классе classGraphicsScene метод, например setFlag(int flag), и в вызванном слоте, в данном
   // случае slot_zoom() вызывать m_scene->setFlag(zoom_flag). А в переопределенном
   // mousePress в классе classGraphicsScene уже делать switch(flag) и производить необходимые
   // действия в зависимости от режима.
}

Так вот, моя реализация буит правильной? или есть более умные пути к решению данной задачки..?!
« Последнее редактирование: Декабрь 27, 2008, 13:52 от log1c » Записан
BRE
Гость
« Ответ #9 : Декабрь 27, 2008, 14:29 »

Можно так. Вообще можно придумать много вариантов.
Например, можно в classMainWindow добавить сигнал changedState( State ), который подключать ко всем, кому необходимо отслеживать изменение состояния.
Записан
BRE
Гость
« Ответ #10 : Декабрь 30, 2008, 09:40 »

Как вариант, можно сделать что-то типа:
Код
C++ (Qt)
class State
{
public:
virtual void mouseMove(...) = 0;
virtual void mousePress(...) = 0;
virtual void keyboarPress(...) = 0;
};
 
// Переопределить методы для режима zoom
class ZoomState : public State
{
public:
virtual void mouseMove(...);
virtual void mousePress(...);
virtual void keyboarPress(...);
};
 
// Переопределить методы для режима rotate
class RotateState : public State
{
public:
virtual void mouseMove(...);
virtual void mousePress(...);
virtual void keyboarPress(...);
};
 

А в соответствующих обработчиках событий classGraphicsScene:
Код
C++ (Qt)
// currentState это указатель на State
 
void classGraphicsScene::mouseMoveEvent(...)
{
currentState->mouseMove(...);
}
 
void classGraphicsScene::mousePressEvent(...)
{
currentState->mousePress(...);
}
 

Смена режима, это изменение указателя currentState на объект соответствующего класса.
« Последнее редактирование: Декабрь 30, 2008, 09:42 от BRE » Записан
Khs
Гость
« Ответ #11 : Декабрь 30, 2008, 17:45 »

Ну да, по сути можно по-разному все это реализовать, просто я когда спрашивал, хотел узнать как будет оптимальней Улыбающийся
Записан
Khs
Гость
« Ответ #12 : Январь 13, 2009, 10:17 »

Итак, возник вопрос из той же темы Улыбающийся

Структуру классов описывал выше. Так вот. Сделал так.
В главном окне класса classMainWindow, создал тулбар, на котором имеется допустим 5 тулбаттонов (каждая кнопка это какой-то режим, тоесть задействован может только 1 режим). На группу (QButtonGroup *toolsGroup) повесил коннект:
connect(m_toolsGroup, SIGNAL(buttonClicked(int)), SLOT(toolsGroupClicked(int)));
, где:

void classMainWindow::toolsGroupClicked(int)
{
    m_mapScene->setMode(classGraphicsScene::Mode(m_toolsGroup->checkedId()));
}


Тоесть в зависимости от переключателя в классе сцены устанавливается режим (зум, поворот иль т.п.)

В классе сцены соответственно имеется слот:

void classGraphicsScene::setMode(Mode mode)
{
    m_Mode = mode;

    switch(m_Mode)
    {
        case mode_zoomin:
             //
        break;

        case ...
        ...
    }
}


Тоесть здесь устанавливается режим в сцене и при событии mousePressEvent(...) в зависимости от режима, выполняются действия (либо со сценой, например размещение элемента на сцене, либо со вьюшкой, тоесь поворот, либо зум).

void classGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
     switch(m_Mode)
    {
        case mode_zoomin:
             // надо сделать зум например
        break;

        case ...
        ...
    }
}


Так вот, сам вопрос, scale и rotate, они ж принадлежат объекту класса classGraphicsView. Как мне их вызвать из одного из этих case? Я так полагаю, либо я сделал неправильно архитектуру взаимодействия классов, либо как-то нужно сделать слоты и сигналы, тока не оч. пойму как это лучше сделать :\
Записан
Rcus
Гость
« Ответ #13 : Январь 13, 2009, 10:40 »

Я бы это реализовал как перехватчик событий представления, который имеет слот для смены состояния. А внутри класса делегировать полномочия по обработке событий через функциональные указатели/композицию объектов
Записан
Rcus
Гость
« Ответ #14 : Январь 13, 2009, 14:11 »

/*hdr*/
Код
C++ (Qt)
#ifndef RVIEWWATCHER_H
#define RVIEWWATCHER_H
 
#include <QObject>
 
class QGraphicsView;
class QEvent;
 
class RViewWatcher : public QObject
{
   Q_OBJECT
public:
   RViewWatcher(QGraphicsView *view, QObject *parent);
   int state() const;
public slots:
   void setState(int id);
protected:
   typedef bool (*Delegate)(QGraphicsView *, QEvent *);
   Delegate _handler;
   int _state;
   bool eventFilter(QObject *watched, QEvent *event);
};
 
#endif // RVIEWWATCHER_H
 
/*src*/
Код
C++ (Qt)
#include "rviewwatcher.h"
#include <QGraphicsView>
#include <QEvent>
#include <QMouseEvent>
 
bool zoomer(QGraphicsView *view, QEvent *event)
{
   static const qreal ZOOM_FACTOR = 1.05;
   if (event->type() != QEvent::MouseButtonPress)
       return false;
   QMouseEvent *e = static_cast<QMouseEvent *>(event);
   switch (e->button()) {
   case Qt::LeftButton:
       view->setMatrix(QMatrix(ZOOM_FACTOR, 0, 0, ZOOM_FACTOR, 0, 0), true);
       break;
   case Qt::RightButton:
       view->setMatrix(QMatrix(1/ZOOM_FACTOR, 0, 0, 1/ZOOM_FACTOR, 0, 0), true);
       break;
   case Qt::MidButton:
       view->resetMatrix();
       break;
   default:
       return false;
   }
   return true;
}
 
bool doNothing(QGraphicsView *view, QEvent *event)
{
   return false;
}
 
RViewWatcher::RViewWatcher(QGraphicsView *view, QObject *parent) : QObject(parent)
{
   view->installEventFilter(this);
   setState(1);
}
 
int RViewWatcher::state() const
{
   return _state;
}
 
void RViewWatcher::setState(int id)
{
   switch (id) {
   case 0:
       _handler = zoomer;
       break;
   case 1:
       _handler = doNothing;
       break;
   default:
       Q_ASSERT(false);
   }
}
 
bool RViewWatcher::eventFilter(QObject *watched, QEvent *event)
{
   if (!qobject_cast<QGraphicsView *>(watched))
       return false;
   return _handler(static_cast<QGraphicsView *>(watched), event);
}
 

Через функциональные указатели конечно просто, но для чего-то серьезного непригодно, а идея композиции уже была указана в сообщении BRE.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.247 секунд. Запросов: 20.