Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Weird problem, with MainWindow class variables.



  • So i have two separate classes. MainWindow and my own class. When i try to access MainWindow variables from my own class, i will face up some problem. Either i have method, which returns private variable from MainWindow to my own class or i try to access it when variable is public. Problem is that, the return i get, is very unrealistic. I have two variables in MainWindow class, which ones are equal to two QSlider value.

    Here are defined variables at MainWindow class

    @
    private:
    int imageWidth;
    int imageHeight;
    @

    I have 2 slots, which act, when QSliders values are changed

    @void MainWindow::on_WidthSlider_valueChanged(int value)
    {
    imageWidth = value;
    QString valueString = QString::number(value);
    ui->WidthLabel->setText(valueString);
    }

    void MainWindow::on_HeightSlider_valueChanged(int value)
    {
    imageHeight = value;
    QString valueString = QString::number(value);
    ui->HeightLabel->setText(valueString);
    }@

    Here are two methods, which one should "return" these variable values.

    @
    void MainWindow::GetImageHeight(int &height) {height = imageHeight;}

    void MainWindow::GetImageWidth(int &width) {width = imageWidth; }@

    And here is the part, how i try to access them.

    @
    MainWindow mw;
    int width, height;

    mw.GetImageHeight(height);
    mw.GetImageWidth(width);
    

    @

    PROBLEM is that, i always get wrong results. If MainWindow instance are defined as variable, then methods return 0. If they are defined as pointers, then they return -842150451. I cannot find solution to my problem, i hope someone can help me.



  • Do you connected QSlider::valueChanged(int) signal to your MainWindow::on_WidthSlider_valueChanged(int) and MainWindow::on_HeightSlider_valueChanged(int) slots?



  • Yeah, i also debugged that, is the on_HeightSlider_valueChanged(int) parameter value correct and yes it is.



  • What relations between your own class and MainWindow? May be you could create signals-slots communications between both classes.



  • This is my implementation, for example:

    mainwindow.h
    @class MainWindow : public QMainWindow
    {
    Q_OBJECT

    public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    signals:
    void heightValueChanged(int value);
    void widthValueChanged(int value);

    private slots:
    void widthSliderChanged(int value);
    void heightSliderChanged(int value);

    private:
    Ui::MainWindow *ui;

    int _imageHeight;
    int _imageWidth;
    

    };@

    mainwindow.cpp
    @MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    _imageHeight(0),
    _imageWidth(0)
    {
    ui->setupUi(this);

    connect(ui->heightlSlider, SIGNAL(valueChanged(int)), this, SLOT(heightSliderChanged(int)));
    connect(ui->widthSlider, SIGNAL(valueChanged(int)), this, SLOT(widthSliderChanged(int)));
    

    }

    MainWindow::~MainWindow()
    {
    delete ui;
    }

    void MainWindow::widthSliderChanged(int value)
    {
    if (_imageWidth == value)
    return;

    _imageWidth = value;
    emit widthValueChanged(_imageWidth);
    

    }

    void MainWindow::heightSliderChanged(int value)
    {
    if (_imageHeight == value)
    return;

    _imageHeight = value;
    emit heightValueChanged(_imageHeight);
    

    }@

    ownclass.h
    @class Own : public QWidget
    {
    Q_OBJECT

    public:
    Own(QWidget *parent = 0);

    public slots:
    void imageHeight(int value);
    void imageWidth(int value);
    };
    @

    ownclass.cpp
    @Own::Own(QWidget *parent) :
    QWidget(parent)
    {

    }

    void Own::imageHeight(int value)
    {
    qDebug() << QString::number(value);
    }

    void Own::imageWidth(int value)
    {
    qDebug() << QString::number(value);
    }@

    main.cpp
    @int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    MainWindow w;
    Own own;

    QObject::connect(&w, SIGNAL(heightValueChanged(int)), &own, SLOT(imageHeight(int)));
    QObject::connect(&w, SIGNAL(widthValueChanged(int)), &own, SLOT(imageWidth(int)));
    
    w.show();
    
    return a.exec&#40;&#41;;
    

    }@



  • QSlider valueChanged are already connected to on_WidthSlider_valueChanged(int value) and on_HeightSlider_valueChanged(int value)



  • I ran into something similar to this recently when trying to update a value by reference. In my case it was done this way for a very different reason but otherwise it was similar to what you are doing.

    I would suggest you re-write your access functions like this:

    @
    int MainWindow::GetImageHeight(void) {return imageHeight;}
    int MainWindow::GetImageWidth(void) {return imageWidth; }
    @

    You can use them like this:

    @
    MainWindow mw;
    int width, height;

    height = mw.GetImageHeight();
    width = mw.GetImageWidth();
    

    @



  • I have already tried this.



  • In your code you have this:

    @
    QApplication a(argc, argv);
    MainWindow w;
    Own own;
    ...
    @

    These exist only in main() which will run until a.exec() returns. For the classes 'w' and 'own' is there a pointer, or some other reference to these classes that you can use outside of main()?

    For this code:

    @
    MainWindow mw;
    int width, height;

        height = mw.GetImageHeight();
        width = mw.GetImageWidth();
    

    @

    GetImageHeight() and GetImageWidth() should return zero or possibly some other random value as it is another, unrelated class.



  • Sorry, i don't understand, what you are trying to say to me.



  • In your example (below), are you trying to get width and height from MainWindow before app.exec() ?
    @
    MainWindow mw;
    int width, height;

        mw.GetImageHeight(height);
        mw.GetImageWidth(width);
    

    @

    If so then MainWindow::imageHeight and imageWidth are not initialized and you are getting whatever random numbers are there.



  • No, im not trying to get them before app.exec()
    getImageHeight and getImageWidth are exectued after i press a button on my form and long proccess is done with network communication is done



  • I post my full source code here

    mainwindow.h
    @
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H

    #include <QMainWindow>
    #include "networking.h"
    namespace Ui {
    class MainWindow;
    }

    class MainWindow : public QMainWindow
    {
    Q_OBJECT

    public:

    explicit MainWindow(QWidget *parent = 0);
    void GetImageHeight(int &height);
    void GetImageWidth(int &width);
    
    ~MainWindow();
    

    private slots:

    void on_pushButton_clicked();
    void on_WidthSlider_valueChanged(int value);
    void on_HeightSlider_valueChanged(int value);
    

    private:
    int imageWidth;
    int imageHeight;

    QUrl q;
    Ui::MainWindow *ui;
    

    };

    #endif // MAINWINDOW_H

    @

    networking.h

    @
    #ifndef NETWORKING_H
    #define NETWORKING_H

    #include <QtNetwork/QNetworkAccessManager>
    #include <QtNetwork/QNetworkRequest>
    #include <QMessageBox>
    #include "mainwindow.h"

    class networking : public QObject
    {
    Q_OBJECT

    public:
        networking();
    
        void on_download_triggered(QUrl url);
        bool IsNetworkAvailable();
    
    
    private:
        QNetworkAccessManager *manager = new QNetworkAccessManager(this);
        void ProcessPicture(QImage *image);
    

    private slots:
    void onNetworkReply(QNetworkReply* reply);

    };

    #endif // NETWORKING_H

    @

    mainwindow.cpp

    @#include "mainwindow.h"
    #include "ui_mainwindow.h"

    MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {

    ui->setupUi(this);
    this->setFixedSize(378, 304);
    

    }

    MainWindow::~MainWindow()
    {
    delete ui;
    }

    void MainWindow::on_pushButton_clicked()
    {

    if(ui->URLbox->text().isEmpty()) QMessageBox::information(0, "Warning", "No URL inserted!");
    
    else
    {
        networking *n = new networking();
        q = ui->URLbox->text();
        if(n->IsNetworkAvailable()) n->on_download_triggered(q);
    }
    

    }

    void MainWindow::GetImageHeight(int &height) {height = imageHeight;}

    void MainWindow::GetImageWidth(int &width) {width = imageWidth; }

    void MainWindow::on_WidthSlider_valueChanged(int value)
    {
    imageWidth = value;
    QString valueString = QString::number(value);
    ui->WidthLabel->setText(valueString);
    }

    void MainWindow::on_HeightSlider_valueChanged(int value)
    {
    imageHeight = value;
    QString valueString = QString::number(value);
    ui->HeightLabel->setText(valueString);
    }

    @

    networking.cpp

    @#include "networking.h"
    #include <QtNetwork/QNetworkReply>
    #include <QFileDialog>

    networking::networking()
    {
    connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onNetworkReply(QNetworkReply*)));
    }
    void networking::on_download_triggered(QUrl url)
    {
    manager->get(QNetworkRequest(QUrl(url)));
    }

    void networking::ProcessPicture(QImage *image)
    {
    MainWindow *mw = new MainWindow();

    int width, height;
    
    mw->GetImageHeight(height);
    mw->GetImageWidth(width);
    
    
    qDebug() << height;
    qDebug() << width;
    
    QImage newimage = image->scaled(width, height, Qt::KeepAspectRatio);
    QString path =  QFileDialog::getSaveFileName(0, tr("Save Image"), "C://", tr("Image Files (*.png *.jpg *.bmp)"));
    
    newimage.save(path);
    

    }

    void networking::onNetworkReply(QNetworkReply* reply)
    {
    if(!reply->error())
    {
    QImage *img = new QImage();
    img->loadFromData(reply->readAll());

        if(img->isNull())
                QMessageBox::critical(0, "Error", "Inserted URL is not an image!");
    
        ProcessPicture(img);
    
    }
    else
    {
        QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
        int status = statusCode.toInt();
    
        qDebug() << status;
    
        switch(status)
        {
            case 0:
            {
                QMessageBox::critical(0, "Error", "URL doesn't exist!");
                break;
            }
            case 404:
            {
                QMessageBox::critical(0, "Error", "404 not found!");
                break;
            }
        }
    }
    

    }

    bool networking::IsNetworkAvailable()
    {
    QNetworkAccessManager m;
    QNetworkReply *check = m.get(QNetworkRequest(QUrl("google.com")));
    return (!check->error()) ? true : false;
    }
    @



  • I think this is your problem:

    @
    void networking::ProcessPicture(QImage *image)
    {
    MainWindow *mw = new MainWindow();

    int width, height;
    
    mw->GetImageHeight(height);
    mw->GetImageWidth(width);
    
    qDebug() << height;
    qDebug() << width;
    

    ...
    }
    @

    The class '*mw' is unrelated to the mw class created in main(). The member imageWidth and imageHeight are not updated in this version.

    To verify this you could create a global pointer of the MainWindow class and see if this solves the problem:

    @
    MainWindow *g_mw;

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        Own own;
    
        g_mw = &mw;
    
     
        QObject::connect(&w, SIGNAL(heightValueChanged(int)), &own, SLOT(imageHeight(int)));
        QObject::connect(&w, SIGNAL(widthValueChanged(int)), &own, SLOT(imageWidth(int)));
     
        w.show();
     
        return a.exec&#40;&#41;;
    }
    

    @

    and then in your network module

    @
    #include "networking.h"
    #include <QtNetwork/QNetworkReply>
    #include <QFileDialog>

    extern MainWindow *g_mw;

    networking::networking()
    {
    ...
    }
    ...
    void networking::ProcessPicture(QImage *image)
    {
    // MainWindow *mw = new MainWindow();

    int width, height;
    
    g_mw->GetImageHeight(height);
    g_mw->GetImageWidth(width);
    
    
    qDebug() << height;
    qDebug() << width;
    

    ...
    }
    @

    Note: I wouldn't use a global variable like this. You are better to pass a pointer (maybe as part of the constructor of your Networking class?). It is just a simple way to verify this is the problem without changing too much.



  • Rondog is right. You are creating new MainWindow object and it is not related to your main MainWindow.

    Another option to solve it would be to pass a MainWindow pointer to networking ctor and keep it there. Then in networking::ProcessPicture() use that pointer.
    networking.h

    @
    #ifndef NETWORKING_H
    #define NETWORKING_H

    class MainWindow;
     
    class networking : public QObject
    {
    

    ...
    public:
    networking(MainWindow* mw);

    ...
    private:
    MainWindow* m_mw;

    };
    #endif // NETWORKING_H
    

    @

    networking.cpp
    @
    #include "networking.h"
    #include "MainWindow.h"
    #include <QtNetwork/QNetworkReply>
    #include <QFileDialog>

    networking::networking(MainWindow* mw) : m_mw(mw)
    {
    

    ...
    }

    void networking::ProcessPicture(QImage *image)
    {
    // MainWindow *mw = new MainWindow();

    int width, height;
    
    m_mw->GetImageHeight(height);
    m_mw->GetImageWidth(width);
    
    
    qDebug() << height;
    qDebug() << width;
    

    ...
    }
    @



  • Thanks, it worked! I didn't know, why i didn't realise fault myself. Quite logical. Thanks again!



  • One last question, why i had to write class MainWindow; to my networking.h file.



  • It is a forward declaration. Compiler needs to know that a type exists but does not need to know the details. It works with the pointers and the references. Helps to avoid including unneeded headers.


Log in to reply