I have instantiated a widgetClass in MainWindow.cpp. I want to pass in "this" to this widget as more than just (QWidget* parent) but also (MainWindow* parent). But on the build, the widgetClass is established before the MainWindow and so it errors out.
I want to get to instanceVariables in the MainWindow??
ie:
myWidget(QWidget* parent, MainWindow* parent);
There are some issues on such task.. Maybe the problem is that you have to use Forward Declaration to include one class in one other that include the first ones.. Or maybe the fact the default constructor of QWidget has the first argument as the default parameter.. what is your error exactly?
Anyway, here is a complete example:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "mywidget.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
int foo(int n);
private:
Ui::MainWindow *ui;
MyWidget *w;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
w = new MyWidget(this);
this->setCentralWidget(w);
}
MainWindow::~MainWindow()
{
delete ui;
}
int MainWindow::foo(int n)
{
std::cout << "foo" << std::endl;
return n+42;
}
mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
class MainWindow;
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(MainWindow *main, QWidget *parent = 0);
signals:
public slots:
};
#endif // MYWIDGET_H
mywidget.cpp
#include "mywidget.h"
#include "mainwindow.h"
#include <iostream>
MyWidget::MyWidget(MainWindow *main, QWidget *parent) :
QWidget(parent)
{
std::cout << main->foo(0) << std::endl;
}
Does this help?
The answer proposed by nkint is the cleanest way to do. However, there exist quick hacks if you don't have time or can't change the architecture of your software:
If you know for sure that the parent of MyWidget is a QMainWindow, you can simply do:
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent)
{
QMainWindow * main = static_cast<QMainWindow*>(parent);
std::cout << main->foo(0) << std::endl;
}
If you are not sure, i.e. may or may not actually be a QMainWindow, then you can do:
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent)
{
QMainWindow * main = qobject_cast<QMainWindow*>(parent);
// here, main is null if and only if parent was not a QMainWindow
if(main)
std::cout << main->foo(0) << std::endl;
}
qobject_cast is similar to dynamic_cast. More precisely, the documentation says:
The qobject_cast() function behaves similarly to the standard C++ dynamic_cast(), with the advantages that it doesn't require RTTI support and it works across dynamic library boundaries.
qobject_cast() can also be used in conjunction with interfaces; see the Plug & Paint example for details.
Warning: If T isn't declared with the Q_OBJECT macro, this function's return value is undefined.
Related
So, I have the source code for a training. Where I want to do operation with QGraphicsView named pp in the own class ProcessPicture.
I would ask you, is it possible to put the QGraphicsView object to the method of own class? If yes, please tell me how or lead me on answer.
For a detailed description after releasing button will done the on_processPic_pushButton_released() where is called the method of pp object. This method take a ui->graphicsview as argument. This argument will used in the pp.drawrectangle(ui->graphicsview).
The code is without error or warning, only it is not draw the rectangle to the ui->graphicsview. When I take a source code from pp.drawrectangle() and try it, in the on_processPic_pushButton_released() all is fine. So I think that i miss some knowledge.
Lets look on my source code.
processpicture.h
#ifndef PROCESSPICTURE_H
#define PROCESSPICTURE_H
#include "QString"
#include "QPicture"
#include "QGraphicsView"
class ProcessPicture
{
public:
ProcessPicture();
void draw(QGraphicsView out);
void draw_rectangle(QGraphicsView out);
private:
QString path = "***/Untitled.bmp";
QImage img;
};
#endif // PROCESSPICTURE_H
processpicture.cpp
#include "processpicture.h"
#include "QGraphicsScene"
#include "QGraphicsPixmapItem"
ProcessPicture::ProcessPicture()
{
img.load(path);
}
void ProcessPicture::draw_rectangle(QGraphicsView out){
//QGraphicsScene* scene = new QGraphicsScene();
QGraphicsScene scene;
QRect rect;
rect.setRect(10,10,10,10);
scene.addRect(rect);
out.setScene(&scene);
out.show();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "processpicture.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
ProcessPicture *pp;
//pp = new ProcessPicture;
~MainWindow();
private:
private slots:
void on_processPic_pushButton_released();
private:
Ui::MainWindow *ui;
bool event(QEvent *event);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
pp = new ProcessPicture;
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_processPic_pushButton_released()
{
//pp->draw(ui->graphicsView);
pp->draw_rectangle(ui->graphicsView);
}
For every non-toxic answer I thank.
I try to switch between two different Widgets in QT5.
The first problem was that my first window was visible in the background of my second window. I solve this with a check in "autoFillBackground". Now i can switch between them, but if i resize them it only resize the Main content.
Both Widgets have a grid layout.
Resize Problem
Im new at QT5, so is there a better way to make a switching between 2 widgets without this problem?
I try it with wMessages = new Messages(); and hide() but then my program crash after going back.
Code:
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "messages.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_btnMessages_clicked();
private:
Ui::MainWindow *ui;
Messages *wMessages;
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_btnMessages_clicked()
{
wMessages = new Messages(this);
wMessages->show();
}
messages.h:
#ifndef MESSAGES_H
#define MESSAGES_H
#include <QWidget>
namespace Ui {
class Messages;
}
class Messages : public QWidget
{
Q_OBJECT
public:
explicit Messages(QWidget *parent = nullptr);
~Messages();
QString NewsGenerator();
private slots:
void on_bBack_clicked();
void on_pushButton_clicked();
private:
Ui::Messages *ui;
};
#endif // MESSAGES_H
messages.cpp:
#include "messages.h"
#include "ui_messages.h"
Messages::Messages(QWidget *parent) :
QWidget(parent),
ui(new Ui::Messages)
{
ui->setupUi(this);
}
Messages::~Messages()
{
delete ui;
}
void Messages::on_bBack_clicked()
{
this->close();
QWidget *parent = this->parentWidget();
parent->show();
}
Edit 1 - working Main Window Button (from G.M.´s answer):
void MainWindow::on_btnMessages_clicked()
{
wPlaner = new Planer();
QMainWindow::setCentralWidget(wPlaner);
}
Update (based on the comments):
The best solution was to use the QStackedWidget to navigate between the views.
Docu: https://doc.qt.io/qt-5/qstackedwidget.html#details
Example-Code for Button:
// return back to first view
void MainWindow::on_btnret_clicked()
{
ui->stackedWidget->setCurrentIndex(0);
}
I don't get it.
loginview.h
#ifndef LOGINVIEW_H
#define LOGINVIEW_H
#include <QMainWindow>
#include <QDebug>
#include <QPushButton>
class LoginView : public QWidget
{
public:
QWidget *LoginViewSetup(QWidget * wdgMain);
public slots:
virtual void LogInUser();
virtual void CreateUser();
public:
QPushButton *logInBtn;
QPushButton *createBtn;
};
#endif // LOGINVIEW_H
loginview.cpp
#include "loginview.h"
QWidget *LoginView::LoginViewSetup(QWidget * wdgMain)
{
//some code
return wdgCenter;
}
void LoginView::LogInUser()
{
//some code
}
void LoginView::CreateUser()
{
//some code
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <loginview.h>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
QWidget * wdgMain;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
wdgMain = new QWidget(this);
LoginView LoginViewObj;
QWidget *wdgCenter = LoginViewObj.LoginViewSetup(wdgMain);
setCentralWidget( wdgMain );
connect(LoginViewObj.createBtn, SIGNAL (released()), &LoginViewObj, SLOT (CreateUser()));
}
MainWindow::~MainWindow()
{
delete ui;
}
Problem:
QObject::connect: No such slot QWidget::CreateUser() in
../proj/mainwindow.cpp:16
I tried to add Q_OBJECT to the loginview.h and then rebuild project with QMAKE. After that there is no warning about slot, but buttons still not active. Program don't jump to handle of the button in debug mode.
Please, help me to understand what's wrong? I have an object of another class LoginView and I pass this object as a reciever for a slot. Why it passes through my class and searches slot in QWidget?
I am trying to call a method called display_txt() from my_class. This method is supposed to change some text in a label. But the method doesn't make any changes to the ui. I know the method runs due to the qDebug(). No errors occur, but the label just doesn't change to "text changed". display_txt() works fine and changes the label when called from the main widget class. There is a similar question in the forums but I couldn't use those solutions. I make an object when the button btn is pressed.
Here is the code:
widget.h
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
void display_txt();
private slots:
void on_btn_clicked();
private:
Ui::Widget *ui;
};
my_class.h
#include <QWidget>
#include "widget.h"
class my_class : public QWidget
{
Q_OBJECT
public:
explicit my_class(QWidget *parent = 0);
void test(Ui::Widget ui1);
signals:
private:
Widget *wo = new Widget;
};
Widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include "my_class.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//display_txt();
qDebug() << "Widget object created";
}
void Widget::display_txt(){
ui->lbl->setText("text changes!!!!!");
qDebug() << "display_txt() method finished";
}
void Widget::on_btn_clicked()
{
my_class mc;
}
my_class.cpp
#include "my_class.h"
#include "QDebug"
my_class::my_class(QWidget *parent) : QWidget(parent)
{
qDebug() << "myclass ran";
wo->display_txt();
}
I am trying to connect a signal from a second QMainWindow to the mainwindow. It doesn't say anything about a problem connection when the program is launched, but It doesn't work. I am not very familiar with C++ and Qt so maybe is something simple.
My code consists on a Mainwindow used as a SCADA with Start, stop, On, off buttons. In the second qmainwindow I created a terminal where you can type, start,stop... There, I would like to emit a signal to my MainWindow which is in charge of controlling the multiple threads and windows. The problem is that I cannot connect to my slot. I present here a simple overview of this two pieces of code.
Terminal. h
#ifndef TERMINAL__H
#define TERMINAL__H
#include <QMainWindow>
#include <QTextEdit>
#include <QLineEdit>
#include <QObject>
namespace Ui {
class Terminal_;
}
class Terminal_ : public QMainWindow
{
Q_OBJECT
public:
explicit Terminal_(QWidget *parent = 0);
~Terminal_();
signals:
void turnonPLC_terminal();
public slots:
void newline();
private:
Ui::Terminal_ *ui;
QTextEdit* mTerminal;
QLineEdit* mInput;
};
#endif // TERMINAL__H
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "terminal_.h"
#include "terminal_help.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
Terminal_ *terminal;
public slots:
void turnon_terminal();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "terminal_.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
terminal = new Terminal_(this);
connect(terminal, SIGNAL(turnonPLC_terminal()), this, SLOT(turnon_terminal()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::turnon_terminal(){
turnonPLC=1;
}
terminal_.cpp
#include "terminal_.h"
#include "ui_terminal_.h"
#include <QDockWidget>
#include <QWidget>
#include <QLineEdit>
QString on=("on");
Terminal_::Terminal_(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Terminal_)
{
ui->setupUi(this);
mTerminal = new QTextEdit();
setCentralWidget(mTerminal);
mInput = new QLineEdit();
QDockWidget* qdw = new QDockWidget;
qdw->setWidget(mInput);
addDockWidget(Qt::BottomDockWidgetArea, qdw);
connect (mInput, SIGNAL(returnPressed()),
this, SLOT(newline()));
}
Terminal_::~Terminal_()
{
delete ui;
}
void Terminal_::newline(){
QString command = mInput->text();
if (command==on){
emit turnonPLC_terminal();
}
}
Thanks
The signal-slots part in the code works perfectly. (compiled and tested with some small modifications)
After entering "on" (not On as written in question)
Terminal_::newline() slot called, turnonPLC_terminal() is fired and finally
void MainWindow::turnon_terminal() is called.
However, there are some small details the header file is called terminal_.h, not Terminal.h turnonPLC is not defined. terminal is created by not displayed (no show-call).
I guess, there are simply some many small logic errors. Try to use debugger or trace the chain of expected calls with qDebug.