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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: умное выделение графика  (Прочитано 6210 раз)
_Vitaliy_
Гость
« : Февраль 02, 2012, 10:31 »

Доброго времени суток.
На сцену нужно вывести порядка двадцати графиков функций, каждый график представляет собой "достаточно ломанную кривую", есть необходимость перемещать графики по сцене, как организовать правильное выделение каждого графика?

Код:
QRectF Grafik::boundingRect() const
{
    return QRectF(0, 0, my_model->rowCount()+10, size_y);
}

Код:
QPainterPath Grafik::shape() const
{
    QPainterPath path;
    path.addRect(1, 1, size_x, size_y);
    return path;
}

сама отрисовка:
Код:
void Grafik::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(widget);

    QColor fillColor = (option->state & QStyle::State_Selected) ? color.dark(150) : color;
    if (option->state & QStyle::State_MouseOver)
        fillColor = fillColor.light(125);

    const qreal lod = option->levelOfDetailFromTransform(painter->worldTransform());

    QVarLengthArray<QPointF> pointsss;
    QList<double> x;

    for (int i = 0; i <= size_x-1; i++)
    {
        x.append(my_model->item(i, stolbec)->text().toFloat());
        pointsss.append(QPointF(i,x[i]));
    }

    painter->setPen(QPen(color, 2));
    painter->drawPoints(pointsss.data(), pointsss.size());

}


QPainterPath Grafik::shape() будет выделять прямоугольник, который может накладываться друг на друга и правильного выделения не происходит.
Как это победить? Т.е. необходимо, чтобы при наведении на сам график +- например 3 пикселя происходило выделение.
П.С. Предварительный поиск по форуму в первом приближении результатов не принес, может не то искал.
Записан
_Vitaliy_
Гость
« Ответ #1 : Февраль 02, 2012, 13:53 »

на мой взгляд несколько вариантов?
1. правильно задать shape()
2. переопределить mousePressEvent
3. использование QPainterPath::LineTo и задать толщину например если линия у меня рисуется в 2 пикселя, то для PainterPath задать например в 5-7 пикселей.

В каком направлении двигаться? 
Записан
_OLEGator_
Гость
« Ответ #2 : Февраль 03, 2012, 09:23 »

4. Переопределить функцию
Код
C++ (Qt)
bool QGraphicsItem::collidesWithPath ( const QPainterPath & path, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape ) const
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #3 : Февраль 03, 2012, 09:50 »

Добавь на выбранный элемент размытый контур через QGraphicsItem::setGraphicsEffect( new QGraphicsDropShadowEffect( ... )  ).
Ну и подними его выше всех других через QGraphicsItem::setZValue().
Записан

Qt 5.11/4.8.7 (X11/Win)
_Vitaliy_
Гость
« Ответ #4 : Февраль 03, 2012, 11:00 »

вывод на сцену производится следующим образом:
Код:
QGraphicsItem *item = new Grafik(model, Qt::red, 3, min, max);
        item->setPos(QPointF(0, 200));
        item->setFlag(QGraphicsItem::ItemIsMovable, true);

это все в цикле.

для _OLEGator_
Пока не пойму как использовать
Код:
bool QGraphicsItem::collidesWithPath ( const QPainterPath & path, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape ) const

ассистент смотрел, но примера использования не нашел, а так пока образования не хватает, отправте хоть к примеру какому-нибудь, буду разбираться. 

для GreatSnake
В том то и дело что нормально выбрать элемент не могу, очень часто выделяются другие, а не тот, который хочешь.
Записан
_OLEGator_
Гость
« Ответ #5 : Февраль 03, 2012, 11:10 »

Это функция для самостоятельной реализации проверки пересечения с произвольным путем.
В случае нажатия мышкой в path будет содержаться всего один элемент (path.elementCount() == 1), можно извлечь координаты из пути (path.elementAt(0)), дальше уже самому реализовать проверку на попадание в нужное отклонение от ломанной.
Записан
_Vitaliy_
Гость
« Ответ #6 : Февраль 06, 2012, 20:14 »

