Qt-interest Archive, April 2007
passing varible between widgets
Message 1 in thread
Hi all
I currently have two Qwidgets - QWidget1 and QWidget2. QWidget1 is the
main window - this class also takes and holds data for a piece of
equipment in the lab and displays some of this information. It also has
a private member which is a pointer to the second Qwidget2 (I declare
the memory in QWidget1s constructor). I press a button and it pops up
QWidget2 with show(). I want to be able to put data that I have stored
in QWidget1 class (voltages currents etc) on LCD widgets on the QWidget2
display. Is there an easy way to share this data?
Thanks
Ross
--
[ signature omitted ]
Message 2 in thread
Ross Williamson schrieb:
> Hi all
> ...
> display. Is there an easy way to share this data?
The short answer: yes, it's called Model/View/Controller pattern (basic
software engineering).
The somewhat more detailed answer: Your widgets are the *views* (don't
store data in views!). Create a *model* class, e.g. "PowerModel". This
model class has setter/getter methods, for setting the voltage for example.
Each time the voltage is changed in a set-method it emits a signal. The
*views* connect to this signal and get informed whenever the *model* is
changed.
A trivial example is also given in the Qt docs, I believe under "signal
and slots" ;)
The more advanced applications have a separate "Controller" instance
which controls how/when/if the model is to be changed. Mostly the view
and the controller are in the same class, e.g. the QLineEdit is usually
be both the controller (entering and changing data) and the view (react
to signal updates by other controller/views and update the value being
displayed).
Cheers, Oliver
--
[ signature omitted ]
Message 3 in thread
Hi Oliver
Thanks for the reply. BTW I'm no software engineer! Just trying to
cludge things together. So, my current code is like the advanced model
you mentioned earlier. I'm thinking one way is to create a "super"
class which inherites the two Qwidgets. I guess this is messy. I'll
also look again at how to do this with slots. Would the idea be
something like:
Class1 - Data taking and Parameter setting
Class2 - Front panel
Class3 - Sub panel with more detail
I create independent instances of Class1 and Class2. These will be able
to communicate data between each other using slots. When I need it
Class2 creates an instance of Class3. Class1 and Class3 will now be able
to communicate data using slots until I close the Class3 QWidget window?
Thanks
Ross
Till Oliver Knoll wrote:
> Ross Williamson schrieb:
>
>> Hi all
>> ...
>> display. Is there an easy way to share this data?
>>
>
> The short answer: yes, it's called Model/View/Controller pattern (basic
> software engineering).
>
> The somewhat more detailed answer: Your widgets are the *views* (don't
> store data in views!). Create a *model* class, e.g. "PowerModel". This
> model class has setter/getter methods, for setting the voltage for example.
>
> Each time the voltage is changed in a set-method it emits a signal. The
> *views* connect to this signal and get informed whenever the *model* is
> changed.
>
> A trivial example is also given in the Qt docs, I believe under "signal
> and slots" ;)
>
> The more advanced applications have a separate "Controller" instance
> which controls how/when/if the model is to be changed. Mostly the view
> and the controller are in the same class, e.g. the QLineEdit is usually
> be both the controller (entering and changing data) and the view (react
> to signal updates by other controller/views and update the value being
> displayed).
>
> Cheers, Oliver
>
> --
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with "unsubscribe" in the subject or the body.
> List archive and information: http://lists.trolltech.com/qt-interest/
>
>
>
--
[ signature omitted ]
Message 4 in thread
Ross Williamson schrieb:
> Hi Oliver
>
> Thanks for the reply. BTW I'm no software engineer!
@astro: I just thought so ;)
> Just trying to
> cludge things together.
First off I'd recommend the small tutorial about signal and slots to get
the "general feeling" for this concept (the Qt docs are excellent!):
http://doc.trolltech.com/4.2/signalsandslots.html
A simple example is given in the same tutorial:
http://doc.trolltech.com/4.2/signalsandslots.html#a-small-example
In your case this "Counter" (from the example above) would be the
equivalent to your "model", i.e. the "VoltageClass". See below.
> So, my current code is like the advanced model
> you mentioned earlier. I'm thinking one way is to create a "super"
> class which inherites the two Qwidgets. I guess this is messy. I'll
You should think of it "the other way round": the Model (the data) is
always at the very "bottom", the View (GUI) at the "top". The Model does
not depenend on much except on QObject (for the signal/slot mechanism)
or other more basic Models. But for sure it must not know anything about
its Views (the widgets displaying the data).
And there is no need for the views to inherit from the model (in fact,
this would even be considered "wrong" in an object-oriented way of
thinking: a view *is not* a model, but rather *has a* (reference to a)
model ("is-a" relationship vs. "has-a" relationship, another concept in
OO-design ;)
> also look again at how to do this with slots. Would the idea be
> something like:
>
> Class1 - Data taking and Parameter setting
> Class2 - Front panel
> Class3 - Sub panel with more detail
>
> I create independent instances of Class1 and Class2. These will be able
> to communicate data between each other using slots. When I need it
> Class2 creates an instance of Class3. Class1 and Class3 will now be able
> to communicate data using slots until I close the Class3 QWidget window?
I believe the above comes closer to the MVC-pattern :) Let's give
concrete names to the classes:
Class1: "PowerModel" (the Model)
Class2: "FrontPanel" (the View1)
Class3: "SubPanel" (the View1)
Analog to the Qt example above the PowerModel could look like this:
// The Model
class PowerModel : public QObject // needs to inherit from at least
// QObject for signal/slots
{
Q_OBJECT // needed for signal/slots
public:
PowerModel();
~PowerModel();
// emits signal 'voltageChanged'
void setVoltage(double newVoltage);
// returns the voltage
double getVoltage() const;
signals:
// emitted whenever the voltage has changed;
// 'voltage' contains the new value'
void voltageChanged(double voltage);
// etc.
...
};
Now for the views, they need to have a reference (or pointer) to a
concrete model instance (typically an instance of a model is created at
program startup or whenever you load a file etc.). Additionally the
views connect themselves to the signal(s) of the model.
Let's assume whenever you create a view you pass along a reference to
the model which exists somewhere in your application:
// forward declarations
class PowerModel;
class SubPanel;
class FrontPanel : public QWidget
{
Q_OBJECT // again needed for the signal/slots
// pass along a reference to the Model so this View
// knows what to display (and change)
FrontPanel(PowerModel &powerModel);
~FrontPanel()
// slots, methods etc.
...
private:
PowerModel &m_powerModel; // a reference to the Model
QLineEdit *m_lineEdit; // the actual "View/Controller": displays
// the voltage and also changes it
private slots:
// I prefer to connect signals in the c'tor of each class,
// so connections are not "forgotten".
// if on the other hand you want to connect the Model to
// this View "externally" then you should declare this slot
// public
void handleVoltageChanged(double voltage);
void handleVoltageEdited(const QString &text);
};
The implementation could look like this:
FrontPanel::FrontPanel(PowerModel &powerModel)
: m_powerModel (powerModel) // initialise the Model reference in this
// "initialisation list" (C++, in case you
// have not seen this before ;)
{
// connect to the Model
// ATTENTION: DON'T write the parameter names here, just their type
// (typical "copy/paste" source of error), else the "moc"
// gets confused
this->connect (&m_powerModel, SIGNAL (voltageChanged(double)),
this, SLOT (handleVoltageChanged(double)));
// setup GUI elements (m_lineEdit etc.) (respective design
// your widget in the Qt Designer instead, give the widgets
// a meaningful name there and access them via the "ui" member,
// see Qt docs for more)
...
// update the Model when the Controller tells us to do so.
// We connect to "textEdited" (and NOT textChanged), see comment
// below
this->connect (m_lineEdit, SIGNAL (textEdited(const QString &)),
this, SLOT (handleVoltageEdited(const QString &)));
}
// called whenever the Model has changed
void FrontPanel::handleVoltageChanged(double voltage)
{
// ATTENTION: In general take care as to AVOID "signal loops"!
// We intentially connected to QLineEdit's textEdited signal
// (and NOT textChanged which would also be emitted when calling
// setText causing a "signal loop"; see also
// http://doc.trolltech.com/4.2/qlineedit.html#textEdited
//
// Alternatively you could "supress" the signals being sent
// by calling QObject#blockSignals on QLineEdit (don't forget
// to unblock them after changing the value)
// update the View, see comment above
m_lineEdit->setText (QString("%1").arg (voltage));
}
// called whenever the Controller/View has changed
void FrontPanel::handleVoltageChanged(const QString &voltage)
{
// update the Model: the clever trick(tm) here is now that
// every other View (for example "the SubPanel") which has connected
// to the model is *automagically updated* as well! We don't need to
// care ourselves at this point. In fact, we don't even need
// to know all the other (possibly hundreds of) Views and
// you can add other Views to your program later on without
// worrying about every other existing View being correctly updated.
//
// That's the clever thing about the Model/View/Controller pattern :)
// It's so simple and such a fundamental thing in software
// engineering, but you just see it all to often in existing
// program code (even from "software engineers") that
// people get it wrong or terribly complicated - hence my hope that at
// least astro engineers get it right ;)
// it's as simple as that :)
m_powerModel->setVoltage (voltage.toDouble());
}
Now in complete analogy you would create your "SubPanel" class: pass
along a reference to the (same) PowerModel Model instance, connect to
it's signal 'voltageChanged' and update the widgets inside your SubPanel
class accordingly, whenever it receives this signal. This is how data is
"passed along widgets".
Note again that in practice you could add more Views/Controller to your
application which connect to the Model instance, for example a
"VoltageGraph" widget which would display the last n voltages as a curve
and would get updated each time the voltage gets changed.
In the FrontPanel then you don't need to care: simply change the voltage
and every other view gets updated :)
Off course I completely agree that in your simple example (having just a
FrontPanel which "knows" it's SubPanel anyway) you could solve things
much easier (in a "Uh I need to type a lot more code than really
necessary with signal/slots"- way), as proposed in another reply
already. But remember: things *always* get more complicated in a program
in time, so it's a good thing to get at least the "foundation" right
from the very beginning ;)
I hope you enjoyed my little "tutorial about MVC pattern" :)
Cheers, Oliver
p.s. I'm a software engineer; don't blame me if the code above does not
compile, has bugs, does not fit your needs and/or requirements or is
otherwise completely useless to you ;)
--
[ signature omitted ]
Message 5 in thread
On 19.04.07 12:12:28, Ross Williamson wrote:
> I currently have two Qwidgets - QWidget1 and QWidget2. QWidget1 is the
> main window - this class also takes and holds data for a piece of
> equipment in the lab and displays some of this information. It also has
> a private member which is a pointer to the second Qwidget2 (I declare
> the memory in QWidget1s constructor). I press a button and it pops up
> QWidget2 with show(). I want to be able to put data that I have stored
> in QWidget1 class (voltages currents etc) on LCD widgets on the QWidget2
> display. Is there an easy way to share this data?
Sure, implement a public setter method on the second widget and call it
before you execute its show() method. In the setter the second widget
can do with the data whatever it wants.
Andreas
--
[ signature omitted ]
Message 6 in thread
Ross Williamson wrote:
> Hi all
>
> I currently have two Qwidgets - QWidget1 and QWidget2. QWidget1 is the
> main window - this class also takes and holds data for a piece of
> equipment in the lab and displays some of this information. It also has
> a private member which is a pointer to the second Qwidget2 (I declare
> the memory in QWidget1s constructor). I press a button and it pops up
> QWidget2 with show(). I want to be able to put data that I have stored
> in QWidget1 class (voltages currents etc) on LCD widgets on the QWidget2
> display. Is there an easy way to share this data?
>
> Thanks
>
> Ross
>
> --
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with "unsubscribe" in the subject or the body.
> List archive and information: http://lists.trolltech.com/qt-interest/
Simple solution,
connect(this->parent(), SIGNAL(newRowDomain(QString, QString)), this,
SLOT(newDomain(QString, QString)));
--
[ signature omitted ]