Solved 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; } } }
-
@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
-
@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 layoutQGridLayout::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
-
@ihdvsk
Like this ?
-
yes this looks perfect!
-
@ihdvsk
Is it also allowed to go back (on the row) if START col is bigger than
Ends col ? -
Yes, it should go horizontally first and then vertically just like your pictures show.
-
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;"); } } } }
-
Super, i assume you found bug2 in the y direction ?
Yep. fixed.Good work. Funny app :)
To fully test, you could add a reset function and call from a button
-
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 funvoid 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()); } } }