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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Некорректная отрисовка на краю View  (Прочитано 2055 раз)
Siarshai
Гость
« : Апрель 16, 2013, 12:34 »

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

Код:

Код:
class SimpleItem : public QObject, public QGraphicsItem
{
Q_OBJECT
public:
qreal x, y, rad, a, sinrad, cosrad, direction;
QColor *mycolor;

//Конструктор: присваивает объекту случайный цвет и траекторию
SimpleItem(qreal ax, qreal ay, qreal arad, qreal az): x(ax), y(ay), rad(arad), a(az)
{
mycolor = new QColor( rand()%255, rand()%255, rand()%255);
sinrad = rand()%10;
cosrad = rand()%10;
direction = ((rand()%2)*2 - 1)/((qreal)(rand()%40) + 10);
}
QRectF boundingRect() const
{
qreal penWidth = 1;
return QRectF(x-rad, y-rad, x+rad, y+rad);
}

void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QPen aMicPen(*mycolor, 2);
painter->translate(-rad/2, -rad/2);
painter->setPen(aMicPen);

painter->drawEllipse(x, y, rad, rad);
painter->drawLine(x+rad/2, y+rad/2, x + rad*(0.5+qCos(a)), y + rad*(0.5+qSin(a)));
}
public slots:
//"Кружит" объект по эллиптической траектории вокруг некоторого центра
void vertigo()
{
y += sinrad*sin(a);
x += cosrad*cos(a);
a += direction;
update();
}
};

class QtSandbox : public QMainWindow
{
Q_OBJECT

public:
QtSandbox(QWidget *parent = 0, Qt::WFlags flags = 0): QMainWindow(parent)
{
//Заполнение сцены объектами
QTimer *aqtimer = new QTimer;
aqtimer->start(10);

QGraphicsScene *scene = new QGraphicsScene(this);
SimpleItem *si[100];
for(int i = 0; i < 100; ++i)
{
si[i] = new SimpleItem(150 + rand()%300, 150 + rand()%300, 10 + rand()%11, 1.57);
scene->addItem(si[i]);
connect(aqtimer, SIGNAL(timeout()), si[i], SLOT(vertigo()));
}
QGraphicsView *view = new QGraphicsView(scene, this);
view->setSceneRect(0, 0, 600, 600);
view->setFixedSize(610, 610);
view->show();

//Дальше кнопки и компоновка содержимого в окне
//-------
QWidget *CW1 = new QWidget;
QWidget *CW2 = new QWidget;
setCentralWidget(CW1);
QPushButton *pb1 = new QPushButton("Exit", this);
QPushButton *pb2 = new QPushButton("Renew", this);
QPushButton *pb3 = new QPushButton("DoSomething", this);
connect(pb1, SIGNAL(clicked()), this, SLOT(close()));
//...
QGridLayout *mainLayout = new QGridLayout;
QHBoxLayout *hLay = new QHBoxLayout;
QVBoxLayout *vLay = new QVBoxLayout;

vLay->addWidget(pb1);
vLay->addWidget(pb2);
vLay->addWidget(pb3);
CW2->setLayout(vLay);
hLay->addWidget(view);
hLay->addWidget(CW2);
CW1->setLayout(hLay);
//-------
}
~QtSandbox(){}

private:
Ui::QtSandboxClass ui;
};

Также буду рад принять любые другие советы по коду.
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #1 : Апрель 16, 2013, 13:34 »

1. В boundingRect() не учитывается толщина pen-a (2)
2. Item должен позиционироваться через setPos() и тогда не придётся в boundingRect() указывать абсолютную геометрию и при отрисовке двигать painter.
Записан

Qt 5.11/4.8.7 (X11/Win)
Siarshai
Гость
« Ответ #2 : Апрель 16, 2013, 19:15 »

Спасибо за ответ, я понял, в чём ошибка. Я кстати, забыл учесть и выпирающую палку тоже.

