How can I connect two windows in Qt? - c++

I am trying make window with chat, and "main" window. If I click at username in chat window, it should show profile in main window. What's the best way to do something like this?

You should pass pointer to one window class from another and connect them by slots/signals:
class MainWindow
{
Q_OBJECT
...
public slots:
void onUsernameSelected(...);
};
class ChatWindow
{
Q_OBJECT
...
MainWindow *mainWindow;
...
ChatWindow(QObject *parent, MainWindow *mainWindow):
...
mainWindow(mainWindow)
{
connect(this, &ChatWindow::usernameSelected, mainWindow, &MainWindow::onUsernameSelected);
}
};

Related

How to detect that the close button of QWidget is pressed?

I create a new QWidget object and I want to know when the close button is pressed.
I have tried the following code:
pWindow = new QWidget();
connect(pWindow , SIGNAL(triggered()), this, SLOT(processCloseButtonWindowsClicked()));
but it give an error:
no signal triggered of pWindow
How to achieve this?
Cause
QWidget does not have a triggered signal.
Solution
I would suggest you to:
Subclass QWidget and reimplement QWidget::closeEvent
Check QEvent::spontaneous to differentiate between a click of the close button and the call to QWidget::close
According to your app's logic either call QWidget::closeEvent(event); to close the widget, or QEvent::ignore to leave it open
Example
I have prepared an example for you of how to implement the proposed solution:
#include <QMainWindow>
#include <QCloseEvent>
#include <QPushButton>
class FooWidget : public QWidget
{
Q_OBJECT
public:
explicit FooWidget(QWidget *parent = nullptr) :
QWidget(parent) {
auto *button = new QPushButton(tr("Close"), this);
connect(button, &QPushButton::clicked, this, &FooWidget::close);
resize(300, 200);
setWindowTitle("Foo");
}
protected:
void closeEvent(QCloseEvent *event) override {
if (event->spontaneous()) {
qDebug("The close button was clicked");
// do event->ignore();
// or QWidget::closeEvent(event);
} else {
QWidget::closeEvent(event);
}
}
};
class MainWindow : public QMainWindow
{
Q_OBJECT
FooWidget *pWindow;
public:
explicit MainWindow(QWidget *parent = nullptr) :
QMainWindow(parent),
pWindow(new FooWidget()) {
pWindow->show();
}
};
void QWidget::closeEvent(QCloseEvent *event) will be the possible way I would go with.
You can read the documentation here.
Before, check if Qt has a class for what you want to do. Maybe you want to use QDialog instead of QWidget for what you want to achieve.
The following code: suppose you want to delete the widget when the X is clicked and you just want to know when to do something.
Try connecting the signal from the base class QObject of your widget when it is Destroyed:
-Your Widget
-attribute setted to destroy your widget after X(closebotton is clicked) or the close() handler is triggered
-connect the destroyed() signal to whatever slot you want to do something before it is destroyed
pWindow = new QWidget();
pWindow->setAttribute(Qt::WA_DeleteOnClose,true);
connect(pWindow , SIGNAL(destroyed()), this,SLOT(processCloseButtonWindowsClicked()));
for more info:
https://doc.qt.io/qt-5/qwidget.html#close
https://doc.qt.io/qt-5/qobject.html#destroyed

Access MainWindow class members from another class

