Can field() be requested in a QWizard before initialization? - c++

I am calling a QWizardPage from a function in the MainWindow
void MainWindow::NoiseFilling()
{
QWizard *wiz = new QWizard;
NoiseFillPage *pg = new NoiseFillPage(&data);
wiz->addPage(pg);
wiz->setWindowTitle("Noise Filling");
wiz->setOption(QWizard::NoBackButtonOnStartPage);
QVBoxLayout *ly = new QVBoxLayout;
QLabel *pb = new QLabel;
ly->addWidget(wiz);
ly->addWidget(pb);
connect(wiz,&QDialog::accepted,[&](){data.NoiseFill(wiz->field("percent").toInt(),wiz->field("factor").toString());});
connect(wiz,&QDialog::accepted,[&](){textEdit->setText("Dataset noise filled.\n");});
delete frame->layout(); // delete previous layout
frame->setLayout(ly);
wiz->show();
}
and the constructor of the WizardPage looks like that
NoiseFillPage::NoiseFillPage(DataFrame* df,QWidget* parent)
: QWizardPage(parent)
{
box = new QComboBox;
lab = new QLabel("Metadata factor");
lab_2 = new QLabel("% of missing values threshold to fill");
sb = new QSpinBox;
box->insertItem(0,*(df->className));
box->insertItems(1,*(df->namesMetaData));
sb->setMaximum(100);
sb->setMinimum(30);
sb->setValue(100);
QGridLayout *ly = new QGridLayout;
ly->addWidget(box,0,0);
ly->addWidget(lab,0,1);
ly->addWidget(sb,1,0);
ly->addWidget(lab_2,1,1);
setLayout(ly);
registerField("factor",box);
registerField("percent",sb);
}
I receive a segmentation fault when I accept (and therefore close) the dialog of the one-page wizard. The debugger stops on the connect instruction making me believe that the problem arises because I am requesting two fields which are not initialised in compile-time. It is also true that this connection would be made at run time so I am very confused. Does anybody have an idea of what is going on?

I figured out the problem. I was capturing by reference a local variable (wiz) in the lambda function which caused undefined behaviour even though the variable was still in scope when the lambda executed.

Related

Qt c++ does not call the move_slot for all objects. Why?

int forIterator = 0;
Scenes::Scenes(QWidget * parent): QObject ()
{
setScene(scene);
for(int i = 0; i < Dot::number_of_dotz; i++)
{
QTimer *timer_move = new QTimer();
QObject::connect(timer_move,SIGNAL(timeout()),dotz[i],SLOT(move_slot()));
timer_move->start(10);
}
The Dot::number_of_dots gets updated(+1) in the move_slot() because there is a new dot created but yet the move_slot of the new dot is never called.
Why is this (not) happening?
It seems that you are supposed to create a new Dot in move_slot(). Scenes::Scenes(QWidget * parent) constructor is being called when Dot::number_of_dotz static member has a value more than 0 and probably you already created some dot instances in it. So, the Scene constructor is called once and it would not be called again.
It's obvious that you are doing this because you want to start the expansion of dotz after creation of the Scenes class.
My solution is to check the sender() type in move_slot() and if it's a QTimer, you can create the new QTimer in the move_slot() itself.
I recommend you to set a parent for your QTimer to prevent memory leaks.
void Dot::move_slots(){
// your code
QTimer *caller_object = qobject_cast<QTimer*>(sender());
// caller_object will be nullptr if this slot is not being called
// by an object other than a QTimer
if(caller_object){
QTimer *timer_move = new QTimer(this);
QObject::connect(timer_move,SIGNAL(timeout()),this,SLOT(move_slot()));
timer_move->start(10);
}
}
I hope that I was correct with my assumption about what you wanted to achieve. Leave a comment if it's not the case.

Qt Change ComboBox2 based on ComboBox1

Hi I am fairly new to Qt scene and I'm having trouble updating my comboBox2 based on comboBox1 selection.
Everytime I make a change in comboBox1, my app crashed, saying access violation. It's probably very straightforward but here's my code: In this case, the initial comboBox1 has "Car" and "Food". Whenever I switch to "Food", I want my comboBox2 to populate the item "Egg".
Any idea what went wrong ?
main.h
class main:
{
Q_OBJECT
public:
main() {}
public slots :
private slots:
void onComboBoxIndexChanged();
private:
QComboBox* comboBox2;
void run();
};
main.cpp
void main::run()
{
QWidget *w = new QWidget();
QComboBox *comboBox1 = new QComboBox();
QComboBox *comboBox2 = new QComboBox();
comboBox1->addItem("Car");
comboBox1->addItem("Food");
connect(comboBox1, SIGNAL(currentIndexChanged(int)), this, SLOT(onComboBoxIndexChanged()));
...
}
void main::onComboBoxIndexChanged()
{
QComboBox* combo = dynamic_cast<QComboBox*>(sender());
if (combo == nullptr)
{
return;
}
comboBox2->addItem("Egg");
}
You didn't fix your typo correctly. There's three things I see wrong, and I would've thought the third one would prevent this from compiling.
First, main.h says that your class name is "main", but in main.cpp, your class is WIPGui. Clearly one of those files isn't the right one. I'm going to proceed assuming that your actual main.h file defines the WIPGui class, but otherwise looks the same.
Second, as Mike tried to point out, in your run function, you have this:
QComboBox *comboBox2 = new QComboBox();
That's creating a local variable in your "run" method; it is not assigning to your class member variable comboBox2. What you want is:
comboBox2 = new QComboBox();
Third, your connect statement shouldn't compile based on the code we're seeing:
connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onComboBoxIndexChanged()));
The "comboBox" variable doesn't exist anywhere in this code. If you've actually used "comboBox1" in the connect statement, but this is just another typo in the code you've presented here, then the connect statement is fine. If this is a cut-and-paste as-is, then I don't see how this compiles.
Assuming that you've used "comboBox1" in the connect statement, then the real problem is that you're never assigning to the member variable "comboBox2" and when your slot tries to use it, you get a crash.

