Название: Некорректная отрисовка на краю View
Отправлено: 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; };
Также буду рад принять любые другие советы по коду.
Название: Re: Некорректная отрисовка на краю View
Отправлено: GreatSnake от Апрель 16, 2013, 13:34
1. В boundingRect() не учитывается толщина pen-a (2) 2. Item должен позиционироваться через setPos() и тогда не придётся в boundingRect() указывать абсолютную геометрию и при отрисовке двигать painter.
Название: Re: Некорректная отрисовка на краю View
Отправлено: Siarshai от Апрель 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(); } };
Название: Re: Некорректная отрисовка на краю View
Отправлено: GreatSnake от Апрель 16, 2013, 20:40
Не вижу вызова setPos() в конструкторе. И после вызова setPos() вызывать update() необязательно. Аллокировать в куче QColor уж больно избыточно, к тому же QPen является свойством QGraphicsItem.
Название: Re: Некорректная отрисовка на краю View
Отправлено: Siarshai от Апрель 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; } };
|