QT - How to get SIGNAL "currentIndexChanged" from QVector<QComboBox*> - c++

I want to get QString text from selected QComboBox. When I selected an index on a QComboBox, I want to get QString from the selected index, after I clicked the desired index on a QcomboBox.
I have researched about this,
Qt QCombobox currentIndexChanged signal
but have not found a way to solve it,
QVector<QComboBox*> cboxes;
for (int i =0; i< 40 ; i++)
{
QComboBox *box = new QComboBox();
cboxes.append(box);
}
for(int i = 0; i < 40; i++)
{
connect(cboxes[i], SIGNAL(currentIndexChanged(const QString &text)), this, SLOT(comboBoxAdjusted_Changed(QString)));
}
comboBoxAdjusted_Changed function
void DialogSettings::comboBoxAdjusted_Changed(QString text)
{
std::cout << text.toStdString() << endl;
}
I have Try, but everytime i change the combobox index, It isn't give output.
for (int i =0; i< 40 ; i++)
{
connect(cboxes[i], static_cast<void(QComboBox::*)(const QString &)>(&QComboBox::currentIndexChanged),
[=](const QString &text){
std::cout << text.toStdString() << endl;
});
What should I do?

I see signal syntax is missing the function input argument.
Below are two valid signals for currentIndexChanged
void currentIndexChanged(int index)
void currentIndexChanged(const QString &text)
If you have to handle index try below for your case.
for(int i = 0; i < 40; i++)
{
connect(cboxes[i], static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),[=](int index){ /* YOUR CODE */ });
}

Related

Template deduction error binding QComboBox::currentIndexChanged to lambda [duplicate]

I want to get QString text from selected QComboBox. When I selected an index on a QComboBox, I want to get QString from the selected index, after I clicked the desired index on a QcomboBox.
I have researched about this,
Qt QCombobox currentIndexChanged signal
but have not found a way to solve it,
QVector<QComboBox*> cboxes;
for (int i =0; i< 40 ; i++)
{
QComboBox *box = new QComboBox();
cboxes.append(box);
}
for(int i = 0; i < 40; i++)
{
connect(cboxes[i], SIGNAL(currentIndexChanged(const QString &text)), this, SLOT(comboBoxAdjusted_Changed(QString)));
}
comboBoxAdjusted_Changed function
void DialogSettings::comboBoxAdjusted_Changed(QString text)
{
std::cout << text.toStdString() << endl;
}
I have Try, but everytime i change the combobox index, It isn't give output.
for (int i =0; i< 40 ; i++)
{
connect(cboxes[i], static_cast<void(QComboBox::*)(const QString &)>(&QComboBox::currentIndexChanged),
[=](const QString &text){
std::cout << text.toStdString() << endl;
});
What should I do?
I see signal syntax is missing the function input argument.
Below are two valid signals for currentIndexChanged
void currentIndexChanged(int index)
void currentIndexChanged(const QString &text)
If you have to handle index try below for your case.
for(int i = 0; i < 40; i++)
{
connect(cboxes[i], static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),[=](int index){ /* YOUR CODE */ });
}

QT retrieve custom widget from layout

I have a scroll area with a layout that has 8 of the same custom widgets that have been added to it. This custom widget has a getter function that will return a value. My question is how to get back that original custom widget so I can call the getter function to retrieve the data it stores?
I have added the custom widget to the layout this way:
for (int var = 0; var < 9; ++var) {
calcRow *CalcWidget = new calcRow(this, &js, KeyList, SizeList);
connect(CalcWidget, &calcRow::testSignal, this, &MainWindow::getRowData);
ui->scrollArea_layout->layout()->addWidget(CalcWidget);
}
Where I am stuck:
void MainWindow::getRowData()
{
for (int i = 0;i < ui->scrollArea_layout->layout()->count() ;++i ) {
QWidget *row = ui->scrollArea_layout->layout()->itemAt(i)->widget();
if(row != NULL)
{
std::cout << row->"SOMETHING TO GET CALCROW WIDGET" <<std::endl;
}
}
}
Usually it's not the best structure for your code, any layout change might break your implementation. For example this solution will not work if you will have multiple calcRow widgets.
To make it better, you can pass required parameters which you want use inside getRowData as a parameters of testSignal signal.
Or just simplify it even more with lambda:
for (int var = 0; var < 9; ++var) {
calcRow* CalcWidget = new calcRow(this, &js, KeyList, SizeList);
connect(CalcWidget, &calcRow::testSignal, [CalcWidget]()
{
std::cout << CalcWidget->"SOMETHING TO GET CALCROW WIDGET" << std::endl;
});
ui->scrollArea_layout->layout()->addWidget(CalcWidget);
}
For anyone else that will find this in the future, the comments helped a bunch and I ended up using static_cast. My final code looks like this:
void MainWindow::getRowData()
{
for (int i = 0;i < ui->scrollArea_layout->layout()->count() ;++i ) {
QWidget *row = ui->scrollArea_layout->layout()->itemAt(i)->widget();
calcRow *rowConverted = static_cast<calcRow*>(row);
if(row != NULL)
{
std::cout << rowConverted ->getData() <<std::endl;
}
}
}

