PDA

View Full Version : send messages from central widget to mainwindow (statusBar)??



fatecasino
22nd December 2010, 01:54
I have created a mainwindow with a status bar
then i created a widget
i set that widget as the central widget
now, I added several other widgets in that widget.

The question how I can send some text messages from those widgets to the mainwindow status bar?!

ChrisW67
22nd December 2010, 05:24
Connect to the QStatusBar::showMessage() slot and send away.

fatecasino
22nd December 2010, 12:29
well, it seems obvious, but I have something missing (probably important block of knowledge) here:
I have successfully constructed a status bar in the mainwindow:



mainwindow.h
public slots:
void printInfoToStatusBar (QString);
mainwindow.cpp
void MainWindow::printInfoToStatusBar (QString msg)
{
statusBar()->showMessage(msg);
}

I have a central widget and in the central widget I have added a widget with a slidebar. I want to see the values of the slidebar in the statusbar. How will i connect them? (i have more messages to send to the mainwindow, but if I get this, I will do the rest similaringly):



connect( myslider, SIGNAL( valueChangedinQStringType(QString) ), ???mainwindow??, SLOT( printInfoToStatusBar (QString ) ) );

PS: I have seen some examples of people using ui->this,etc,etc, but the way I started building my application had no ui whatsoever and now I cannot change the constructor of the main window (the ui way).

boudie
22nd December 2010, 13:01
in mainwindow.h

private slots:
void mySliderChanged(int);




in MainWindow.cpp

in constructor MainWindow::MainWindow
connect(mySlider, SIGNAL(valueChanged(int)), this, SLOT(mySliderChanged(int)));

void MainWindow::mySliderChanged(int newValue)
{
... send something to your statusbar ...
}


In some cases you can send a value directly from one control to another, but processing a signal the way shown above, gives you freedom to change values or formats before sending it to someplace else.

Make sure that mySlider has tracking == true, if you want immidiate update when moving the slider:


mySlider.setTracking(true);

fatecasino
22nd December 2010, 18:05
@boudie
the point is that mySlider does not belong to "MainWindow" class, but to a widget (central) of the MainWindow.That means that:


constructor MainWindow::MainWindow
connect(mySlider, SIGNAL(valueChanged(int)), this, SLOT(mySliderChanged(int)));