I googled a lot before writing here. I found a couple of posts but I couldn't quite get them. So I'm starting a new post.
I am developing a simple UI. There is this main class (see below), which is a main dialogue box which is shown when the app is started.
class MainWindow : public QMainWindow
There are few buttons on the MainWindow dialogue box, when I click a button, it hides the MainWindow and opens another QDialog box. This dialogue box is of the class as shown below
class libinsert : public QDialog
I create the libinsert object this way:
void MainWindow::on_pushButton_clicked()
{
this->hide();
libinsert lib; // I create libinsert object this way
lib.setModal(true);
lib.exec();
}
This is libinsert.cpp:
libinsert::libinsert(QWidget *parent) :
QDialog(parent),
ui(new Ui::libinsert)
{
ui->setupUi(this);
}
When the libinsert dialogue box is open, I need to access a socket variable which is a member of class MainWindow. How do I achieve this ?
My main app looks like this:
{
QApplication a(argc, argv);
MainWindow w(sock);
w.show();
return a.exec();
};
Alternatively: in general how are multiple dialogue boxes built, as parent-child relation?
libinsert will not be a child of MainWindow. QDialog-based windows are always top-level windows, regardless of what you pass as their parent when you construct them.
If there will only ever exist a single instance (per process) of MainWindow at any given time, you can give MainWindow a static function which returns a pointer to the window:
class MainWindow : public QMainWindow
{
public:
MainWindow()
{
theWindow = this;
}
virtual ~MainWindow()
{
theWindow = nullptr;
}
static get()
{
return theWindow;
}
static MainWindow *theWindow;
}
MainWindow *MainWindow::theWindow = nullptr;
Your dialogs can then access the main window's members thusly:
MainWindow::get()->someMemberFunction();
A more robust approach is to have libinsert store a pointer to the main window when it is created:
class MainWindow;
class libinsert : public QDialog
{
public:
libinsert(MainWindow *mw)
: mainWindow(mw)
{ ... }
MainWindow *getMainWindow()
{
return mainWindow;
}
MainWindow *mainWindow;
}
When MainWindow creates the dialog, it passes a pointer to itself to the constructor:
void MainWindow::createDialog()
{
libinsert *dialog = new libinsert(this):
}
This approach will work even if there are multiple instances of MainWindow active at the same time.

Qt incorrectly lays widgets on top of each other

In Qt 4.8.5 32-bit and VS2010, I'm trying to create a Window as shown in this screenshot from QtDesigner:
When I run the application, the widgets get laid down on top of each other :
In the Console, I see this :
Does anybody have any idea why this is happening?
Here is my code :
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(){
ui = new Ui::AView();
ui->setupUi(this);
}
~MainWindow();
...
private:
Ui::AView* ui;
}
From the screenshot of QtDesigner, I see that your UI is for a QWidget, but you are applying it to a QMainWindow. This causes the problem, as the handling of main window is different to other widgets.
I don't know of a way to change the base class for a UI file. Maybe the best way is to create a new file, select the mainwindow template, and copy/paste the content from the old file.
Another option would be to have a QWidget, set it up with the UI, and add it as the main window's central widget:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(){
ui = new Ui::AView();
QWidget *wgt = new QWidget;
ui->setupUi(wgt);
this->setCentralWidget(wgt);
}
~MainWindow();
...
private:
Ui::AView* ui;
}
Try this:
class MainWindow : public QMainWindow, public Ui::AView
{
Q_OBJECT
public:
MainWindow(){
setupUi(this);
}
~MainWindow();
}

connect signals on a child widget slot