QTableWidget to multiple files

I’ve got QTableWidget with data like this:
table.png
The table can contains only names from the QList:
QList<QString> shapes { "Triangle", "Circle", "Trapeze", "Square", "Rectangle", "Diamond" };
with random int values in the neighboring cell.
Table can contain all "shapes" or only a part of it (like in the example).
I try to create separate file for each shape form the table and write down corresponding int values to them.
To achieve this I wrote something like that:
QList<QTableWidgetItem *> ItemList
/.../
for(int i = 0; i < rows; ++i)
{
for(int i = 0; i<columns; ++i)
{
foreach(QString itm, shapes )
{
ItemList = ui->tableWidget->findItems(itm, Qt::MatchExactly);
QFile mFile(itm + ".txt");
if(mFile.open(QFile::ReadWrite))
{
for(int i = 0; i < ItemList.count(); ++i)
{
int rowNR = ItemList.at(i)->row();
int columnNR = ItemList.at(i)->column();
out << "Values = " << ui->tableWidget->item(rowNR, columnNR+1)->text() << endl;
}
}
}
mFile.flush();
mFile.close();
}
}
Files are created for every item from the QList – if the shape from the QList is not in the table, an empty file is created.
How to create files only on the basis of available names in the table?
You can write like this.
QList<QTableWidgetItem *> ItemList
/.../
for(QString str : Shapes){
ItemList = ui->tableWidget->findItems(itm, Qt::MatchExactly); // Get the matching list
if(ItemList.isEmpty(){
continue; // If shape does not exist in table skip the iteration
}
QFile mFile(str + ".txt");
if(!mFile.open(QFile::ReadWrite){
return; // This should not happen ; this is error
}
for(QTableWidgetItem *item : ItemList){
int row = item->row();
int col = item->column()+1; // since it is neighboring cell
QString Value = ui->tableWidget->item(row,col)->text();
mFile.write(Value.toUtf8()); // You can change the way in which values are written
}
mFile.flush();
mFile.close();
}

Qt connect statement

I want to enhance my code which works but I fail to do so and my problem is how to pass arguments properly, I mean:
void pracownik2::on_pushButton_4_clicked(){
this->setWindowTitle("EKRAN");
QWidget *centralWidget = new QWidget;
int licznik=1;
QString licz;
//QString kolumny = ui->lineEdit->text();
//QString wiersze = ui->lineEdit_2->text();
miejsca2 = ui->lineEdit_3->text().toInt();
//QPushButton *button[wiersze.toInt()][kolumny.toInt()];
QPushButton *button[3][6];
QGridLayout *controlsLayout = new QGridLayout;
for(int i=0;i<3;i++)
{
for(int j=0;j<6;j++)
{
licz = QString::number(licznik);
licznik++;
button[i][j] = new QPushButton(licz);
button[i][j]->setCheckable(1);
if(tab[i][j]==1)
button[i][j]->setEnabled(false);
controlsLayout->addWidget(button[i][j], i, j);
}
}
QPushButton *okej = new QPushButton("Zatwierdź");
QPushButton *anul = new QPushButton("Anuluj");
controlsLayout->addWidget(okej, 3, 0);
controlsLayout->addWidget(anul, 3, 1);
controlsLayout->setHorizontalSpacing(0);
controlsLayout->setVerticalSpacing(0);
centralWidget->setLayout(controlsLayout);
setCentralWidget(centralWidget);
for(int i=0;i<3;i++)
{
for(int j=0;j<6;j++)
{
connect(button[i][j],SIGNAL(toggled(bool)),this,SLOT(tescik(bool)));
}
}
connect(anul,SIGNAL(clicked()),this,SLOT(close()));
connect(okej,SIGNAL(clicked()),this,SLOT(okay2()));}
void pracownik2::tescik(bool t){
if (t)
{
miejsca++;
}
else
{
miejsca--;
}}
This is working so far and I want 'tescik' function also to set values of my array:
void pracownik2::tescik(bool t, int i, int j){
if (t)
{tab[i][j]=1;
miejsca++;
}
else
{tab[i][j]=0;
miejsca--;
}}
I can't pass 'i' and 'j' indexes of current qpushbutton and I have no idea how to edit my connect line
connect(button[i][j],SIGNAL(toggled(bool)),this,SLOT(tescik(bool,int,int)));
it still has no idea what do I mean by int,int and I still have no idea how to make it work :)
Your problem is because of arguments mismatch when trying to connect signal and slot (signal is emitted with only one boolvalue, when slot takes three) - you should recieve corresponding message in your's application output. One of the solutions is to use QObject-dynamic properties. You can do something like this when creating your buttons:
button[i][j] = new QPushButton(licz);
button[i][j]->setProperty("i", i);
button[i][j]->setProperty("j", j);
And after that you can rewrite your slot:
void pracownik2::tescik(bool t) {
int i = QObject::sender()->property("i").toInt();
int j = QObject::sender()->property("j").toInt();
if (t)
{tab[i][j]=1;
miejsca++;
}
else
{tab[i][j]=0;
miejsca--;
}}

Qt - How to convert from QObject to UI elements?

I am working in Qt 4.7, and I have a QWidget object in my dialog. I need to go through each of the children and extract the current text into a QStringList. Every other object is a QCheckBox, and the rest are QComboBoxes (I would just need the text portion of both). So far the only way I could think of to do this would be to use the children() function to get them as QObject*'s and cast them, like this:
QStringList textlist;
for(int i = 0; i < ui->myWidget->children().size(); i++)
{
if(i % 2 == 0)
{
QCheckBox *q = (QCheckBox *)ui->myWidget->children().at(i);
textlist.append(q->text());
}
else
{
QComboBox *q = (QComboBox *)ui->myWidget->children().at(i);
textlist.append(q->currentText());
}
}
However, when I try to use this, it builds and compiles fine, but then crashes when it's run. I checked and both classes are subclasses (albeit indirectly through QAbstractButton and QWidget) of QObject, which is the type of the objects in the list ui->myWidget->children(), so I feel like they should be able to cast this way. I haven't worked much with this kind of thing before so I'm not sure if there's a better way to do this. If anyone has any ideas, it would be greatly appreciated. Thanks!
UPDATE: So, I can't get the casting to work this way or with the qobject_cast. I HAVE however discovered that I can go from QObject to QWidget, and I think I should be able to go from QWidget to the needed objects with dynamic_cast, but that doesn't work either. Right now I have this:
QStringList textlist;
for(int i = 0; i < ui->myWidget->children().size(); i++)
{
QWidget *qw = qobject_cast<QWidget*>(ui->myWidget->children().at(i)
if(i % 2 == 0)
{
QComboBox *q = dynamic_cast<QComboBox*>(qw);
if(q)
{
textlist.append(q->text());
}
}
else
{
QCheckBox *q = dynamic_cast<QCheckBox*>(qw);
if(q)
{
textlist.append(q->currentText());
}
}
}
If anyone has any ideas, I'd appreciate the help. Thank you.
UPDATE2: I haven't found much online that helps with this still, so I may as well ask as well, if there is anyway to do this WITHOUT casting, i.e. getting the objects directly from the QWidget in their original type, I would really appreciate that as well. I'm not heartset on my current strategy or anything, it was just the only way I could think to do it - I'll take anything that works at this point.
You should think about using qobject_cast. After the cast you should also check if the object is valid.
QStringList textlist;
for(int i = 0; i < ui->myWidget->children().size(); i++)
{
if(i % 2 == 0)
{
QCheckBox *q = qobject_cast<QCheckBox*>(ui->myWidget->children().at(i));
if(q)
textlist.append(q->text());
}
else
{
QComboBox *q = qobject_cast<QComboBox*>(ui->myWidget->children().at(i));
if(q)
textlist.append(q->currentText());
}
}
But this still seems like a bad design to me. The widget class that contains the comboboxes and checkboxes should have a function, that goes through the checkboxes and comboboxes and returns a QStringList. Then you could just call that function.
Here is an example
mywidget.h:
namespace Ui {
class MyWidget;
}
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = 0);
~MyWidget();
QStringList getComboTextList();
QStringList getCheckBoxTextList();
private:
Ui::MyWidget *ui;
QList<QComboBox*> comboList;
QList<QCheckBox*> checkList;
};
 