cannot be used :(

boudie
22nd December 2010, 20:35
How and where did you create mySlider?
Please show complete code.

ChrisW67
22nd December 2010, 21:12
If the slider is part of a Designer built QMainWindow, i.e. the central widget sub-widgets are accessible to the main window, then something like this will work:


connect(ui->mySlider, SIGNAL(valueChanged(int)), this, SLOT(mySliderChanged(int)));


If you have a completely separate widget (OtherWidget) that you set as the central widget then its sub-widgets are not usually accessible from outside. In this case you should expose a signal in class OtherWidget that simply repeats the slider's valueChanged(int) signal to the outside world. Then you connect that externally visible signal as above. Something like:

class OtherWidget: public QWidget {
Q_OBJECT
public:
OtherWidget() {
mySlider = new QSlider(this);
...
connect(mySlider, SIGNAL(valueChanged(int)), this, SIGNAL(sliderChanged(int)));
}
signals:
void sliderChanged(int value);
private:
QSlider *mySlider;
};

fatecasino
23rd December 2010, 23:06
thanks ChrisW67 ,
I am close to understand, but I am still a bit confused. After further reading, here's what I have got:

mainwindow.h


public slots:
void printInfoToStatusBar (QString);
mainwindow.cpp

void MainWindow::printInfoToStatusBar (QString msg)
{
statusBar()->showMessage(msg);
}

then indeed OtherWidget is the central widget of the main window
OtherWidget.h


class OtherWidget : public QWidget
{
public:
OtherWidget(QWidget *parent = 0);
signals:
void sliderChanged(int value);
private:
.....
........other widgets....
QSlider mySlider;
};

OtherWidget.cpp


OtherWidget::OtherWidget(QWidget *parent)
: QWidget(parent)
{
mySlider = new QSlider(this);
connect(mySlider, SIGNAL(valueChanged(int)), this, SIGNAL(sliderChanged(int)));//connecting two SIGNALS, right?
}

void OtherWidget::sliderChanged(int)
{
//is this the place that I should reflect the slider signal to the mainwindow?how?
}



PS: I haven't used Designer, just Creator.

ChrisW67
24th December 2010, 00:24
Yes, connecting two SIGNALS together. When the source signal is emitted the destination signal will be emitted. It is in the docs.

As you have it now, you need to find the correct spot to:


connect(
otherWidget, SIGNAL(sliderChanged(int)),
mainWindow, SLOT(printInfoToStatusBar(QString)) // the function templates do not match: you'll need to sort this out
);
Probably immediately after creating an instance of OtherWidget.

You could redefine the signal out of OtherWidget:


public slots:
void sliderChanged(int value);
signals:
void statusMessage(QString msg);
...
connect(mySlider, SIGNAL(valueChanged(int)), this, SLOT(sliderChanged(int)));
...
void OtherWidget::sliderChanged(int value)
{
emit statusMessage( QString("Some status message including the %1").arg(value) );
}

or redefine the slot in the main window class to accept an int.

fatecasino
26th December 2010, 16:59
Hi Chris,

I think I am getting closer, but I am stuck with this error:


error: expected primary-expression before ‘,’ token

which means that I am probably doing something very wrong connecting signal/slot.

In the constructor of otherWidget (I call it MyWidget)


mySlider = new QSlider;
//connect(mySlider, SIGNAL(valueChanged(int)), this, SIGNAL( sendInfoToMainWindows(int) ));
connect(mySlider, SIGNAL(valueChanged(int)), this, SLOT( sendInfoToMainWindows(int) ));

connect( MyWidget, SIGNAL( sendInfoToMainWindows(int) ), MainWindow, SLOT( printNumberInfoToStatusBar(int) ) );//error!!!




I tried without success to put the connection line in the MainWindow.cpp

widget = new MyWidget;
setCentralWidget(widget);
connect( widget, SIGNAL( sendInfoToMainWindows(int) ), MainWindow, SLOT( printNumberInfoToStatusBar(int) ) );



I know the emit function is wrong, but I just want to emit the value that the slider sends to the MyWidget


void MyWidget::sendInfoToMainWindows(int value)
{
emit value;
}


I sorted out the mainWindow message function to accept integers:


void MainWindow::printNumberInfoToStatusBar (int value)
{
QString str;
str.setNum(value);
statusBar()->showMessage(str);
}


Any ideas?~!

Added after 10 minutes:

well, it is this magic effect when you press the post button of the forum, you get a new idea and things work better.

The connection SHOULD be in the MainWindow.cpp


widget = new MyWidget;
setCentralWidget(widget);
connect( widget, SIGNAL( sendInfoToMainWindows(int) ), this, SLOT( printNumberInfoToStatusBar(int) ) );

everything compiles, but now I have to find the right syntax to emit the value that the MYWidget gets from the slide to the MainWindow


void MyWidget::sendInfoToMainWindows(int value)
{
emit value;
}

AlexSudnik
26th December 2010, 20:18
Hey there!

1.Connect MyWidget's widgets with MyWidget's signal (as Chris said,you just want to propogate your inner signals):

connect(mySlider, SIGNAL(valueChanged(int)), SIGNAL( sendInfoToMainWindows(int) )); //you may not write this keyword

2.As you said,MyWidget is not initially aggregated by MainWindow.But there's got to be a place in your program where you actually invoke QMainWindow::setCentralWidget method.Let's say you do this in your main.cpp,your main function may look like this:


int main(int argc,char* argv[]){

QApplication app(argc,argv);

MainWindow mainWin;

MyWidget widget;

mainWin.setCentralWidget(&widget);

QObject::connect(&widget,SIGNAL(sendInfoToMainWindows(int)),&mainWin,SLOT(printNumberInfoToStatusBar(int)));

mainWin.show();

return app.exec();


}

That's it,you have your widgets connected now...By the way, you can have a QString contructed from the int type (and other built-in types) via the static method:

QString number ( int n, int base = 10 )

So check out QAssistant's page on QString:)

Hope you have an idea now...

fatecasino
26th December 2010, 20:33
supposing I have successfully connected the widgets to the mainWindow in the constructor of the Mainwindow.cpp, I cannot figure out how I will emit the int signal:


void MyWidget::sendInfoToMainWindows(int value)
{
emit value;
}

ChrisW67
26th December 2010, 22:11
Take a look back at post #9 (http://www.qtcentre.org/threads/37216-send-messages-from-central-widget-to-mainwindow-(statusBar)?p=171327#post171327) in this thread. You need to name the signal you are emitting and provide it with any arguments it requires. The word "emit" is syntactic sugar, the rest of the line is essentially a function call.

This will all make more sense it you read the "Signals and slots" information available from the "Qt Object Model" page in Assistant.

AlexSudnik
27th December 2010, 06:06
Think about connecting signal to signal like this: every time one is emitted,another is emitted as well...tyou don't have to emit connected signals manually (if it wasn't,what's the point of connections then)

fatecasino
27th December 2010, 17:28
well, I have been studying several signal/slot examples and there is always a dark area in my understanding:


connect(mySlider, SIGNAL(valueChanged(int)), this, SIGNAL( sendInfoToMainWindows(int) ));

The function valueChanged(int) function, is a signal function.
It sends the actual value of the slider to the MyWidget.
Then,
The function sendInfoToMainWindows(int) sends this signal from the MyWidget to the MainWIndow.
In simple words valueChanged(int) and sendInfoToMainWindows(int) do a very similar job, right? they emit a signal to a certain destination.
Question:
What is the exact source code of the valueChanged(int) so I can reproduce it for the sendInfoToMainWindows(int)?


@AlexSudnik
I think I am trying to do exactly the thing you describe.

The slider sends a value signal to the central widget

connect(mySlider, SIGNAL(valueChanged(int)), this, SIGNAL( sendInfoToMainWindows(int) ));


the sendInfoToMainWindows(int) receives it and resends(?) it to the printNumberInfoToStatusBar(int) of the MainWindow

connect( widget, SIGNAL( sendInfoToMainWindows(int) ), this, SLOT( printNumberInfoToStatusBar(int) ) );

I believe that the actual missing part is the source code of the sendInfoToMainWindows(int) because I have never designed a signal function so far.

ChrisW67
28th December 2010, 04:10
The main points:

Want the signal from the slider on your custom widget to be connected to the slot of the main window status bar.
Cannot do this directly because the slider on your widget is private (in the C++ sense) to the widget.
Need to expose a signal in the public interface of the widget so that it can be connected to the status bar slot.
The signal should fire every time the signal of the widget slider fires.
The signal needs to match the integer argument from the slider signal to the string argument expected by the slot.
There is more than one way to do it.


One way to organise it:

Private slider's valueChanged(int) signal

connected to
Widget's sliderChanged(int) slot, which converts the int to a meaningful message and...
Emits a signal statusChanged(QString)

connected to
Status bar showMessage(QString) slot, which shows the message.

Another:

Private slider's valueChanged(int) signal

connected to
Widget's sliderChanged(int) signal

connected to
Main window slot receiveASliderUpdateMessage(int), which converts the value to a message and calls the status bar showMessage(QString)


The function that underlies a signal is written for you by the moc component of Qt. You do not need to write a signal function yourself. You need to write a simple slot in either the widget or main window and make sure the connections are made.

fatecasino
29th December 2010, 21:54
Hi all!
i feel a bit stupid after all these posts that I cannot implement something that seems so realistic !
Well, I am stubborn enough to get back to this thread.

From the two Chris' options I have algorithmically 100% understood the second one (signal to signal)



Private slider's valueChanged(int) signal
connected to
Widget's sliderChanged(int) signal



connect(mySlider, SIGNAL(valueChanged(int)), this,SIGNAL(sendInfoToMainWindows(int) ));





Widget's sliderChanged(int) signal
connected to
Main window slot receiveASliderUpdateMessage(int), which converts the value to a message and calls the status bar showMessage(QString)


in MainWindow.cpp


widget = new MyWidget;
setCentralWidget(widget);
connect( widget, SIGNAL( sendInfoToMainWindows(int) ), this, SLOT( printNumberInfoToStatusBar(int) ) );

void MainWindow::printNumberInfoToStatusBar (int value)
{
QString str;
str.setNum(value);
statusBar()->showMessage(str);
}

well, so far so good.
Now, trying to create the famous Widget's sliderChanged(int) signal
(i called it sendInfoToMainWindows(int value) because i want to use it for other widgets,too)


void MyWidget::sendInfoToMainWindows(int value)
{
emit mySlider->valueChanged(value);
}

I get the error:
error: ‘void QAbstractSlider::valueChanged(int)’ is protected

That's the best point i have reached the last week!

ChrisW67
30th December 2010, 21:00
You don't need to create an implementation of the sendInfoToMainWindows(int) signal. You just need to include it in the class definition as a signal and let Qt generate the code for you (moc).


class MyWidget: public QWidget
{
Q_OBJECT
...
signals:
void sendInfoToMainWindows(int value);
}

fatecasino
31st December 2010, 19:16
thanks!!!I will check it out the soonest,
until then,

HAPPY NEW YEAR TO EVERYONE!!!!!!!!!!!!!!!!!!!!!!!!!!!:cool::rolleyes ::D

fatecasino
3rd January 2011, 21:53
well...new year brought a success!!!


The function that underlies a signal is written for you by the moc component of Qt. You do not need to write a signal function yourself. You need to write a simple slot in either the widget or main window and make sure the connections are made.

I couldn't imagine that it would simply work if I just write absolutely nothing in the implementation .cpp file about the function:


void sendInfoToMainWindows(int value);

Now, last question on this topic:

instead of connecting the integer value of the slider with the status bar of the MainWindow


connect(mySlider, SIGNAL(valueChanged(int)), this,SIGNAL(sendInfoToMainWindows(int) ));

I want to sent a simple QString message from a subwidget to the status bar of the MainWindow( subwidget--signal-->centralWidget--signal-->MainWindow--slot-->statusBar), like


"you tried 12 times to find the key"
(variable value "12" changes)

The QSlider has a built in function valueChanged(int), how can I create a similar message QString SIGNAL sendMSGToMainWindows(QString) to connect to the MainWIndow?


connect(mySubWidget, SIGNAL( ???sendMSGtoCentralWidget(QString)??? ), this,SIGNAL( sendMSGToMainWindows(QString) ));