После некоторых размышлений практически решил проблему в лоб.
само рисование:
Код:
void Grafik::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    ...
    const qreal lod = option->levelOfDetailFromTransform(painter->worldTransform());

    QVarLengthArray<QPointF> pointsss;
    QList<double> x;

    for (int i = 0; i <= size_x-2; i++)
    {
        x.append(my_model->item(i, stolbec)->text().toFloat());
        pointsss.append(QPointF(i,x[i]));
   
        path1.moveTo(i,x[i]);
        path1.lineTo(i+1, my_model->item(i+1, stolbec)->text().toFloat());
    }

    painter->setPen(QPen(color, 2));
    painter->drawPoints(pointsss.data(), pointsss.size());
    painter->setPen(QPen(Qt::blue,15));
    //painter->drawPath(path1);
}

т.е. добавил траекторию path1, соответственно в
Код:
QPainterPath Grafik::shape() const
{
    //QPainterPath path1;
 //   path.addRect(1, 1, size_x, size_y/2);
    return path1;
}
прописал эту траекторию.

Однако выбор графика необходимо осуществлять "очень точно", малейшее отклонение и выбора не происходит, а хотелось бы чтобы по оси игрек можно было бы иметь запас +-10 пикселей. Установка painter->setPen(QPen(Qt::blue,15)) желаемого результата не принесла.

переопределил нажатия мышью
Код:
void Grafik::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    QGraphicsItem::mousePressEvent(event);
    QGraphicsItem::setCursor(Qt::ClosedHandCursor);
    update();
}

Код:
void Grafik::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    QGraphicsItem::setCursor(Qt::ClosedHandCursor);
    QGraphicsItem::mouseMoveEvent(event);

    if (QGraphicsItem::pos().x()!=0) // zapret peremesheniya po X
    {
        QGraphicsItem::setX(0);
    }
    update();   
}


Код:
void Grafik::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
   QGraphicsItem::setCursor(Qt::OpenHandCursor);
   QGraphicsItem::mouseReleaseEvent(event);
   update();
}

но теперь это начинает немного подтормаживать на одном тестовом графике, а их должно быть несколько десятков.
В какую сторону искать оптимизацию, потому что скорее всего изобрел велосипед.
З.Ы. думал может collidesWithPath но не смог пока осилить.
Записан
_Vitaliy_
Гость
« Ответ #7 : Февраль 06, 2012, 20:19 »

ответ GreatSnake
Цитировать
Добавь на выбранный элемент размытый контур через QGraphicsItem::setGraphicsEffect( new QGraphicsDropShadowEffect( ... )  ).
Ну и подними его выше всех других через QGraphicsItem::setZValue().
вроде пока не то,
а _OLEGator_
Цитировать
В случае нажатия мышкой в path будет содержаться всего один элемент (path.elementCount() == 1), можно извлечь координаты из пути (path.elementAt(0)), дальше уже самому реализовать проверку на попадание в нужное отклонение от ломанной.
пока не понял как реализовать.
Записан
_OLEGator_
Гость
« Ответ #8 : Февраль 06, 2012, 21:24 »

Ну вы и велосипедист, _Vitaliy_ =)
очень просто ее реализовать, переопределяешь
Код
C++ (Qt)
bool QGraphicsItem::collidesWithPath ( const QPainterPath & path, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape ) const [virtual]

проверяешь
Код
C++ (Qt)
//это проверка на клик будет
if (path.elementCount() == 1)
{
 QPointF pos = path.elementAt(0);
 //дальше определяешь попадает ли в область (элементарная геометрия)
 if ( ... ) return true;
 return false;
}
 
//возвращаешь пересечение со свои путем
return path.intersects( ... );
Соответственно через эту функцию будет и проверка на смену курсора, тебе просто надо будет установить курсор на элемент стандартным способом
Код
C++ (Qt)
void QGraphicsItem::setCursor ( const QCursor & cursor )

Помоему разжевал уже совсем.
Пробуй.

UPD
С запретом перемещения тоже намудрил. Используй
Код
C++ (Qt)
void QGraphicsItem::setTransform ( const QTransform & matrix, bool combine = false )
и
Код
C++ (Qt)
void QGraphicsItem::prepareGeometryChange () [protected]
в случае изменения геометрии для перерисовки, а если тупо двигаешь - то перерисовка вызовется автоматически!
« Последнее редактирование: Февраль 08, 2012, 10:43 от _OLEGator_ » Записан
_Vitaliy_
Гость
« Ответ #9 : Февраль 07, 2012, 23:48 »

Для _OLEGator_
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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