mywidget.cpp:
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyWidget)
{
ui->setupUi(this);
this->setLayout(new QVBoxLayout);
for(int i = 0; i < 5; i++)
{
QCheckBox *checkBox = new QCheckBox(this);
this->layout()->addWidget(checkBox);
checkBox->setText(QString("Check box #%1").arg(i));
checkList.append(checkBox);
}
for(int i = 0; i < 5; i++)
{
QComboBox *comboBox = new QComboBox(this);
this->layout()->addWidget(comboBox);
comboBox->addItem("Combo box item 1");
comboBox->addItem("Combo box item 2");
comboList.append(comboBox);
}
}
MyWidget::~MyWidget()
{
delete ui;
}
QStringList MyWidget::getComboTextList()
{
QStringList returnList;
for(int i = 0; i < comboList.length(); i++)
{
returnList << comboList[i]->currentText();
}
return returnList;
}
QStringList MyWidget::getCheckBoxTextList()
{
QStringList returnList;
for(int i = 0; i < checkList.length(); i++)
{
returnList << checkList[i]->text();
}
return returnList;
}
Then in your other class you can just call getCheckBoxTextList or getComboTextList like this:
QStringList comboTextList = myWidget->getComboBoxList();
QStringList checkTextList = myWidget->getCheckBoxTextList();