QComboBox: the addItem function trigger index change signal - qt

I am using QComboBox in my project. And I find that the addItem function would trigger currentIndexChanged signal.
The minimum code to reproduce this problem is:
class Test: public QWidget
{
public:
QComboBox * m_box;
Test()
{
m_box = new QComboBox;
connect(m_box, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &Test::IndexChangeSlot);
m_box->addItem("test");
}
public slots:
void IndexChangeSlot(int index)
{
std::cout<<"index changed"<<std::endl;
}
}
Why addItem would trigger currentIndexChanged signal?
How can I avoid this signal caused by addItem?

CurrentIndex was -1 (nothing is selected) and become 0.
To avoid disconnect before adding items and connect back, or use variable to ignore signal temporary, or connect after initialisation.

Related

If I call a setValue() or similar function of a Qt widget, when is its valueChanged() slot guaranteed to be executed?

Let's say I have multiple input widgets to set up the same parameter. For example, there is a QSlider and a QSpinBox which need to show the same value. In the valueChanged() slot of one of them I call the setValue() of the other one.
Obviously, this would result in an endless loop of them calling each other.
A similar problem arises when this input widget controls some external resource or device. If the user changes the value, it will send the new value to the external device. But if the external device changes the value (or it is read from a settings file, etc) then I have to update the widget, which in turn will send the value, which in turn will update the widget, and so on.
A third scenario is when I save the values into a file or database, but I have to initialize the widgets to some value at the beginning, possibly before I got all the values from the database. But by initializing the widgets at the beginning of my program, they will write that dummy value into the database, overwriting the real values.
The obvious solution for these problems is to just have a bool which allows or forbids the side effects of the valueChanged() functions.
For example, if I want to change the value of my slider, I use
editing = true;
slider.setValue(value);
editing = false;
While I have if (editing) return; at the beginning of my valueChanged() function.
Assuming I didn't fiddle with setting up the signals and slots manually, but they were done by QtCreator, is there a danger of the slot being called later, for example after the editing flag is set to false again? I tried it, and it works, but I am unsure how guaranteed it is.
If you use direct connection (the default for objects in the same thread), the slot is called as soon as the signal is emitted, that is before the setValue method returns.
If you use Qt::QueuedConnection, the slot is invoked when control returns to the event loop of the receiver's thread.
See Qt::ConnectionType
The way I would go about solving this problem is by having another QObject that will be your data model. Your data will be centralized in your model, and will gotten/set via the model. This way your widgets wouldn't need to know about one another and can be created in separate places in your code as long as they can access your model.
Your model will have a method setValue and a signal valueChanged, so it will look some thing like this:
class Model : public QObject {
Q_OBJECT
public:
void setValue(const QVariant& value) {
if (_value != value) {
_value = value;
emit valueChanged(_value);
}
}
const QVariant& getValue() const {
return _value;
}
public signals:
void valueChanged(QVariant& value);
private:
QVariant _value;
}
Then your widgets can take the same instance of Model as a dependency and listen to its valueChanged signal and update themselves. The widgets will also listen to user input, and when the user changes the value then they will change the value in the model. That way the other widgets will get notified about the change.
Your widgets will look like this:
class MySlider : public QSlider {
Q_OBJECT
public:
explicit MySlider(QSharedPointer<Model> model, QWidget *parent=nullptr)
: QSlider(parent), _model(model) {
connect(this, &QSlider::valueChanged, this, [this](int value){
_model->setValue(value);
});
connect(_model.data(), &Model::valueChanged, this, &MySlider::onValueChanged);
//this is to update the widget with the latest value upon creation
onValueChanged(_model->getValue());
}
private slots:
void onValueChanged(const QVariant& value) {
if (value.toInt() != value()) {
//this is calling QSlider::setValue
setValue(value.toInt());
}
}
}
Before you create all your widgets you can create your model with the default value, so let's assume it's in main:
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWindow w;
w.show();
//note that your model doesn't have a parent, it's a shared pointer
auto model = QSharedPointer<Model>::create();
auto mySlider1 = new MySlider(model, &w);
auto mySlider2 = new MySlider(model, &w);
return a.exec();
}
P.S. You can also look into QDataWidgetMapper and see if it can accomplish what you're looking for.

how to trigger a signal in Qt

I've got an easy GUI window: a QLineEdit with a QPushButton. I want to trigger a signal when when the push button is clicked AND the input is validated (it meets a conditional statement, nevermind the details).
Normally I would use connect (object, signal, subject, slot). I guess that QPushButton clicked should trigger the middle-signal which is handled inside the widget slot. And the widget slot could trigger another signal - to my destination point. But how?
You have to declare your signal in class:
class myClass
{
/* stuff */
public signals:
void mySignal();
}
and in your code after validation:
void myClass::dataValidation()
{
/*validate data*/
emit mySignal();
}

how to access a widget from another class

