How to get x and y position from Gridlayout?



  • Hello, i wrote a function to draw a path in a Gridlayout of 20x20 PushButtons from "Start" to "End" but somehow it is not working and causing a crash in my program.

    The Problem is that i need to get the x and y coordinates to set the corresponding PushButton backgroundcolor to black

    here is my function:

    void Widget::setPath(){
    
        int start_x,start_y,end_x,end_y, path_x,path_y;
    
        // finds "Start" and "End" Buttons
        QPushButton *startButton = parentWidget()->findChild<QPushButton *>("Start");
        QPushButton *endButton = parentWidget()->findChild<QPushButton *>("End");
    
        // Gets x and y Value of StartButton in the grid
    
        for(int c = 0;c<20;c++){
            for(int d = 0;d<20;d++){
                if(array[c][d] == startButton){
                    start_x = c;
                    start_y = d;
                }
        // Gets x and y Value of EndButton in the grid
                if(array[c][d] == endButton){
                    end_x = c;
                    end_y = d;
                }
            }
        }
    
        path_x = start_x;
        path_y = start_y;
    
        while(path_x != end_x){
            // if "End" is to right of "Start" next Button to the right of "Start"
            // will be set to Path
            if(path_x < end_x){
                path_x = path_x + 1;
                array[path_x][start_y]->setStyleSheet("background-color:black;");
    
                // if "End" is to left of "Start" next Button to the left of "Start"
                // will be set to Path
            } else if (path_x > end_x){
                path_x = path_x + 1;
                array[path_x][start_y]->setStyleSheet("background-color:black;");
            }
        }
    
        while(path_y != end_y){
            // if "End" is lower than "Start" next Button to under "Start"
            // will be set to Path
            if(path_y < end_y){
                path_y -= 1;
                array[path_x][path_y]->setStyleSheet("background-color:black;");
                // if "End" is higher than "Start" next Button to above "Start"
                // will be set to Path
            } else if (path_x > end_y){
                path_y += 1;
                array[path_x][path_y]->setStyleSheet("background-color:black;");
            }
        }
    
    
    }
    

    i think this is causing the problem (array[c][d] is the array of pushButtons in the gridlayout):

        // Gets x and y Value of StartButton in the grid
    
        for(int c = 0;c<20;c++){
            for(int d = 0;d<20;d++){
                if(array[c][d] == startButton){
                    start_x = c;
                    start_y = d;
                }
        // Gets x and y Value of EndButton in the grid
                if(array[c][d] == endButton){
                    end_x = c;
                    end_y = d;
                }
            }
        }
    

  • Moderators

    @ihdvsk
    sry but this code hurts my eyes and my brain...
    Why so complicated? What is the reason to use a multi-dimensional array? Since you already use a QGridLayout why don't you use it's methods to access the contained widgets?



  • sorry i'm new to Qt and i didnt find a fitting function in the QGridlayout Class.
    How could i then resolve my problem better?



  • @ihdvsk said in How to get x and y position from Gridlayout?:

    causing a crash

    crash = look at/post the stack trace


  • Moderators

    @ihdvsk said in How to get x and y position from Gridlayout?:

    sorry i'm new to Qt and i didnt find a fitting function in the QGridlayout Class.

    since your code doesn't show clearly what you are trying to do IMHO i can't answer this question.

    But i guess your flow is sequential right? Means your "path" can only progress sequentially from start to end?
    Then eiter use the layout QGridLayout::itemAt(int index) method to iterate through the layout items (=widgets) or store the QWidgets independantly in a QList.

    Or is QGridLayout even the correct layout? Maybe a QHBoxLayout is more appropriate?



  • Here is my Code:
    widget.h

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QPushButton>
    #include <QObject>
    #include <QApplication>
    #include <QGridLayout>
    #include <QVBoxLayout>
    
    namespace Ui {
    class Widget;
    }
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    
        int numOfClicks = 0;
        QPushButton* array[20][20];
    
    public:
        explicit Widget(QWidget *parent = 0);
        ~Widget();
    
    public slots:
    
        void setUp(QWidget* w);
    
        /* sets the first clicked Button to "Start"
         and the second clicked Button to "End" */
        void setStartEnd();
    
        void setPath();  // creates the path from "Start" to "End"
    
    
    private:
        Ui::Widget *ui;
    };
    
    #endif // WIDGET_H
    
    

    main.cpp

    #include "widget.h"
    
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        QWidget *w = new QWidget();
        Widget *wid = new Widget();
    
        wid->setUp(w);
    
        return a.exec();
    }
    
    

    and widget.cpp:

    #include "widget.h"
    #include "ui_widget.h"
    
    
    Widget::Widget(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::Widget)
    {
        ui->setupUi(this);
    }
    
    Widget::~Widget()
    {
        delete ui;
    }
    
    
    void Widget::setUp(QWidget* w){
    
        // New GridLayout for Button Array
        QGridLayout *ButtonLayout = new QGridLayout;
    
        // Create 20x20 Buttons in Grid
        for(int i = 0;i<20;i++){
            for(int j = 0;j<20;j++){
    
                QPushButton *pushButton = new QPushButton("");
    
                // Next line will be used to help find the Path later
                array[i][j] = pushButton;
    
                // Adds pushButton to Grid
                w->setLayout(ButtonLayout);
                ButtonLayout->addWidget(pushButton,i,j,1,1);
    
                // Connects buttons to setStartEnd() function
                w->connect(pushButton, SIGNAL(clicked()), this, SLOT(setStartEnd()));
            }
        }
    
        // Set the grid layout as a main layout
        w->setLayout(ButtonLayout);
    
    
        // Display
        w->show();
    
    }
    
    void Widget::setStartEnd(){
    
    
        /* check if it is the first click
           if yes the clicked Button is set to "Start" */
    
    
        if(numOfClicks == 0) {
    
        // New QObject that equals the clicked Button
        QObject* obj = sender();
        QPushButton* button = qobject_cast<QPushButton*>(obj);
    
    
        button->setText("Start");
        button->setStyleSheet("background-color:green;");
        button->setObjectName("Start");
    
        numOfClicks = numOfClicks + 1;
    
        /* else if it is the second click (numOfClicks == 1)
           sets Button to "End" */
    
        } else if(numOfClicks == 1) {
    
            QObject* obj2 = sender();
            QPushButton* button2 = qobject_cast<QPushButton*>(obj2);
    
    
            button2->setText("End");
            button2->setStyleSheet("background-color:red;");
            button2->setObjectName("End");
    
            numOfClicks = numOfClicks + 1;
    
            setPath();
    
        }
    
    }
    
    
    void Widget::setPath(){
    
        int start_x,start_y,end_x,end_y, path_x,path_y;
    
        // finds "Start" and "End" Buttons
        QPushButton *startButton = parentWidget()->findChild<QPushButton *>("Start");
        QPushButton *endButton = parentWidget()->findChild<QPushButton *>("End");
    
        // Gets x and y Value of StartButton in the grid
    
        for(int c = 0; c<20 ; c++){
            for(int d = 0; d<20 ; d++){
                if(array[c][d] == startButton){
                    start_x = c;
                    start_y = d;
                }
        // Gets x and y Value of EndButton in the grid
                if(array[c][d] == endButton){
                    end_x = c;
                    end_y = d;
                }
            }
        }
    
        path_x = start_x;
        path_y = start_y;
    
        while(path_x != end_x){
            // if "End" is to the right of "Start" next Button to the right of "Start"
            // will be set to Path
            if(path_x < end_x){
                path_x = path_x + 1;
                array[path_x][start_y]->setStyleSheet("background-color:black;");
    
                // if "End" is to the left of "Start" next Button to the left of "Start"
                // will be set to Path
            } else if (path_x > end_x){
                path_x = path_x + 1;
                array[path_x][start_y]->setStyleSheet("background-color:black;");
            }
        }
    
        while(path_y != end_y){
            // if "End" is lower than "Start" next Button to under "Start"
            // will be set to Path
            if(path_y < end_y){
                path_y -= 1;
                array[path_x][path_y]->setStyleSheet("background-color:black;");
                // if "End" is higher than "Start" next Button to above "Start"
                // will be set to Path
            } else if (path_x > end_y){
                path_y += 1;
                array[path_x][path_y]->setStyleSheet("background-color:black;");
            }
        }
    
    
    }
    
    

    i have a 20x20 grid of PushButtons. the user can select a start and endpoint. The program then should show a horizontally and then vertically path from start to end. Excuse me if the code is ugly, i tried to comment and indent everything


  • Qt Champions 2017

    @ihdvsk
    Like this ?
    alt text



  • yes this looks perfect!


  • Qt Champions 2017

    @ihdvsk
    Is it also allowed to go back (on the row) if START col is bigger than
    Ends col ?

    alt text



  • Yes, it should go horizontally first and then vertically just like your pictures show.


  • Qt Champions 2017

    Hi
    Is there not a bug here ?

      while(path_x != end_x){
            // if "End" is to the right of "Start" next Button to the right of "Start"
            // will be set to Path
            if(path_x < end_x){
                path_x = path_x + 1;
                array[path_x][start_y]->setStyleSheet("background-color:black;");
    
                // if "End" is to the left of "Start" next Button to the left of "Start"
                // will be set to Path
            } else if (path_x > end_x){
                path_x = path_x + 1;  // should it no go "back" here ? as in -1 
                array[path_x][start_y]->setStyleSheet("background-color:black;");
            }
        }
    


  • I found my mistake. now it works.
    widget.h

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QPushButton>
    #include <QObject>
    #include <QApplication>
    #include <QGridLayout>
    #include <QVBoxLayout>
    #include <QPair>
    #include <QLabel>
    
    
    namespace Ui {
    class Widget;
    }
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    
        int numOfClicks = 0;
        QPushButton* array[20][20];
    
    public:
        explicit Widget(QWidget *parent = 0);
        ~Widget();
    
    public slots:
    
        void setUp(QWidget* w);
    
        /* sets the first clicked Button to "Start"
         and the second clicked Button to "End" */
        void setStartEnd();
    
        void setPath();  // creates the path from "Start" to "End"
    
    
    private:
        Ui::Widget *ui;
    };
    
    #endif // WIDGET_H
    
    

    main.cpp

    #include "widget.h"
    
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        QWidget *w = new QWidget();
        Widget *wid = new Widget();
    
        wid->setUp(w);
    
        return a.exec();
    }
    
    

    and widget.cpp

    #include "widget.h"
    #include "ui_widget.h"
    
    
    Widget::Widget(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::Widget)
    {
        ui->setupUi(this);
    }
    
    Widget::~Widget()
    {
        delete ui;
    }
    
    void Widget::setUp(QWidget* w){
    
        // New GridLayout for Button Array
        QGridLayout *ButtonLayout = new QGridLayout;
    
    
        // Create 20x20 Buttons in Grid
        for(int i = 0;i<20;i++){
            for(int j = 0;j<20;j++){
    
    
                QPushButton *pushButton = new QPushButton("");
    
                // Next line will be used to help find the Path later
                array[i][j] = pushButton;
    
                // Adds pushButton to Grid
                w->setLayout(ButtonLayout);
                ButtonLayout->addWidget(pushButton,i,j,1,1);
    
                // Connects buttons to setStartEnd() function
                w->connect(pushButton, SIGNAL(clicked()), this, SLOT(setStartEnd()));
            }
        }
    
        // Set the grid layout as a main layout
        w->setLayout(ButtonLayout);
    
    
        // Display
        w->show();
    
    }
    
    void Widget::setStartEnd(){
    
    
        /* check if it is the first click
           if yes the clicked Button is set to "Start" */
    
    
        if(numOfClicks == 0) {
    
        // New QObject that equals the clicked Button
        QObject* obj = sender();
        QPushButton* button = qobject_cast<QPushButton*>(obj);
    
    
        button->setText("Start");
        button->setStyleSheet("background-color:green;");
        button->setObjectName("Start");
    
        numOfClicks = numOfClicks + 1;
    
        /* else if it is the second click (numOfClicks == 1)
           sets Button to "End" */
    
        } else if(numOfClicks == 1) {
    
            QObject* obj2 = sender();
            QPushButton* button2 = qobject_cast<QPushButton*>(obj2);
    
    
            button2->setText("End");
            button2->setStyleSheet("background-color:red;");
            button2->setObjectName("End");
    
            numOfClicks = numOfClicks + 1;
    
            setPath();
    
        }
    
    }
    
    
    void Widget::setPath(){
    
        int start_x,start_y,end_x,end_y, path_x,path_y;
    
        // finds "Start" and "End" Buttons
    
        // Gets x and y Value of StartButton in the grid
        for(int c = 0; c<20 ; c++){
            for(int d = 0; d<20 ; d++){
                if(array[c][d]->objectName() == "Start"){
                    start_x = c;
                    start_y = d;
                }
        // Gets x and y Value of EndButton in the grid
                if(array[c][d]->objectName() == "End"){
                    end_x = c;
                    end_y = d;
                }
            }
        }
    
        path_x = start_x;
        path_y = start_y;
    
        while(path_y != end_y){
            // if "End" is to the right of "Start" next Button to the right of "Start"
            // will be set to Path
            if(path_y < end_y){
                path_y += 1;
                if(path_y != end_y || path_x != end_x){
                    array[path_x][path_y]->setStyleSheet("background-color:black;");
                }
                // if "End" is to the left of "Start" next Button to the left of "Start"
                // will be set to Path
            } else if (path_y > end_y){
                path_y -= 1;
                if(path_y != end_y || path_x != end_x){
                    array[path_x][path_y]->setStyleSheet("background-color:black;");
                }
            }
        }
    
        while(path_x != end_x){
            // if "End" is lower than "Start" next Button to under "Start"
            // will be set to Path
            if(path_x < end_x){
                path_x += 1;
                if(path_x != end_x || path_y != end_y){
                    array[path_x][path_y]->setStyleSheet("background-color:black;");
                }
    
                // if "End" is higher than "Start" next Button to above "Start"
                // will be set to Path
            } else if (path_x > end_x){
                path_x -= 1;
                if(path_x != end_x || path_y != end_y){
                    array[path_x][path_y]->setStyleSheet("background-color:black;");
                }
            }
        }
    
    }
    
    

  • Qt Champions 2017

    Super, i assume you found bug2 in the y direction ?
    Yep. fixed.

    Good work. Funny app :)

    alt text

    To fully test, you could add a reset function and call from a button


  • Qt Champions 2017

    Hi
    Note:
    You should set variable to zero or else you cant do it again as it has values (random)

    void Widget::setPath() {
    int start_x=0, start_y=0, end_x=0, end_y=0, path_x=0, path_y=0;
    ...
    }
    also a reset function makes it more fun

    void Widget::Reset() {
        numOfClicks = 0;
        for(int c = 0; c < 20 ; c++) {
            for(int d = 0; d < 20 ; d++) {
                array[c][d]->setStyleSheet(QString());
                array[c][d]->setText(QString());
            }
        }
    }
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.