I have some problems with inheritance in widgets and connecting slots. I have created an abstract Widget which inherits from QWidget. Here is the prototype :
class WidgetParams : public QWidget
{
Q_OBJECT
public:
explicit WidgetParams(QWidget *parent = 0) : QWidget(parent){}
virtual bool paramChanged() = 0;
protected:
bool paramsChanged;
};
Then I created derivated class from WidgetParams, for example WidgetParamsWindows:
class WidgetParamsWindows : public WidgetParams
{
public:
explicit WidgetParamsWindows(QWidget *parent = 0);
virtual bool paramChanged(){return paramsChanged;}
private:
QFormLayout *layout;
QSpinBox *svertical;
QSpinBox *shorizontal;
signals:
public slots:
void changeSomeParam(int value);
};
In WidgetParamsWindows, I have some QSpinBox, QPushButton etc. to adjust the params.
I connect the QSpinBox in WidetParamsWindows like this :
connect(spinbox,SIGNAL(valueChanged(int)),this,SLOT(changeSomeParam(int));
After that, I created a WidgetParamsWindows and put It in a list of WidgetParams, in order to show the correct WidgetParams when the user clicks on it.
But when I tried to change the value in the QSpinBox, nothing change and I have the following message in the console :
QObject::connect: No such slot WidgetParams::changeSomeParam(int)
I don't know why the parent Widget takes the slot, instead of WidgetParamsWindows, do you have any ideas?
There is no Q_OBJECT macro in WidgetParamsWindow, so moc doesn't resolve slot macros, try to add Q_OBJECT in WidgetParamsWindow

Qt, can't display child widget

I have two widgets defined as follows
class mainWindow : public QWidget
{
Q_OBJECT
public:
mainWindow();
void readConfig();
private:
SWindow *config;
QVector <QString> filePath;
QVector <QLabel*> alias,procStatus;
QVector <int> delay;
QGridLayout *mainLayout;
QVector<QPushButton*> stopButton,restartButton;
QVector<QProcess*> proc;
QSignalMapper *stateSignalMapper, *stopSignalMapper, *restartSignalMapper;
public slots:
void openSettings();
void startRunning();
void statusChange(int);
void stopProc(int);
void restartProc(int);
void renew();
};
class SWindow : public QWidget
{
Q_OBJECT
public:
SWindow(QWidget *parent=0);
void readConfig();
void addLine(int);
private:
QVector<QPushButton*> selectButton;
QVector<QLabel*> filePath;
QVector<QLineEdit*> alias;
QSignalMapper *selectSignalMapper;
QVector<QSpinBox*> delay;
QGridLayout *mainLayout;
public slots:
void selectFile(int);
void saveFile();
void addLineSlot();
};
when i create and display SWindow object from mainWindow like this
void mainWindow::openSettings()
{
config = new SWindow();
config->show();
}
everything is ok, but now i need to access the mainWindow from SWindow, and
void mainWindow::openSettings()
{
config = new SWindow(this);
config->show();
}
doesn't display SWindow. How can i display SWindow?
How do i call a function on widget close?
By default a QWidget isn't a window. If it is not a window and you specify a parent, it will be displayed inside the parent (so in your case it is probably hidden by other widgets inside your mainWindow).
Look at windowFlags() too. Or you could make your SWindow inherit from QDialog, depending on what you use it for.
As for calling a function on widget close : you could reimplement closeEvent().
When you do config = new SWindow(this); you're setting the parent of config to be the instance of mainWindow.
This means config is no longer a top-level widget, therefore it won't display outside the mainWindow instance (specifically, it would need to be the central widget or inside the mainWindow instance's layout to be displayed).
EDIT: Sorry - I missed your last question; How do i call a function on widget close
You will want to override the QWidget::closeEvent(QCloseEvent *event) method. This gets called when you close a top-level widget. The most practical thing to do is emit() a signal so that another class can handle it having been closed.
As noted by Leiaz, you can use the windowsFlags flag when you create the widget. It would look like this:
void mainWindow::openSettings()
{
config = new SWindow(this, Qt::window);
config->show();
}
To reimplement the closeEvent:
header:
protected:
virtual void closeEvent ( QCloseEvent * event )
cpp:
void sWindow::closeEvent(QCloseEvent *event)
{
this->parentWidget()->SomeFunction();
qWidget::closeEvent(event);
}
However, its probably better to use signal/slots for your case here. Since you said you want to call the parent's renew method on some button click in sWindow, what you want is to EMIT a signal everytime the button is clicked, and connect this signal in the parent with the parent's refresh slot.
void sWindow::sWindow()
{
...
connect(ui.button, SIGNAL(clicked()), this, SLOT(btnClicked()));
}
void sWindow::btnClicked()
{
// whatever else the button is supposed to do
emit buttonClicked();
}
and in your parent class
void mainWindow::openSettings()
{
config = new SWindow(this, Qt::window);
connect(config, SIGNAL(buttonClicked()), this, SLOT(refresh()));
config->show();
}