I have two classes(MyWidget,ViewContact). In MyWidget, there is a QLineEdit and QListWidget. The contents in the QListWidget changes dynamically while changes in QLineEditt.
In ViewContact class there is many widgets.The ViewContact class is called by MyWidget class.
void MyWidget::viewbind(QListWidgetItem *item)
{
LblNames *widget = (LblNames*)( listWidget->itemWidget(item) );
ViewContacts *v=new ViewContacts(widget->getLabelId());
v->show();
}
then ViewContact widget shown as a window,no problem.works fine.
while clicking an update button inside ViewContact class i need to close that window and change the text inside MyWidget .now i just close the ViewContact by this.close(); function.
I give QLineEdit as public and try to change the text. No errors occur. But no changes display in QLineEdit inside MyWidget
Add a signal in the ViewContact class and emit a signal while close ViewContact Widget.The signal should contain a string to bind your list view.Before initiating ViewContact Widget from MyWidget ,should connect the signal and setText(const QString) slot.
Add the MyWidget as a parent to your ViewContacts instance. This will allow you to call a function to update the text (and it will also fix the memory leak which you currently have in your code).
You need a constructor for your ViewContacts that takes both a parent and the labelId.
class ViewContacts : public QWidget // or whatever it is, you didn't tell
{
Q_OBJECT
public:
// I don't know the class of "LabelId" either
explicit ViewContacts(LabelId id, QObject* parent = 0) : QWidget(parent)
{
// ...
}
void updateTextInParent()
{
MyWidget* w = qobject_cast<MyWidget*>(this->parent());
if (NULL != w)
{
// w is a valid pointer to a MyWidget instance
// you can access any public fields and function through it.
}
}
};
You should also use qobject_cast or dynamic_cast in the snippet you provided because a blind cast is not safe.
This seems like a perfect time to take advantage of Qt's signals and slots. You can connect a signal that emits the value you want to update in your MyWidget object, from your ViewContacts widget.
First you'll need to create a signal that emits the changed value when the ViewContacts widget is closed.
Something like:
Q_SIGNALS:
void value_changed_signal( QString value );
Next you'll want to add a slot, it can be private, in your MyWidget parent class
The declaration would look something like:
private Q_SLOTS:
void update_text( QString value );
Finally, in your MyWidget class, somewhere after you have instantiated your ViewContacts object, connect the signal and slot with something like:
connect(new_view_contacts_object, SIGNAL( value_changed_signal( QString ) ),
this, SLOT( update_text( QString ) ) );

How to delete a QProcess instance correctly?

I have a class looking like this:
class FakeRunner : public QObject
{
Q_OBJECT
private:
QProcess* proc;
public:
FakeRunner();
int run()
{
if (proc)
return -1;
proc = new QProcess();
QStringList args;
QString programName = "fake.exe";
connect(comp, SIGNAL(started()), this, SLOT(procStarted()));
connect(comp, SIGNAL(error(QProcess::ProcessError)), this,
SLOT(procError(QProcess::ProcessError)));
connect(comp, SIGNAL(finished(int, QProcess::ExitStatus)), this,
SLOT(procFinished(int, QProcess::ExitStatus)));
proc->start(programName, args);
return 0;
};
private slots:
void procStarted() {};
void procFinished(int, QProcess::ExitStatus) {};
void procError(QProcess::ProcessError);
}
Since "fake.exe" does not exist on my system, proc emits the error() signal. If I handle it like following, my program crashes:
void FakeRunner::procError(QProcess::ProcessError rc)
{
delete proc;
proc = 0;
}
It works well, though, if I don't delete the pointer. So, the question is how (and when) should I delete the pointer to QProcess? I believe I have to delete it to avoid a memory leak. FakeRunner::run() can be invoked many times, so the leak, if there is one, will grow.
Thanks!
You can't delete QObject instance inside slot which is connected to a signal in this instance using normal delete operator. This is due to the fact that if signal and slot connected using direct connection then the slot actually called from the signal implementation made by moc. This is like attempt to delete this; from inside the member of a class. There is a solution QObject::deleteLater(). Object will be deleted by Qt event loop inside events processing function. So you need to call proc->deleteLater() in your case.
And you don't need to disconnect signal from slot since Qt do it automatically when QObject is deleted.

QT EventTransition implementation