Но вот насчёт setPos() мне не совсем понятно. Эта функция же меняет позицию на некоторую точку в координатах родителя (в данном случае, сцены). Как это может помочь не двигать painter? Ниже исправленный код, но мне кажется, что я неправильно понял, т.к. он не работает.
Кстати, ещё странная вещь. Доки утверждают, что в boundingRect должен возвращаться прямоугольник в своей системе отсчёта, тогда как возвращается в сценовой.

Код:
class SimpleItem : public QObject, public QGraphicsItem
{
Q_OBJECT
public:
qreal x, y, rad, a, sinrad, cosrad, direction;
QColor *mycolor;

//Конструктор: присваивает объекту случайный цвет и траекторию
SimpleItem(qreal ax, qreal ay, qreal arad, qreal az, QGraphicsItem * parent = 0):
x(ax), y(ay), rad(arad), a(az), QGraphicsItem(parent)
{
mycolor = new QColor( rand()%255, rand()%255, rand()%255);
sinrad = rand()%10;
cosrad = rand()%10;
direction = ((rand()%2)*2 - 1)/((qreal)(rand()%40) + 10);
}
QRectF boundingRect() const
{
//return QRectF(x-rad-3, y-rad-3, x+3*rad+3, y+3*rad+3);
return QRectF(-rad-3, -rad-3, 3*rad+3, 3*rad+3);
}

void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QPen aMicPen(*mycolor, 2);
//painter->translate(-rad/2, -rad/2);
painter->setPen(aMicPen);

painter->drawEllipse(x, y, rad, rad);
painter->drawLine(x+rad/2, y+rad/2, x + rad*(0.5+qCos(a)), y + rad*(0.5+qSin(a)));
}
public slots:
//"Кружит" объект по эллиптической траектории вокруг некоторого центра
void vertigo()
{
                        //x += cosrad*cos(a);
                        //y += sinrad*sin(a);
setPos(x+cosrad*cos(a), y+sinrad*sin(a));
a += direction;
update();
}
};
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #3 : Апрель 16, 2013, 20:40 »

Не вижу вызова setPos() в конструкторе.
И после вызова setPos() вызывать update() необязательно.
Аллокировать в куче QColor уж больно избыточно, к тому же QPen является свойством QGraphicsItem.
« Последнее редактирование: Апрель 16, 2013, 20:42 от GreatSnake » Записан

Qt 5.11/4.8.7 (X11/Win)
Siarshai
Гость
« Ответ #4 : Апрель 16, 2013, 21:28 »

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

Однако сцена считает x, y QGraphicsItem'a его верхней левой точкой. Т.е. получается смещать painter для нормальной отрисовки всё-таки нужно?

Аллокировать в куче QColor уж больно избыточно, к тому же QPen является свойством QGraphicsItem.
А как тогда? Хранить RGB в числах?

Последняя правка
Код:
class SimpleItem : public QObject, public QGraphicsItem
{
Q_OBJECT
public:
qreal rad, a, sinrad, cosrad, direction;
QColor *mycolor;

SimpleItem(qreal ax, qreal ay, qreal arad, qreal az, QGraphicsItem * parent = 0): rad(arad), a(az), QGraphicsItem(parent)
{
setPos(ax, ay);
mycolor = new QColor( rand()%255, rand()%255, rand()%255);
sinrad = rand()%10;
cosrad = rand()%10;
direction = ((rand()%2)*2 - 1)/((qreal)(rand()%40) + 10);
}
QRectF boundingRect() const
{
return QRectF(-rad-3, -rad-3, 3*rad+3, 3*rad+3);
}

void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->setPen(*mycolor);
painter->drawEllipse(0, 0, rad, rad);
painter->drawLine(rad/2, rad/2, rad*(0.5+qCos(a)), rad*(0.5+qSin(a)));
}
public slots:
void vertigo()
{
moveBy(cosrad*cos(a), sinrad*sin(a));
a += direction;
}
};
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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