I want to get the names of my spinboxes in Qt - c++

How can I pull the names of my spinBoxes? I tried looking at a lot of the documentation, however, I couldn't find anything that would show the names of each of the child spinBoxes. I've tried changing the result to a string. However, I just get a Hex or Long Int, of the address I’d imagine, returned instead.
QList<QSpinBox*> spinBoxes= findChildren<QSpinBox*>();
//create the QSignalMapper object
QSignalMapper* signalMapper= new QSignalMapper(this);
//loop through your spinboxes list
QSpinBox* spinBox;
foreach(spinBox, spinBoxes){
//setup mapping for each spin box
connect(spinBox, SIGNAL(valueChanged(int)), signalMapper, SLOT(map()));
signalMapper->setMapping(spinBox, spinBox);
}
//connect the unified mapped(QWidget*) signal to your spinboxWrite slot
connect(signalMapper, SIGNAL(mapped(QWidget*)), this, SLOT(spinboxWrite(QWidget*)));
.
.
.
void GuiTest::SpinBoxChanged(QWidget* wSp){
QSpinBox* sp= (QSpinBox*)wSp; //now sp is a pointer to the QSpinBox that emitted the valueChanged signal
int value = sp->value(); //and value is its value after the change
//do whatever you want to do with them here. . .
qDebug() << value << "SpinBoxChanged";
}
void GuiTest::spinboxWrite(QWidget* e){
SpinBoxChanged(e);
QString* value = (QString*)e;
qDebug() << e << value << " SpinBoxWrite";
}
Please note qDebug() << e as this is where I'm having trouble getting some information about the spinboxes