I am trying to build an QT State Maschine. I have some States, and for those States i need Transition that alter the Graphics on my gui.
The Problem i having and the only reason i am asking, i am Stuck and Point 1.
The compiler cant identifie the QTEventTransition. I have QT 4.6 wroking with QT Creator on Windows.
The compiler does not find Header #include < QtEventTransition >
This is what i did i never did this bevor but i think it should be correct, I have A Header File where i have my Transitions Declareted like this:
class validateBoatTransition : public QtEventTransition
{
public:
validateBoatTransition(Widget *widget,ServerSkeleton* server);
protected:
bool eventTest(QEvent *e);
void onTransition(QEvent *);
private:
Chart* ourChart;
Message current;
BarelySocket* myBarelySocket;
};
Than i have my Cpp File where i have this:
validateBoatTransition::validateBoatTransition(Widget *widget,ServerSkeleton* server)
{
}
void validateBoatTransition::onTransition(QEvent *e)
{
/*
My Logik should go here
*/
}
What i want is that if the Transition is activated by an Button (clicked) it should fire this transition!
I searched the net, but cant find an solution. Can i do that? I should i think.
Yours Thomas
Maybe you should take a look to signals/slot mechanism. I think this is what you need to achieve what you want.
Make your onTransition function a slot instead of an event handler and connect it to the signal clicked of the button.
class validateBoatTransition : public QtEventTransition
{
...
public slots:
void onTransition();
...
}
Somewhere in your code, connect the button to the slot:
QObject::connect(myButton, signal(clicked()), myValidateBoatTransition, slot(onTransition());
Each time the button will be clicked the execution will go through the onTransition function.
I think you're trying to use wrong classes/mechanisms to achieve your goals. If I understand you correctly, you have some GUI and after clicking some button you want to validate some stuff and if this validation is successful the state machine should change it's state. I'd write it this way:
Create some class to handle validation:
class BoatValidator : public QObject
{
Q_OBJECT
// boring stuff like constructor, etc.
public slots:
void validate()
{
if ( /*your validation logic goes here*/ ) {
emit boatTransition();
}
}
signals:
void boatTransition(); // emitted if validation is succesful
};
Then you connect your QPushButton::clicked() to BoatValidator::validate() and use BoatValidator::boatTransition() signal to drive the state machine:
QStateMachine machine;
QState *state1 = new QState(&machine);
QState *state2 = new QState(&machine);
// more state machine setup
// connect validator and button
QPushButton button;
BoatValidator validator;
connect(&button, SIGNAL(clicked()), &validator, SLOT(validate()));
// use validator to change states
state1->addTransition(&validator, SIGNAL(boatTransition()), state2);
Generally I'd use signal to drive state machine, unless some transitions are obviously event driven (for example some QEvent::Enter/QEvent::Leave on GUI widgets, etc.).
What i wanted to do is build a Qt State Machine. The Problem was that i could not trigger my own Transitions (let alone with my own Events). The answers given are good but would lead to a messy code. Why should i use a QT State Machine if i could not use the QT Transitions?
The First Problem above is solved, if you create a new Project. QT Creater is very annoying.
But here now my solution , may it help others.
First my State:
class ServerState : public QState
{
Q_OBJECT
public:
ServerState(QPushButton * pushButton);
~ServerState();
public slots:
void buttonWasClicked();
protected:
void onEntry(QEvent *e);
void onExit(QEvent *e);
private:
QPushButton * pushButton;
};
Normal, but you see i added an Slot. This slot enables me to connect a bottom signal or a Widget Mouse Press Signal to it !
Like this:
QStateMachine *machine = new QStateMachine(this);
ServerState *s1 = new ServerState(connectButton);
connect(connectButton, SIGNAL(clicked()), s1, SLOT(buttonWasClicked()));
machine->addState(s1);
s1->addTransition(connectTransition);
all i needed to to is now fire a declared Event like this one :
#define RegisterToServerEventIndex User+5
class ConnectToServerEvent : public QEvent
{
public:
ConnectToServerEvent() : QEvent(QEvent::Type(QEvent::ConnectToServerEventIndex))
{}
};
when the slot was called:
void ServerState::buttonWasClicked()
{
this->machine()->postEvent(new ConnectToServerEvent());
qDebug("ServerState::buttonWasClicked");
}
The QT State Machine would now call all the Transitions , link with this state:
ConnectToServerTransition::ConnectToServerTransition(QPushButton * pushButtonB,ServerSkeleton* serverSkeleton)
{
this->pushButtonB = pushButtonB;
this->pushButtonB->hide();
this->serverSkeleton = serverSkeleton;
qDebug("ConnectToServerTransition::ConnectToServerTransition");
}
bool ConnectToServerTransition::eventTest(QEvent *e)
{
return (e->type() == QEvent::ConnectToServerEventIndex);
}
void ConnectToServerTransition::onTransition(QEvent *e)
{
if (true == this->serverSkeleton->initalisieren())
{
this->pushButtonB->show();
}else{
qDebug("Conection to Server faild");
}
emit kill();
return;
}
Whats so great that i dare to post?
Well first you can link a Qt SM to a widget where a mouse press event , or somthing else, is called and process the raw data to a an level you need later in your program. All you then need to do is, to emit the singal:
void Widget::mousePressEvent(QMouseEvent *event){
Coordinates current;
current.line = 0;
current.row = A;
current.row = (Row) (event->x() / 30); // 30 = breite von einen Feld
current.line = event->y() / 30; // 30 = länge von einen Feld
emit this->clicked(current);
return;
}
Then this enhenced information (current) is passed to the slot at my state, where i chose to call the correct transition that does the work. You could link more transitions to it, if you need it.
But most importend you dont need to reprogramm the Transition, a think i realy disliked.
Thank you for your help , i could not done it alone.

Resources