Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: pashazz от Апрель 14, 2009, 10:20



Название: Перерисовка QGraphicsItem
Отправлено: pashazz от Апрель 14, 2009, 10:20
Задача такая: залить цветом уже нарисованный QGraphicsItem
Речь идет о интерпретаторе QBasic. https://github.com/pashazz/qtqbasic/tree
Переопределение QGraphicsItem не рассматриваю - фигур много. Если это не единственный вариант
Вот что у меня получилось:
Код
C++ (Qt)
void runWindow::paintEvent(QPaintEvent *e) {
   if (it != 0  && colornum != -1) {
QPainter *p = new QPainter (this);
p->setBrush(QBrush (num2col(colornum)));
it->paint(p, new QStyleOptionGraphicsItem(), this);
it = 0;
   }
}
 

it добывается с помощью ItemAt по координатам x,y. Определяется правильно.
colornum тоже правильно - номер цвета.
Но рисовать не хочет.
Вывод: QPaintEngine::setSystemRect: Should not be changed while engine is active
QPaintEngine::setSystemRect: Should not be changed while engine is active
QPaintEngine::setSystemRect: Should not be changed while engine is active

Подскажите, как сделать правильно. Спасибо.


Название: Re: Перерисовка QGraphicsItem
Отправлено: pastor от Апрель 14, 2009, 10:36
Попробуй так:

Код
C++ (Qt)
void runWindow::paintEvent(QPaintEvent *e) {
   if (it != 0  && colornum != -1) {
       QPainter p (this);
       p.setBrush(QBrush (num2col(colornum)));
       it->paint(&p, new QStyleOptionGraphicsItem(), this);
       it = 0;
   }
}


Название: Re: Перерисовка QGraphicsItem
Отправлено: pashazz от Апрель 14, 2009, 10:42
Предупреждения пропали, но цвет не меняется там, где должен. Все так и остается.


Название: Re: Перерисовка QGraphicsItem
Отправлено: pashazz от Апрель 14, 2009, 16:35
Неужели придется наследовать?


Название: Re: Перерисовка QGraphicsItem
Отправлено: Rcus от Апрель 14, 2009, 16:58
А в чем проблема в наследовании? Наследовать свои классы от QAbstractShapeItem и рисовать в paint'е при помощи установленных pen()/brush()


Название: Re: Перерисовка QGraphicsItem
Отправлено: pashazz от Апрель 14, 2009, 18:00
Проблема в том, что нужно подставлять координаты в drawEllipse допустим. А откуда их брать?


Название: Re: Перерисовка QGraphicsItem
Отправлено: pashazz от Апрель 14, 2009, 18:00
Точнее смысл не в этом. Я не очень понимаю, как это будет выглядеть.


Название: Re: Перерисовка QGraphicsItem
Отправлено: BaltikS от Апрель 14, 2009, 19:58
pashazz, поставьте конкретнее задачу. Я уверен, что всё можно решить наследованием, главное понять логику того, чего вам в итоге нужно!


Название: Re: Перерисовка QGraphicsItem
Отправлено: pashazz от Апрель 14, 2009, 21:03
Задача: реализовать QBasic-овский оператор PAINT
там дается точка на плоскости и цвет, которым нужно заполнить фигуру, на которой находится эта точка.
Допустим
PAINT (56,23),7
Найти объект, на котором лежит точка 56,23 и закрасить его цветом 7.
Объекты могут быть: круг, полигон (прямоугольник).
Так понятнее?


Название: Re: Перерисовка QGraphicsItem
Отправлено: pashazz от Апрель 14, 2009, 21:07
Вот один из вариантов.
Код
C++ (Qt)
//.h
#ifndef MYSCENE_H
#define MYSCENE_H
 
