Domanda

I am in the process of putting Qlabels in a QGridLayout to arrange them nicely in a class derived from QWidget. However, when I try to access the coordinates, it always returns (0,0)

Here is my code :

class brick : public QWidget
{
Q_OBJECT
public:
    explicit brick(QWidget *parent);
    ...
private:
    QLabel* label;
    QPixmap* brickPic;
}

brick::brick(QWidget *parent) :
QWidget(parent)
{
rect=new QRect();
label=new QLabel;
brickPic=new QPixmap(100,15);
brickPic->fill(QColor(255,0,0));
label->setPixmap(*brickPic);
}

class Grid : public QWidget
{    
QOBJECT
public:
    void fill_grid(QWidget* parent);
    ...
private:
    QGridLayout* grid;
}
void Grid::fill_grid(QWidget* parent)
{
for (int i=0;i<10;i++)
{
    for (int j=0;j<12;j++)
    {
        brick* fillingBrick=new brick(parent);
        grid->addWidget(fillingBrick->getLabel(),j,i);
        qDebug()<<fillingBrick->parentWidget();
        brickVector.push_back(fillingBrick);
    }
}
}

These are to be shown as I said before in the following class derived from QWidget :

class render_area : public QWidget
{
Q_OBJECT
public:
    render_area(QWidget *parent = 0);
    Grid* getGrid() const;
    ...
private:
    Grid* grid;
    QRect* bar;
    ...
}

render_area::render_area(QWidget *parent)
:QWidget(parent)
{
    setFocusPolicy(Qt::StrongFocus);
    setBackgroundRole(QPalette::Base);
    setAutoFillBackground(true);

    bar=new QRect(width()/2,height()+50,150,10);
    grid=new Grid(this);
    grid->fill_grid(this);
    std::cout<<"Grid filled !"<<std::endl;

    qDebug()<<grid->getBrick(5)->pos();
    ...
}

The qDebug()<<fillingBrick->parentWidget() returns render_area which is good but qDebug()<<grid->getBrick(5)->pos() returns QPoint(0,0) which is not.

I wonder how I can get pos() or x() and y() to return the coordinates in render_area inside of which every brick is placed. I tried with cellRect from QGridLayout, MapToParent() inherited from QWidget, forcing render_area to show(); but no luck so far.

Edit : this is the loop I'm talking about :

void render_area::update_timer()
{
int x1,x2,y1,y2;
bar->getCoords(&x1,&y1,&x2,&y2);

if(is_fixed==false)
{
    //gestion du sol
    if(yc+diametre>height())
    {
        timer.stop();
        QDialog* gameOver=new QDialog;
        gameOver->setLayout(new QGridLayout);
        gameOver->layout()->addWidget(new QPushButton("Ok"));
        gameOver->setGeometry(500,500,300,150);
        gameOver->show();
    }

    if(xc>x1 && xc<x1+150)
    {
        if(yc+diametre>y1)
        {
            vyc=-vyc;
        }
    }
    //plafond
    for (int i=0;i<12;i++)
    {
        for(int j=0;j<10;j++)
        {
            grid->getBrick(i,j)->setRect(grid->getGrid()->cellRect(i,j));
        }
    }

    for(int i=0;i<widgets.size();i++)
    {
            if(widgets.at(i)->getRect()->intersects(ballRectangle))
            {
                std::cout<<i<<std::endl;
                widgets.at(i)->getPixmap()->fill(QColor(255,255,255));
                widgets.at(i)->getLabel()->setPixmap(*(widgets.at(i)->getPixmap()));
                delete widgets.at(i);
                vyc=-vyc;
            }
            //qDebug()<<grid->getBrick(i,j)->getRect();
    }
    //bord droit
    if(xc+diametre>width())
    {
            vxc=-vxc;
    }

    //bord gauche
    if(xc<0)
    {
            vxc=-vxc;
    }

    //integration (Euler explicite)
    xc=xc+dt*vxc;
    yc=yc+dt*vyc;

}
repaint();
}
È stato utile?

Soluzione

The widget positions and sizes are determined by the layout, and are calculated in calls from event loop sometime after you call show() on the window widget, and sometime before that window becomes visible.

Since you want to implement a brick breaker game, there are two approaches:

  1. Use the graphics view/scene system.

  2. Use widgets, like you want to do.

Your widget-based approach is excellent to demonstrate that the solution to your problems can be solved naturally by not checking brick positions at all.

You will be updating the ball position in a timer event, or using the animation system. In either case, the ball widget will receive a moveEvent with the new position. There, you can easily calculate the intersections of the ball rectangle with each of the brick widget rectangles. Since they are children of the same parent, they'll be in the same coordinate system. At that time, all the positions will be current. Upon detecting a collision, you reflect the ball's direction, and literally delete the brick widget. You can also start playing a "hit" sound effect.

It's reasonably easy to use the QObject property system to mark different brick widgets depending on their behavioral traits. All this can be done without having to subclass the base widget, which could be a QFrame for example.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top