Qt: why does connect() work only in the main window class? - c++

Here's a simple code that creates a button and assigns a onclick handler:
auto btn = new QPushButton("CLICK ME");
connect(btn, SIGNAL(clicked()), this, SLOT(btn_Click()));
private slots:
void btn_Click() {
alert("clicked!");
}
It works as it should if called in the main window class. However when I try to do this in a child window, clicking the button does nothing. The child window is shown like this:
auto settingsWindow = new SettingsWindow();
settingsWindow->show();
I guess it's somehow connected with the receiver object which is now a different window. But how can I make it work?

In order to be able to declare signals/slots in your own class you should include Q_OBJECT directive in your class:
class SettingsWindow {
Q_OBJECT
...
};

You should add a MACRO in class SettingsWindow to enable singal receiving.
Add "Q_OBJECT" like the following.
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget();
....

Related

QDialog derived class

I have derived class from QDialog that I use for showing the charts. The constructor looks like this:
myplot::myplot(QDialog *parent) : QDialog(parent)
{
chartView = new QChartView();
chart = new QChart();
Qt::WindowFlags flags = 0;
flags |= Qt::WindowMaximizeButtonHint;
flags |= Qt::WindowCloseButtonHint;
setWindowFlags(flags);
this->setLayout(new QVBoxLayout);
this->layout()->addWidget(chartView);
this->setModal(1);
chartView->setChart(chart);
}
I call my class from Mainwindow.cpp but dialog does not close after App exit:
myplot* plot = new myplot(); //does not close after app exit
plot->do_something();
plot->show();
I thought I will correct the problem by this but it does not work:
myplot* plot = new myplot(this); //does not work
When I use this the dialog is closed immediatelly
myplot plot; //immediatelly close
plot.do_something();
plot.show();
When I use exec instead of .show() I get the error "Debug Assertion Failed, _CtrlIsValidHeapPointer(block)" after dialog is closed
plot.exec();
//work but after exiting dialog error
Please, how to handle correctly my derived class to be closed after App exit? I also want to have myplot class to be not modal (now I have it modal in order the user would close it manually before app exit).
Added header file:
#ifndef MYPLOT_H
#define MYPLOT_H
class myplot : public QDialog
{
Q_OBJECT
private:
public:
explicit myplot(QDialog *parent = nullptr);
signals:
};
#endif // MYPLOT_H
This is probably a duplicate of this question.
The answer is you have to write that functionality yourself. If you have your myplot object as a member variable of your MainWindow class then you can properly close it in the MainWindow::closeEvent. See the linked answer above for a hint on how you might implement this.
BTW: Then you don't have to make your dialog modal to enforce closing it before the MainWindow.
you need to look what the QDialog looks like...
do: pass a QWidget instead of a QDialog to the constructor, add a destructor to the dialog and delete there all the things created by the myplot instance if any, call exec() instead of show()...
class myplot : public QDialog
{
Q_OBJECT
public:
explicit myplot(QWidget *parent = nullptr);
~myplot();
....

Access QT Widget child members from QT Widget Object Instance

Consider this QWidget initialized as:
QWidget *Logger;
Logger = new QWidget();
QPushButton *btn;
btn= new QPushButton(Logger);
btn->setObjectName(QStringLiteral("pushButton"));
Logger->show();
It display the Logger with a button with text pushButton.
Now Later if i want to access pushButton, i do it like this:
QPushButton *pushButton = Logger->findChild<QPushButton *>("pushButton");
pushButton->setText("NEW BUTTON");
I want to know is there a possibility to access directly this pushButton from Logger??Something like:
Logger->btn ...
I tried but it does not work. I have Widgets defined like this with many child objects and i wonder is this the only way to access them at run time??
EDIT: #drescherjm, So something along these lines you mean:
class MyWidget : QWidget
{
public:
QPushButton *pushButton;
MyWidget(){
pushButton = new QPushButton(this);
}
};
MyWidget *w = new MyWidget();
w->pushButton->setText("XYZ");
And is it worth it to create so many classes?? for small redundant tasks?
It won't work the way that you are expecting it to work. Use btn as long as it is in scope.
If you are creating btn somewhere locally, but your use-case demands you to use it in different places across your code, then you need to reconsider your design and make the QPushButton part of a class member.
Something of this sort :
#include <QPushButton>
class SampleWidget : public QWidget
{
public :
SampleWidget( QWidget * inParent );
// public methods to change the properties of the QPushButton go here.
void SetButtonText( QString const & inString );
bool IsButtonChecked();
private :
QPushButton *mSampleButton;
};
And in the implementation :
SampleWidget::SampleWidget(QWidget *parent)
:
mSampleButton( new QPushButton( parent ) )
{
// connect( mSampleButton,......... ); Connection to slot
}
void SampleWidget::SetButtonText( QString const & inString )
{
mSampleButton->setText( inString );
}
bool
SampleWidget::IsButtonChecked()
{
return mSampleButton->isChecked();
}
The question was not very clear on what you exactly want, but it seems like you are struggling to understand how to alter the attributes of a push button if it is a private member of a class and the above example will help you with that.

How to connect two dialogs?

If i click on one dialog button on the other dialog will show some text, it doesnt have to be text basicly connection between two dialogs. Something that will help me about my problem.
If you have two QWidget (or inherited) objects represented as dialogs, then you should use an QObject::connect method. Learn about signals and slots in Qt. It looks like:
class DialogA : public QWidget {
Q_OBJECT
...
public slots:
void ShowSomeText(); // called when receive a signal
...
};
class DialogB : public QWidget {
Q_OBJECT
...
void SendTextSignal(); // sends a signal
...
};
// somwhere in code
DialogA da;
DialogB db;
connect(db, SIGNAL(SendTextSignal()), da, SLOT(ShowSomeText()));

Adding custom QWidget during runtime

I'm trying to implement a custom widget hierarchy:
QMainWindow -> QFrame -> MyWidget -> QFrame -> MySubWidget
Here is how MyWidget class looks like:
class MyWidget : public QWidget {
Q_OBJECT
public:
MyWidget(QWidget *parent = 0, ...);
...
public slots:
void SlotFunction(int i);
...
private:
MySubWidget *sub_w;
QFrame *sub_frame;
...
}
If I try to create an MySubWidget during MyWidget constructor, then all MySubWidget elements are shown as intended:
MyWidget::MyWidget (...) : QWidget(parent) {
...
sub_frame = new QFrame(this);
...
sub_w = new MySubWidget(sub_frame); // commented out on a runtime test
}
But if I try to add subwidget during runtime, sub_frame remains blank. I.e. signal reaction:
void MyWidget::SlotFunction(int i) {
sub_w = new MySubWidget(sub_frame); // update, repaint, show and hide methods aren't helphul
}
I know this is an old question, but I was having a very similar issue and it turned out to be a lack of call to the QWidget::show(). Perhaps that was your problem as well?
My question here: Dynamically add instance inherited from QWidget
Cheers.
Are you reaching your function?
At the top of your function before making a new instance of MySubWidget put:
qDebug() << Q_FUNC_INFO;
Is the slot connected properly?
Qt will let you know if it is unable to connect a slot using a runtime warning. Look at the debug output that shows up in Qt Creator and it may mention a reason why the slot was never reached.
Is subframe visible?
If the parent of your object isn't visible, then showing or hiding the child object will only affect it when the parent is shown.
Hope that helps. Good luck.

Using QMDIArea with Qt 4.4.

I'm using the QMdiArea in Qt 4.4.
If a new project is created, I add a number of sub windows to a QMdiArea. I'd like to disallow the user to close a sub window during runtime. The sub windows should only be closed if the whole application is closed or if a new project is created.
How can I do this?
You need to define your own subWindow. create a subclass of QMdiSubWindow and override the closeEvent(QCloseEvent *closeEvent). you can control it by argument. for example:
void ChildWindow::closeEvent(QCloseEvent *closeEvent)
{
if(/*condition C*/)
closeEvent->accept();
else
closeEvent->ignore(); // you can do something else, like
// writing a string in status bar ...
}
then subclass the QMdiArea and override QMdiArea::closeAllSubWindows () like this:
class MainWindowArea : public QMdiArea
{
Q_OBJECT
public:
explicit MainWindowArea(QWidget *parent = 0);
signals:
void closeAllSubWindows();
public slots:
};
// Implementation:
MainWindowArea::closeAllSubWindows()
{
// set close condition (new project is creating, C = true)
foreach(QMdiSubWindow* sub,this->subWindowList())
{
(qobject_cast<ChildWindow*>(sub))->close();
}
}
you may also need to override close slot of your mdi area.
You'd do this the same as for a top-level window: process and ignore the QCloseEvent it sent. QMdiArea::closeActiveSubWindow/QMdiArea::closeAllSubWindows just call QWidget::close, which sends a closeEvent and confirms that it was accepted before proceeding.
You can process this event by subclassing QMdiSubWindow and reimplementing QWidget::closeEvent, or by using an event filter to intercept it..