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 ) ) );
Related
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.
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.
I have a problem. I've created a class, in which I have a slider and a label. I want to connect these with the QObject::connect, but when I do it, nothing happens. Can you tell me what am I doing wrong?
My class:
class Loads :public QObject
{
Q_OBJECT
public:
QSlider slider;
QLabel label;
QMainWindow okno;
Loads();
private:
int wart;
public slots:
void zmiana(int li);
};
Class "Loads" constructor:
Loads::Loads()
{
okno.setGeometry(300,300,300,300);
label.setParent(&okno);
slider.setParent(&okno);
label.setGeometry(0,0,300,200);
slider.setGeometry(0,200,300,100);
slider.setMinimum(1);
slider.setMaximum(30);
label.setText("0");
wart=0;
QObject::connect(this, SIGNAL( slider.valueChanged(int)), this , SLOT( zmiana(int)) );
okno.show();
}
My "zmiana" slot
void Loads::zmiana(int li)
{
wart=li;
label.setText(QString::number(li));
}
QObject::connect(this, SIGNAL( slider.valueChanged(int)), this , SLOT( zmiana(int)) );
I don't think that's correct, you're connecting the signal of the Loads object to the slot but the Loads object is not the one generating the signal, the slider object is doing that.
Hence I think you'll need slider as the first argument, not this. Using this as the third argument is okay, I believe, since the slot does belong to the Loads object.
I have a QMainWindow object parent to a QDialog Object. When I call the QDialog with exec() it stays open, but I can't use the QMainWindow at the same time. If I use show() instead, the QDialog opens and hides immediately after.
I know this relates to the modality flag of the QDialog, but it does not have a Qt::Modeless flag, so I'm a bit lost.
Question: How can I display a QDialog and still be able to interact with its parent QMainWindow?
My code for the QDialog object:
class catalog : public QDialog
{
Q_OBJECT
public:
explicit catalog(QWidget *parent = 0);
~catalog();
private:
Ui::catalog *ui;
};
How I'm calling it:
void DiagramWindow::showCatalog()
{
catalog catalog(this);
catalog.exec();
}
It closes, because QDialog::show() method is asynchronous and your catalog object is destroyed right after your code leaves DiagramWindow::showCatalog() method. You should rewrite it like this:
void DiagramWindow::showCatalog()
{
catalog *c = new catalog(this);
c->setAttribute(Qt::WA_DeleteOnClose);
c->show();
}
How can I pass data from one form to another in Qt?
I have created a QWidgetProgect -> QtGuiApplication, I have two forms currently. Now I want to pass data from one form to another.
How can I achieve that ?
Thanks.
Here are some options that you might want to try:
If one form owns the other, you can just make a method in the other and call it
You can use Qt's Signals and slots mechanism, make a signal in the form with the textbox, and connect it to a slot you make in the other form (you could also connect it with the textbox's textChanged or textEdited signal)
Example with Signals and Slots:
Let's assume that you have two windows: FirstForm and SecondForm. FirstForm has a QLineEdit on its UI, named myTextEdit and SecondForm has a QListWidget on its UI, named myListWidget.
I'm also assuming that you create both of the windows in the main() function of your application.
firstform.h:
class FistForm : public QMainWindow
{
...
private slots:
void onTextBoxReturnPressed();
signals:
void newTextEntered(const QString &text);
};
firstform.cpp
// Constructor:
FistForm::FirstForm()
{
// Connecting the textbox's returnPressed() signal so that
// we can react to it
connect(ui->myTextEdit, SIGNAL(returnPressed),
this, SIGNAL(onTextBoxReturnPressed()));
}
void FirstForm::onTextBoxReturnPressed()
{
// Emitting a signal with the new text
emit this->newTextEntered(ui->myTextEdit->text());
}
secondform.h
class SecondForm : public QMainWindow
{
...
public slots:
void onNewTextEntered(const QString &text);
};
secondform.cpp
void SecondForm::onNewTextEntered(const QString &text)
{
// Adding a new item to the list widget
ui->myListWidget->addItem(text);
}
main.cpp
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// Instantiating the forms
FirstForm first;
SecondForm second;
// Connecting the signal we created in the first form
// with the slot created in the second form
QObject::connect(&first, SIGNAL(newTextEntered(const QString&)),
&second, SLOT(onNewTextEntered(const QString&)));
// Showing them
first.show();
second.show();
return app.exec();
}
You could also use pointers to access the QTextEdit (assuming that's what you're using) from the other form.
Following from Venemo's example (where FirstForm has the QTextEdit and SecondForm's the one you need to access the QTextEdit from):
firstform.h:
class FistForm : public QMainWindow
{
...
public:
QTextEdit* textEdit();
};
firstform.cpp:
QTextEdit* FirstForm::textEdit()
{
return ui->myTextEdit;
}
You can then access the QTextEdit's text in SecondForm with something like this (assuming your instance of FirstForm is called firstForm):
void SecondForm::processText()
{
QString text = firstForm->textEdit()->toPlainText();
// do something with the text
}