#include <QGraphicsScene>
#include <QPainter>
#include <QtGui>
class myscene : public QGraphicsScene
{
public:
   myscene();
   QColor color; //номер цвета
protected:
   virtual void  drawItems (QPainter *painter, int numItems,
                            QGraphicsItem *items[],
                            const QStyleOptionGraphicsItem options[],
                            QWidget *widget);
 
#endif // MYSCENE_H
 
 
//.cpp
 
#include "myscene.h"
 
void myscene::drawItems(QPainter *painter, int numItems,QGraphicsItem *items[], const QStyleOptionGraphicsItem options[], QWidget *widget) {
 
     for (int i = 0; i < numItems; ++i) {
         // Draw the item
         painter->save();
         painter->setMatrix(items[i]->sceneMatrix(), true);
         painter->setBrush(QBrush (color));
         items[i]->paint(painter, &options[i], widget);
         painter->restore();
     }
 }
 
 

Вываливается с ошибками компиляции
make: Entering directory `/home/pasha/work/QtQBasic'
/usr/bin/make -f Makefile.Debug
make[1]: Entering directory `/home/pasha/work/QtQBasic'
g++ -c -m64 -pipe -g -Wall -W -D_REENTRANT -DQT_OPENGL_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/opt/qtsdk-2009.01/qt/mkspecs/linux-g++-64 -I. -I/opt/qtsdk-2009.01/qt/include/QtCore -I/opt/qtsdk-2009.01/qt/include/QtGui -I/opt/qtsdk-2009.01/qt/include/QtOpenGL -I/opt/qtsdk-2009.01/qt/include -I/usr/X11R6/include -Idebug -I. -o debug/myscene.o myscene.cpp
myscene.cpp:3: ошибка: избыточная квалификация ‘myscene::’ элемента ‘drawItems’
myscene.cpp:3: ошибка: ‘void myscene::drawItems(QPainter*, int, QGraphicsItem**, const QStyleOptionGraphicsItem*, QWidget*)’ cannot be overloaded
myscene.h:16: ошибка: with ‘virtual void myscene::drawItems(QPainter*, int, QGraphicsItem**, const QStyleOptionGraphicsItem*, QWidget*)’
myscene.cpp:13: ошибка: expected `}' at end of input
myscene.cpp:13: ошибка: expected unqualified-id at end of input
make[1]: *** [debug/myscene.o] Ошибка 1
make[1]: Leaving directory `/home/pasha/work/QtQBasic'
make: *** [debug] Ошибка 2
make: Leaving directory `/home/pasha/work/QtQBasic'
Exited with code 2.
Error while building project QtQBasic
When executing build step 'Make'


Название: Re: Перерисовка QGraphicsItem
Отправлено: pashazz от Апрель 14, 2009, 21:09
В общем я совсем запутался.
Подскажите другое решение.
и да: http://github.com/pashazz/qtqbasic/tree


Название: Re: Перерисовка QGraphicsItem
Отправлено: BaltikS от Апрель 15, 2009, 07:00
Могу тебе подсказать алгоритм решения твоей задачи....
1) оставить сцену в покое(не нужно от неё наследоваться);
2) унаследуйся от QGraphicsItem и добавь в нём переменные для хранения варианта (круг, полигон) и цвета.
Например h-файл может выглядеть так:
Код:
class MyItem : public QGraphicsItem
{
public:
             enum TypeObject {Circle, Rectangle, Polygon);                 // типы наших объектов

MyItem( QGraphicsItem * parent);

             void setColor(int);               // передаём цвет

int type() const { return UserType+1; } // не забываем энту строчку!!!

protected:
     // переопредляем методы
     virtual QRectF boundingRect () const; // размер прямоугольной области
     virtual void paint ( QPainter * painter,
const QStyleOptionGraphicsItem * option, QWidget * widget = 0 );// отрисовка нашего объекта
     virtual QPainterPath shape () const ; // область фокуса

private:
     TypeObject _type;   // тип нашего объекта
     int _color;    // цвет нашего объекта
3) переопредели методы boundingRect(), shape() и paint();
4) добавляем на сцену нужное количество твоих элементов (например в цикле случайным образом);
5) напиши в главной форме свою функцию paint.
Например:
Код:
void paint(const QPoint point, int color)
{
   ...
   QList<QGraphicsItem *> list = scene->items(point);
   for (int i = 0; i < list.size(); ++i)
       qgraphicsitem_cast<MyItem *>(list.at(i))->setColor(color);
5) определи на форме событие, по которому будет вызываться твоя фунция paint...


Название: Re: Перерисовка QGraphicsItem
Отправлено: xokc от Апрель 15, 2009, 07:57
Я бы наследовался дважды - базовый класс с цветом и уже от него классы для круга и прямоугольника с перепоределенным paint.


Название: Re: Перерисовка QGraphicsItem
Отправлено: Rcus от Апрель 15, 2009, 08:20
Круто, вы только что заново изобрели QGraphicsAbstractShapeItem, QGraphicsEllipseItem, QGraphicsRectItem и QGraphicsPolygonItem. oh wait...


Название: Re: Перерисовка QGraphicsItem
Отправлено: BaltikS от Апрель 15, 2009, 09:50
Ну да, правильно было бы от QGraphicsAbstractShapeItem наследоваться....

Хотя можно вообще не городить огород, а взять и преобразовать к типу, указанному выше, и, задавать его цвет...


Название: Re: Перерисовка QGraphicsItem
Отправлено: pashazz от Апрель 15, 2009, 21:42
А setColor как реализовать? Я не совсем понимаю. Там в paintEvent надо вызывать MyItem::paint, или как?


Название: Re: Перерисовка QGraphicsItem
Отправлено: lit-uriy от Апрель 15, 2009, 22:15
неработал с грфикой, но по асистенту вроде так:
painter->pen()->setColor ( ...)


(в функции MyItem::paint)


Название: Re: Перерисовка QGraphicsItem
Отправлено: pashazz от Апрель 15, 2009, 22:38
В общем т.к. я плохо понимаю здесь
у меня акк на what.cd есть, стукните в Jabber, помогите с реализацией, а то у меня тупик.
Получите акк, если поможете.
(это ко всем)


Название: Re: Перерисовка QGraphicsItem
Отправлено: pashazz от Апрель 15, 2009, 22:39
Jabber: pashazz@j.kvx.ru


Название: Re: Перерисовка QGraphicsItem
Отправлено: kamre от Апрель 16, 2009, 05:03
дается точка на плоскости и цвет, которым нужно заполнить фигуру, на которой находится эта точка.
Допустим
PAINT (56,23),7
Найти объект, на котором лежит точка 56,23 и закрасить его цветом 7.
Объекты могут быть: круг, полигон (прямоугольник).
Так понятнее?

Понятнее. Тогда запрашиваем у сцены item, в который попала точка, через метод QGraphicsScene::itemAt. Пытаемся через dynamic_cast привести к указателю на QAbstractGraphicsShapeItem. Если приводится, то вызываем метод QAbstractGraphicsShapeItem::setBrush. Там автоматически вызовется метод update для item и он перерисуется, если виден.


Название: Re: Перерисовка QGraphicsItem
Отправлено: pashazz от Апрель 16, 2009, 09:14
Спасибо, помогло!
Тогда следующий вопрос.
Мне известны координаты центра круга, и его радиуса.
А в QGraphicsScene::addEllipse нужно подставить координаты прямоугольника, в котором рисуется эллипс
Как мне их вычислить?


Название: Re: Перерисовка QGraphicsItem
Отправлено: BaltikS от Апрель 16, 2009, 10:51
pashazz, извините конечно, ну видимо 10 класс геометрии прошёл мимо вас.
Код:
QPoint center = ...;    // координата центра круга
qreal radius = ... ;      // радиус круга
painter->drawEllipse(QRectF(center.x()-radius, center.y()-radius, 2*radius, 2*radius));
Наверное так....


Название: Re: Перерисовка QGraphicsItem
Отправлено: pashazz от Апрель 16, 2009, 11:42
Спасибо, я так и думал
Оказывается в последних 2-х агрументах подставляется диаметр, не радиус, в этом была моя ошибка


Название: Re: Перерисовка QGraphicsItem
Отправлено: Racheengel от Май 26, 2009, 17:32
А вот интересно, что будет делаться, если допустим нарисовали 2 круга одного цвета так, что они немного соприкасаются... А потом выполнили заливку по координате, попадающей только в один - второй так и останется белым, правда?