qobject_cast<QVBoxLayout*>(layout()), is the appropriate cast?

Considering the layout was set in a QWidget with the following code:
setLayout(new QVBoxLayout);
And then it needs to be retrieved (to add more stuff to the layout). This was done with the following code:
QHBoxLayout *hLayoutTime(new QHBoxLayout);
qobject_cast<QVBoxLayout*>(layout())->addLayout(hLayoutTime);
qobject_cast is the appropriate kind of cast to use here?
To avoid unneded casting write this like this:
void YourWidget::setupContents()
{
QVBoxLayout *vLayout = new QVBoxLayout(this); // effectively this does setLayout(new QVBoxLayout);
QHBoxLayout *hLayoutTime(new QHBoxLayout);
vLayout->addLayout(hLayoutTime);
… … …
}
Looking the code in your current example, Why don't you just get the pointer when creating?
auto *vLayout = new QVBoxLayout;
auto *hLayoutTime = new QHBoxLayout;
vLayout->addlaout(hLayoutTime);
Answering your question, probably the most adequate cast is:
dynamic_cast<QHBoxLayout*>(new QVBoxLayout);
dynamic_cast has several checks and benefits over static_cast, so it is better to use it when possible.

Replace THIS when moving from MainWindow to function

I have moved the following code from the MainWindow constructor to a function within the MainWindow.
void allFilters(QStringList list){
QWidget *w = new QWidget(this);
w->setFixedSize(300,200);
QVBoxLayout *vbox = new QVBoxLayout;
foreach(QString filt, list){
QCheckBox *checkbox = new QCheckBox(filt, this);
checkbox->setChecked(true);
vbox->addWidget(checkbox);
connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(cbstate(int)));
}
w->setLayout(vbox);
w->show();
}
this is now causing me problems. I assume there is an alternative but I'm unaware of what it is?
Hopefully someone can help me!
It looks like allFilters isn't a member function within MainWindow. this is only valid within non-static member functions as it points to the instance of the object.
You'll need to define it like
void MainWindow::allFilters(QStringList list)

SLOT problem / C++

Im trying to figure this error out. I have a simple application made with Qt Creator.
I have three buttons and 2 of them are not enabled. Then when push the first button i want to make them visible, but when i push the button, windows error occures : "program stopped working". the program compiles and does everything else.
QPushButton *dealButton = new QPushButton(tr("Deal cards"));
dealButton->show();
QPushButton *hitButton = new QPushButton(tr("HIT"));
hitButton->show();
hitButton->setEnabled(false);
QPushButton *standButton = new QPushButton(tr("STAND"));
standButton->show();
standButton->setEnabled(false);
...
connect(dealButton, SIGNAL(clicked()), this, SLOT(dealCards()));
...
void MainWindow::dealCards()
{
hitButton->setEnabled(true);
standButton->setEnabled(true);
}
thats the code.
The problem is that you are re-declaring dealButton and the others in your constructor (or whatever function it is that has the new calls you're showing).
You should have in your class definition:
private: // probably
QPushButton *dealButton;
And in your constructor or gui init code:
dealButton = new QPushButton(...); // note: not QPushButton *dealButton = ...
What you have now is creating a new variable called dealButton that is local to that scope (function). That variable is hiding (masking) the class's member.