The name you are trying to retrieve is the objectName property, which every QObject and QObject-derived class has. Call objectName() to retrieve this value.
You can also use this with the QObject::findChild() function.
This should get what you want:
void GuiTest::spinboxWrite(QWidget* e){
SpinBoxChanged(e);
qDebug() << e->objectName() << " SpinBoxWrite";
And will output:
"norm_spinBox_10" SpinBoxWrite
Note
This line is dangerous:
QSpinBox* sp= (QSpinBox*)wSp;
Use qobject_cast instead of C-style casts.

There is no direct way to get the name of a variable as a string.
However, you can use a QMap<QSpinBox*, QString> to map each spin-box to its name.
In the constructor you have to assign these manually:
map[ui->spinBox] = "spinBox";
map[ui->spinBoxWithStrangeName] = "spinBoxWithStrangeName";
Then you can simply get the strings using:
QString name = map[ui->spinBox];

Just give them names in the designer file and then use that name to retrieve them in the C++ code.
QSpinBox* mySpinner = findChild<QSpinBox*>("myGivenName");

Related

Problems creating a slot for putting some text into QTextEdit

I've done quite a thorough research as I've been struggling with a slot issue, but as the Google search results steadily grew more and more purple, I decided just to ask the SO pals =) Please mind that I am not using QtCreator nor any dynamic stuff. I need to:
declare some QStrings which are constant
get some QStrings out of QLineEdits
add 1 and 2
finally, put them into QTextEdit when a button is clicked.
For the step 1, I declare QStrings like this:
QString set_1 = "ООО «Хеллманн» (129343, г. Москва, ул. Уржумская, д. 4, стр. 14, ИНН 7722637955, ОГРН 1087746168476) доверяет забор груза - ";
QString set_2 = " - перегружаемого из контейнера ";
QString set_3 = ", в количестве ";
QString set_4 = " паллет, весом ";
QString set_5 = " кг, водителю ";
QString set_6 = ", паспорт ";
QString set_7 = " выдан ";
QString set_8 = ".";
QString set_9 = " На автотранспортном средстве марки ";
QString set_10 = " - ";
QString set_11 = ", прицеп: ";
Then, for the step 2, I make QStrings out of QLineEdits like this (e.g. line_b_b is the name of a QLineEdit):
QString a = line_b_b.text();
QString b = line_b_a.text();
QString c = line_b_c.text();
QString d = line_b_d.text();
QString e = line_a_b.text();
QString f = line_a_a.text();
QString g = line_a_c.text();
QString h = line_a_d.text();
QString i = line_c_b.text();
QString j = line_c_a.text();
QString k = line_c_c.text();
For the step 3, I add the QStrings from the step 1 with those from the step 2 into a variable named "doverka" (please don't mind this cyrillic stuff):
QString doverka = set_1+a+set_2+b+set_3+c+set_4+d+set_5+e+set_6+f+set_7+g+h+set_8+set_9+i+set_10+j+set_11+k+set_8;
Finally, in the step 4, I try to put the whole into QTextEdit when a button is pushed. And I guess the problem is here. I create a QTextEdit named "text":
QTextEdit text (&dw);
text.show();
And then I try to create a slot and I presume I am doing this in a totally wrong way as it simply doesn't work:
QPushButton btn_t ("Создать текст", &dw);
QObject::connect(
&btn_t,
SIGNAL(clicked()),
&text,
SLOT([dover](){return text.setText(doverka)}));
btn_t.show();
I am new to Qt as well as to C++ and that's why poor at slot creation. Here I've tried this with a lambda function but I am obviously doing something wrong. Maybe I should just put the lambda function somewhere else before SLOT? My slot is not recognized as such when the prog is being compiled, I get the "no such slot" notification. Or maybe the problem is somewhere earlier, e.g. in making QStrings out of QLineEdits (step2)?.. I'm pretty helpless and appreciate any useful tips greatly! Very many thanks.
You are trying to mix old style Qt signal/slot connection with new style which obviously does not work. lambdas can be used only with new style of connections. If you are using Qt 5 the connection could be like:
QObject::connect(
&btn_t,
&QPushButton::clicked,
[&text, &doverka](){
text.setText(doverka);
});
You should be careful that text and doverka objects should not be destroyed before the lambda is invoked, as they are captured by reference.
In case of using Qt 4.* you should use the old syntax. In your case just provide a slot in your class and connect the signal it:
QObject::connect(
&btn_t,
SIGNAL(clicked()),
this,
SLOT(onClicked()));
Your class should inherit from QObject containing a slot like:
public slots:
void onClicked() {
text.setText(doverka);
}
Also note that text and doverka should be members of the class.

QListWidget::itemChanged signal triggered twice in qt

I have a QListWidget to store usernames, and I use this signal to detect if username is being changed:
connect(listWidget, &QListWidget::itemChanged, this, &MainWindow::changeUserName);
void MainWindow::changeUserName(QListWidgetItem *editItem)
{
qDebug() << "Name:" << editItem->text();
}
And this is how I make QListWidget editable in another function:
connect(listWidget, &QListWidget::itemDoubleClicked, this, &MainWindow::makeListEditable);
void MainWindow::makeListEditable()
{
QListWidgetItem *editItem = listWidget->currentItem();
editItem->setFlags(editItem->flags() | Qt::ItemIsEditable);
qDebug() << "Name edit";
}
But which confused me is, whenever I double clicked the list widget, the itemChanged signal will be triggered once, and when I input a new username, the signal will be triggered again. Why would this happen?
This is the debug output, when I double clicked the list, it says:
Name: "Testing name_1"
Name edit
after I entered a new name and hit the enter, it says:
Name: "Testing name_2" //a new name I changed to
And what if I only want a signal be triggered once whenever I input a new name and hit the enter, what should I do to achieve this?
Thanks
You can use the item delegate commitData signal, this way:
QObject::connect(listWidget->itemDelegate(), SIGNAL(commitData(QWidget*)), this, SLOT(dataCommited(QWidget*)));
the slot is like this:
void dataCommited(QWidget * w)
{
QString data = (static_cast<QLineEdit *>(w))->text();
//...
}
The signal will be emitted at the end of the editing (i.e. enter key pressed or focus lost etc.)
As #Rafalon said, calling setFlags calls your slot changeUserName, and the signal currentTextChanged is emitted when the current item changed, it is the same as currentItemChanged except it gives you the text instead of the item.
What you can do is, make your item editable as you instantiate it:
QListWidgetItem* pItem = new QListWidgetItem();
pItem->setText("Testing name_1");
pItem->setFlags(pItem->flags() | Qt::ItemIsEditable);
listWidget->addItem(pItem);
or you can activate/deactivate the connection when you need it:
void MainWindow::makeListEditable(QListWidgetItem *editItem)
{
editItem->setFlags(editItem->flags() | Qt::ItemIsEditable);
connect(ui->listWidget, SIGNAL(itemChanged(QListWidgetItem *)), this, SLOT(changeUserName(QListWidgetItem *)));
qDebug() << "Name edit";
}
void MainWindow::changeUserName(QListWidgetItem *editItem)
{
qDebug() << "Name:" << editItem->text();
disconnect(ui->listWidget, SIGNAL(itemChanged(QListWidgetItem *)), this, SLOT(changeUserName(QListWidgetItem *)));
}
but you will have to make another connection when the current element is not modified after a double click, maybe with the signal currentItemChanged.

QT how to emit a signal in this case

I need to develop a Sudoku game. After reading a text file containing the number values, I create 9*9 widgets.
If (the value is already set then I instantiate to a qlabel containing the number,
else I instantiate a combobox containing the possible values of each case).
Until here everything is OK.
The problem is that when a value is chosen from the combobox, I need to draw it in a square in my view (MVC). The problem is how can I know which one was chosen?
The only signal can I use from combobox signals is currenttextchanged(QString), but I'll not know which combo made that signal.
The ideal for me would be something like this SIGNAL(curretextchanged(QString, int, int)), but I don't know if I can define a new signal?
Here is some code:
QWidget *tab[9][9];
SudModel *modele = ???;
QComboBox *combobox = new QComboBox();
combobox->setStyleSheet("border: 1px solid red");
int tmp = modele->valuesof(i, j).size();
for (int s = 0; s < tmp; s++) {
combobox->addItem(QString::number(modele->valuesof(i, j)[s]));
}
connect(combobox, SIGNAL(currentTextChanged(QString)), this, SLOT(update()));
tab[i][j] = combobox;
One solution would be to attach that extra information when you connect to the signal for a specific combobox.
For example, say you have your function update(QString text, int x, int y) then you could attach the signal to a lambda that calls the function with the extra arguments, captured at connect time. Something like this:
connect(combobox, &QComboBox::currentTextChanged, [x, y, this](const QString& text){ this->update(text, x, y); });
That would then call the update functions with the x and y values captured when the connection was made along with the text argument that originated from the signal.
You can ask the slot for a sender()
QObject *QObject::sender() const
Returns a pointer to the object that sent the signal, if called in a
slot activated by a signal; otherwise it returns 0. The pointer is
valid only during the execution of the slot that calls this
function from this object's thread context.
You can use QSignalMapper.
In this you map every item with mapper with any specific string. Now when any mapped item emits signal you can know which item emitted it by the string.
You can use the same with minor changes like using Signal 'currentTextChanged' as mentioned. But the same result can be obtained by using 'currentIndexChanged' signal with some modifications.
signalMapper = new QSignalMapper(this);
for (int i = 0; i < 2; ++i) {
QComboBox *combo = new QComboBox();
connect(combo, SIGNAL(currentIndexChanged()), signalMapper, SLOT(map()));
signalMapper->setMapping(combo, "combo" + i);
}
connect(signalMapper, SIGNAL(mapped(QString)),
this, SIGNAL(indexChanged(QString)));
NOTE : (source Qt Assistant)
QSignalMapper class collects a set of parameterless signals, and
re-emits them with integer, string or widget parameters corresponding
to the object that sent the signal

Qt c++ Increasing integer with pushButton to label

I'm trying to make a simple "Cookie Clicker" game and I'm having trouble with this. When I press the button I want the label to print out "You have mined (VALUE) FSCoins" but the label won't update for some reason. Console shows no errors :(
Here's my code:
mainwindow.cpp
void MainWindow::on_pushButton_clicked(int num, int numplus)
{
num = numplus + 1;
QString qstr = QString::number(numplus);
ui->label->setText("You have mined " + qstr + " FSCoins");
}
Any help would be appreciated, I've only started working with Qt yesterday and I'm "Sort of" getting the hang of it.
num = numplus + 1;
What is the point of this line? num is a local variable that is never used. Did you mean to pass it by reference?
You need to connect a SIGNAL to a SLOT, but that function you wrote there does not seem like a SLOT. Somewhere in your code there shall be something like this in your header file:
class ...
{
// ...
private slots:
void onPushButtonClicked();
};
and in your source file:
// For example in the constructor.
connect( ui->PushButton, SIGNAL( clicked() ), this, SLOT( onPushButtonClicked() ) );
// The implementation of your SLOT.
Class::onPushButtonClicked()
{
// Your implementation.
updateLabel( /* Your arguments */ );
}
The SLOT function cannot have more arguments than the SIGNAL, so in this case your SLOT cannot have any.
And something else. I prefer this version of creating a QString:
QString( "You have mined %1 coins" ).arg( value );
I think it's more readable.
So the point is that that you need store that integers somewhere. Maybe in your class as a member variable.

Qt pass additional argument to slot AND keep emitted signal data

I have searched the web on this issue and I've repeatedly got answers referring to the use of QSignalMapper. But my problem is pretty clear, QSignalMapper automatically gets rid of whatever is originally emitted and replaces it with basically nothing, plus the new data that is set via setMapping().
The problem here is simple.
I have a QNetworkAccessManager that parses html and updates a vector containing text data:
void DataManager::startHttpRequest(QString url, int index)
{
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
//QSignalMapper* signalMapper = new QSignalMapper(this);
//connect(manager,SIGNAL(finished(QNetworkReply*)), signalMapper,SLOT(map()));
//signalMapper->setMapping(manager, index);
//connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(insertUpdate(int)));
connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(finishHttpRequest(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl(url)));
qDebug() << index;
}
and here is what happens when the request is finished, the normal way:
void DataManager::finishHttpRequest(QNetworkReply *reply)
{
QString html = QString(reply->readAll()).simplified();
QString info;
int start = html.indexOf("<span id=\"SalePrice\" >");
if(start != -1)
{
QString price = html.mid(start + 23, 30);
int end = price.indexOf("</span>");
info = price.mid(0, end - 1);
qWarning() << price.mid(0, end - 1);
}
else
{
info = "NA";
}
// Do more stuff
}
Using the normal way of signals and slots, I would not be able to know the index of the vector I am updating,
Or,
If I am using QSignalMapper, I know the index, but not the data that comes with it.
How do I get BOTH working (index + data)?
(something like mySlot(QNetworkReply *reply, int *index), but we all know that won't work)
Many thanks in advance.
While it's probably not the best,
sender()->setObjectName(const QString & name) allows the sender to name itself.
The sender's name can be accessed from the receiving slot via sender()->ObjectName()
As documented on http://qt-project.org/doc/qt-5/qobject.html#objectName-prop.