Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: KontAr от Ноябрь 22, 2011, 15:28



Название: resize item'a с помощью маркеров
Отправлено: KontAr от Ноябрь 22, 2011, 15:28
Подскажите пожалуйста, как грамотно реализовать изменение размера итема. сейчас у меня есть унаследованный итем (пусть линия), ресайзИтем (квадратный маркер, как в КОМПАСЕ, COREL), сцена, которая содержит все итемы, и view, управляющий созданием и удалением ресайзИтемов. Правильно ли это?  ??? Может есть подобный механизм в самом итеме?

У меня получается, что myGraphicsView управляет всем: созданием, изменением всех элементов, в том числе маркеров.
4 инструмента + 7 позиций маркера = хаос((


Название: Re: resize item'a с помощью маркеров
Отправлено: panAlexey от Ноябрь 22, 2011, 16:16
4 инструмента + 7 позиций маркера = хаос((
Вообще-то у маркера 8 позиций.
+ еще одна, если требуется ротаре.
вот заготовочка, только делалась она не для сцены, а тупо для виджета, может поможет.
смысл: разметить определенные области картинок для ловли кликов по ним и реакции на клики.
генерирует тексовый файл с координатами.
Работает только с прямоугольными областями. Других вроде не надо было.
По клику мыши добавляет квадрат с маркерами на виджет, квадрат можно перемещать, удалять менять размер.


Название: Re: resize item'a с помощью маркеров
Отправлено: KontAr от Ноябрь 23, 2011, 09:48
никак не могу понять, является ли uoDiaLayer итемом, способным изменять себя или управление должно быть извне, например через представление или виджет?


Название: Re: resize item'a с помощью маркеров
Отправлено: panAlexey от Ноябрь 23, 2011, 10:47
никак не могу понять, является ли uoDiaLayer итемом, способным изменять себя или управление должно быть извне, например через представление или виджет?

uoDiaLayer управляет коллекцией QRect, используя события QWidget в который он встраивается.
Он отрисовывает свои QRect, маркеры в текущем QRect, реагируя на события мышки меняет текущий QRect, растягивает его и т.п.
Он не является итемом, а скорее менеджером поверх QWidget.
На его основе можно легко построить простенький редактор диалогов например.



Название: Re: resize item'a с помощью маркеров
Отправлено: KontAr от Ноябрь 23, 2011, 15:46
тогда, думаю, у меня правильное направление: сцена - это контейнер итемов, а все управление возложу на view. спасибо за ответы


Название: Re: resize item'a с помощью маркеров
Отправлено: _OLEGator_ от Ноябрь 23, 2011, 16:03
Я реализовывал такое поведение, когда сам айтем себя менял и сам задавал свое поведение.
Точнее даже не так, это был базовый класс для объектов, отрисовывающий себя с маркерами для манипуляции и отслеживающий все необходимые действия.
Все остальные айтемы были от него унаследованы.

Можно как вариант создать один такой айтем и при необходимости манипуляции помещать в него редактируемый айтем.

ИМХО, эту логику я бы не стал завязывать на вью, тем более могут появиться айтемы с другой логикой и потом потребуется явно приводить их к нужному классу, очнь плохая гибкость и расширяемость этого механизма.


Название: Re: resize item'a с помощью маркеров
Отправлено: KontAr от Ноябрь 23, 2011, 16:25
а этот базовый класс был сам по себе или унаследован от чего-либо?

я немного поясню, делаю векторный редактор, очень простой. из инструментов линия (отпрыск от QGraphicsLineItem), прямоугольник (от QGraphicsRectItem), эллипс (соотв). то есть базовый класс получается QGraphicsItem.

мне нужны маркеры не по краям какой-то области, а на самих элементах: по концам линии, в углах прямоугольника...
P.S. а про гибкость я уже понял, просто не знаю как иначе


Название: Re: resize item'a с помощью маркеров
Отправлено: _OLEGator_ от Ноябрь 23, 2011, 16:38
Базовый класс от QGraphicsItem.
По сути даже один общий абстрактный класс (не QGraphicsItem) с общими данными и несколько наследников (QGraphicsItem), например класс для маркеров для линейных объектов, для прямоугольных объектов.

По сути можно наследоваться от абстрактного класса со всей общей логикой, данными и функциями для изменения размеров, который НЕ QGraphicsItem и от требуемого QGraphicsItem, например так можно сделать кнопку с изменяющимися размерами.

Разделять логику приходится в таких ситуациях, как для линейных, когда изменяются координаты конкретных точек и допустим площадных, когда изменяются физические размеры объекта, хотя в некоторых ситуациях первый класс может просто расширять второго класса - равномерное расширение и сжатие линии при изменении размеров ограничивающего ее прямоугольника.


Название: Re: resize item'a с помощью маркеров
Отправлено: KontAr от Ноябрь 23, 2011, 17:25
нужен пример. не могу понять, куда дальше.
вот мой класс маркера:
Код:
#ifndef ITEMRESIZE_H
#define ITEMRESIZE_H

#include <QGraphicsPolygonItem>

class ItemResize : public QGraphicsPolygonItem
{
public:
    enum {Type = UserType + 37};
    enum resizePositions { None, UpperLeft, LowerRight, UpperRight, LowerLeft, Top, Bottom, Left, Right, Center };

    ItemResize();
    int type() const { return Type; }

    void setResizePosition(resizePositions position);
    resizePositions getResizePosition() {return resizeposition;}


    resizePositions resizeposition;
};

#endif // ITEMRESIZE_H


Название: Re: resize item'a с помощью маркеров
Отправлено: _OLEGator_ от Ноябрь 23, 2011, 22:18
Если ты желаешь реализовывать наследованием, то приблизительно так:
Код
C++ (Qt)
class ItemResize
{
   ///Все перечисления, переменные и прочее...
   resizeFunction(...);
}
 
class MyRect : public QGraphicsPolygonItem, ItemResize
{
 
}

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

Плюс еще надо определить в базовом классе метод отрисовки контрольных точек, который в обязательном порядке надо вызвать в переопределенном методе QGraphicsItem::paint().


Название: Re: resize item'a с помощью маркеров
Отправлено: KontAr от Ноябрь 24, 2011, 14:48
я попробовал такой вариант: в свой класс линии (унаследован только от QGraphicsLineItem) я включил 2 объекта маркера, передав в каждый указатель на эту линию, и положение маркера. линия теперь сама создает и удаляет маркеры из сцены. но для изменения размеров не удалось обойтись без явного приведения типов. то есть вся каша перекочевала из вью в класс маркера. получается это тупик?
мне непонятно, как в вашем базовом классе реализованы методы отрисовки маркеров, ведь он не от QGraphicsItem. Был бы рад простейшему образцу :-[


Название: Re: resize item'a с помощью маркеров
Отправлено: _OLEGator_ от Ноябрь 24, 2011, 15:54
А разве чтобы рисовать надо обязательно наследовать от QGraphicsItem?

В базовом классе реализовать функцию
Код
C++ (Qt)
void paintMarkers(QPainter* painter);

В наследнике в переопределенном методе
Код
C++ (Qt)
void QGraphicsItem::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 );
ее вызывать


Название: Re: resize item'a с помощью маркеров
Отправлено: KontAr от Ноябрь 27, 2011, 14:49
как в базовом классе указать координаты маркера, они ведь есть только только в наследнике?


Название: Re: resize item'a с помощью маркеров
Отправлено: _OLEGator_ от Ноябрь 28, 2011, 09:07
Если придерживаться описанного выше разделения класса линейных объектов и прямоугольных, то для линейных объектов я бы брал список точек, для прямоугольных - сам прямоугольник и по этим данным рисовал и отслеживал возможность изменения.

Совсем проблемно с проектированием?


Название: Re: resize item'a с помощью маркеров
Отправлено: KontAr от Ноябрь 28, 2011, 09:16
с графикой впервые работаю, до этого только БД. не скажу, что сильно проблемно, просто иногда простую мысль не сразу вижу


Название: Re: resize item'a с помощью маркеров
Отправлено: _OLEGator_ от Ноябрь 28, 2011, 09:23
Ясно.
Суть проектирования здесь остается та же - все общее для линий и прямоугольников - в базовый абстрактный класс, потом два наследника и реализация по максимуму общего функционала в них...


Название: Re: resize item'a с помощью маркеров
Отправлено: KontAr от Ноябрь 29, 2011, 15:28
видимо все-таки плохо у меня с наследованием :-\ раз уж мне нужна только линия (уже хватит и ее), то может обойтись без абстрактных классов? не попадалось ли случайно примеров полилинии (что-то вроде артура, только с возможностью добавления узлов)?


Название: Re: resize item'a с помощью маркеров
Отправлено: KontAr от Декабрь 10, 2011, 14:27
получилась у меня линия. и даже маркеры всё тянут, но появился эффект как в примере Path Stroking - маркеры срабатывают от щелчков, которые за километр от них самих. Может сталкивался кто с такой проблемой?
Код:
class ItemResize : public QGraphicsItem
{
public:
    ItemResize(int num) : QGraphicsItem()
    {
        setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
        setZValue(1000);
        numPoint = num;
    }

        void setNumPoint(int position);
        int  getNumPoint() {return numPoint;}

protected:
        int numPoint;

        QRectF boundingRect() const
            {return QRectF(-4, -4, 8, 8);}

        void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
        {
            painter->save();
            painter->setBrush(Qt::red);
            painter->drawEllipse(-4, -4, 8, 8);
            painter->restore();
        }

//        QPainterPath shape() const
//        {
//            QPainterPath path;
//            path.addEllipse(-4, -4, 8, 8);
//            return path;
//        }
};


Название: Re: resize item'a с помощью маркеров
Отправлено: KontAr от Декабрь 10, 2011, 17:37
в событии mousePressEvent  во view  я анализирую scene()->itemAt(mapToScene(event->pos())).
У маркеров значение Z = 1000, т.е. по любому щелчок мышки сначала попадет на него. Но срабатывают они даже если мыша на него не попала :(


Название: Re: resize item'a с помощью маркеров
Отправлено: steelvan от Январь 07, 2012, 21:45
Получилось редактор сделать ?

У меня похожая задача. Интересно ?

http://www.forum.crossplatform.ru/index.php?showtopic=8082



Название: Re: resize item'a с помощью маркеров
Отправлено: Fregloin от Январь 12, 2012, 18:09
Держите класс для изменения размеров итемов и виджетов на сцене (позволяет перемещать прокси-виджеты на сцене).

пример использования для прокси-виджета (все лишнее повырезал)

Код:
#ifndef QMOVABLEGRAPHICSPROXYWIDGET_H
#define QMOVABLEGRAPHICSPROXYWIDGET_H

#include <QDomDocument>
#include <QDomElement>
#include <QGraphicsProxyWidget>
#include "crailobject.h"
#include "cresizer.h"
#include "qcommonrailitem.h"

class QMovableGraphicsProxyWidget : public QGraphicsProxyWidget,
                                    public QCommonRailItem,
                                    public CResizer
{
    Q_OBJECT

    void            onDrag(QPointF NewPosition); //при перетаскивании
    void            onResize(); //при изменении размера с помощью маркера
    void            updateAnchors(); //обновить изображение маркеров

protected:

    void            mousePressEvent(QGraphicsSceneMouseEvent *event);
    void            mouseMoveEvent(QGraphicsSceneMouseEvent *event);

    QRectF          boundingRect() const;
    void            paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    void            resizeEvent(QGraphicsSceneResizeEvent *event);
    QPainterPath    shape() const;
    void            focusInEvent(QFocusEvent *event);
    void            focusOutEvent(QFocusEvent *event);

public:
    explicit    QMovableGraphicsProxyWidget(QGraphicsItem * parent = 0, Qt::WindowFlags wFlags = 0);
    ~QMovableGraphicsProxyWidget();
    void        setWidget(QWidget *widget);

public  slots:

};


#endif // QMOVABLEGRAPHICSPROXYWIDGET_H

Код:
void    QMovableGraphicsProxyWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
        if(work_state==wsEditing)
        {
            CResizer::mousePressEvent(event);
        }
        else
        if(event->button()==Qt::RightButton)
        {
            QGraphicsSceneContextMenuEvent cevent;
            cevent.setPos(event->pos());
            contextMenuEvent(&cevent);
        }
}

void    QMovableGraphicsProxyWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    if(work_state==wsEditing)
    {
        CResizer::mouseMoveEvent(event,pos());
    }
    else
    QGraphicsProxyWidget::mouseMoveEvent(event);
}

QRectF    QMovableGraphicsProxyWidget::boundingRect() const
{
    QRectF  rect = QGraphicsProxyWidget::boundingRect();
    if(isSelected()) rect.adjust(-6,-6,6,6);
    return rect;
}

void    QMovableGraphicsProxyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QGraphicsProxyWidget::paint(painter,option,widget);
    if((option->state & QStyle::State_Selected) && work_state == wsEditing)
    {
        CResizer::paint(painter,option,widget);
    }
}

QPainterPath    QMovableGraphicsProxyWidget::shape() const
{
    QPainterPath path;
    path.addRect(-6,-6,widget()->width()+12,widget()->height()+12);
    return path;
}

void    QMovableGraphicsProxyWidget::resizeEvent(QGraphicsSceneResizeEvent  * event)
{
    CResizer::setSize(event->newSize());
}

void    QMovableGraphicsProxyWidget::onDrag(QPointF NewPosition)
{
    setPos(NewPosition);
}

void    QMovableGraphicsProxyWidget::onResize()
{
    if(widget())
    {
        widget()->resize(qCeil(CResizer::size().width()),qCeil(CResizer::size().height()));
    }
    //setSize(CResizer::size());
}

void    QMovableGraphicsProxyWidget::updateAnchors()
{
    update();
}

void    QMovableGraphicsProxyWidget::setWidget(QWidget *widget)
{
    QGraphicsProxyWidget::setWidget(widget);
    if(widget)
    {
        CResizer::setSize(QSizeF(widget->size().width(),widget->size().height()));
    }
}



Название: Re: resize item'a с помощью маркеров
Отправлено: Fregloin от Январь 12, 2012, 18:11
класс немного недоработан, но основной функционал реализован - отображение маркеров, изменение размера итема при перетаскивании маркера, перетаскивание прокси-виджета (так как сама сцена этого почемуто не умеет)