[C++] [QT] Object door geven aan andere objecten.

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • SnowDude
  • Registratie: Januari 2002
  • Nu online
Ik ben een klein programma aan het schrijven in C++/QT maar ben een beetje de weg kwijt met het doorgeven van objecten naar andere objecten. Althans, ik wil een referentie doorgeven zodat ik geen global object hoef te gebruiken. Ik ben wel redelijk weg wijs in simpele C code maar dit groeit me even boven me pet, misschien dat hier iemand me wat tips of aanwijzingen kan geven. En misschien zit ik ook wel in een verkeerde oplossing te denken.

Het vereenvoudigde probleem is dit:

Ik heb een Raspberry Pi met daar op aangesloten een I2C thermometer en een I2C pwm boardje.

Ik wil 1 object aan maken met daarin de status van de in en uitgangen, wat configuratie gegevens en de code om de uitgangen te sturen. Omdat de sensoren gepold moeten worden wil ik met een timer om de x (mili) seconden een functie aanroepen in het object om de sensoren uit te lezen en op te slaan in waardes in het object. Ik wil dit object (uiteraard geen kopie!) kunnen gebruiken binnen een ander object, als voorbeeld hier een object van een dialog window, alleen gaat dit uiteraard fout want de SetPWM wordt gedaan in localIOobject en niet in IOmainWindow.

Hoe kan ik dit het beste en netste doen?
In een latere versie wil ik misschien nog wat processen gaan multi-threaden en hoewel dat echt een gevorderde oefening is voor later is het misschien wel handig om daar nu al rekening mee te houden.


C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//main.cpp
#include <QApplication>
#include "mainwindow.h"
#include "MyIOClass.h"

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

    MainWindow w();
    w.show();
    
    return a.exec();
}


C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "MyIOClass.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT    
    MyIOClass IOmainWindow;

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

private slots:

    void on_pushButton_3_clicked();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H


C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "MyIOClass.h"

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

    ui->setupUi(this);
    connect(ui->verticalSlider,SIGNAL(valueChanged(int)), &IOmainWindow,SLOT(SetPWM0(int)));
}

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

void MainWindow::on_pushButton_3_clicked()
{
    ConfigDialog ConfDialog(IOmainWindow);
    ConfDialog.setModal(true);
    ConfDialog.exec();
}


C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//ConfigDialog.h
#ifndef CONFIGDIALOG_H
#define CONFIGDIALOG_H

#include <QDialog>
#include "MyIOClass.h"

namespace Ui {
class ConfigDialog;
}

class ConfigDialog : public QDialog
{
    Q_OBJECT
    MyIOClass localIOobject;
    
public:
    explicit ConfigDialog(MyIOClass IOobject, QWidget *parent = 0);
    ~ConfigDialog();
    
private:
    Ui::ConfigDialog *ui;
    void ConfigDialog::on_pushButton_2_clicked();

};

#endif // CONFIGDIALOG_H


C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//ConfigDialog.cpp
#include "configdialog.h"
#include "ui_configdialog.h"
#include "MyIOClass.h"


ConfigDialog::ConfigDialog(MyIOClass IOobject, MyQWidget *parent) :
    QDialog(parent),
    ui(new Ui::ConfigDialog)
{
    localIOobject = IOobject;
    ui->setupUi(this);
}


void ConfigDialog::on_pushButton_2_clicked()
{
    localIOobject.SetPWM(0,4000);
}


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

All electric components run on smoke. If you let the smoke out, they won't work anymore.


Acties:
  • 0 Henk 'm!

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 11-10 06:48

Gerco

Professional Newbie

Het ziet er naar uit dat je pass-by-value gebruikt om de IOmainWindow door te geven aan de ConfigDialog:
C++:
1
2
3
4
ConfigDialog::ConfigDialog(MyIOClass IOobject, MyQWidget *parent) :
    QDialog(parent),
    ui(new Ui::ConfigDialog)
{


Nu maak je een kopie van je object en zijn IOmainWindow en localIOObject verschillende instances van dezelfde class. Wat je wilt is een pointer doorgeven, of eigenlijk een reference:
Passing arguments by reference

Je moet in ConfigDialog de variabele declareren als een reference (zie link hierboven) en de constructor argument ook veranderen naar een reference. Wanneer je dan vervolgens een instance van ConfigDialog aanmaakt krijgt die een reference naar de bestaande MyIOClass instance in plaats van een kopie.

[ Voor 18% gewijzigd door Gerco op 08-10-2015 01:48 ]

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 12-10 23:30
Ik denk dat je je moet afvragen of het MainWindow wel de eigenaar moet zijn van het IO object : misschien moet het wel een global zijn omdat je er vanaf meerdere plekken goed bij moet kunnen. Heb je bijvoorbeeld perse het MainWindow nodig om de IO te kunnen manipuleren, of is het mogelijk om er al iets mee te doen voordat het MainWindow gemaakt wordt?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • jeroen3
  • Registratie: Mei 2010
  • Laatst online: 14:32
Gebruik de model-view relatie die qt heeft. Hoewel het waarschijnlijk boven je pet gaat (en te complex is voor zoiets simpels), kun je het concept wel gebruiken.

Je maakt een ConfigDialog voor je MyIOClass, en als je het venster met de parameters van je object pas nodig hebt. Dan maak je hem aan. In de constructor van je ConfigDialog maak je een pointer naar een instantie van MyIOClass (en de parent QObject niet vergeten), en als het venster weer sluit breek je de connecties weer af, en ruim je ConfigDialog weer op.

De model-view relatie staat het toe om data en ui gescheiden te houden. Ipv een onbegrijpelijke spaghetti met event handlers te creëren.
http://doc.qt.io/qt-5/qtquick-modelviewsdata-modelview.html

[ Voor 16% gewijzigd door jeroen3 op 08-10-2015 11:18 ]


Acties:
  • 0 Henk 'm!

  • SnowDude
  • Registratie: Januari 2002
  • Nu online
Ik ben toch lui geweest en heb de makkelijke weg gekozen. Ik wilde het object in meerdere andere objecten gebruiken, en heb hem dus toch maar global gemaakt.

All electric components run on smoke. If you let the smoke out, they won't work anymore.


Acties:
  • 0 Henk 'm!

  • ATS
  • Registratie: September 2001
  • Laatst online: 29-09 11:31

ATS

Er gaan diverse dingen fout:

In de constructor van MainWindow maak je een MyIOClass instance op de stack, waarna je een signal-slot connection maakt. Maar zodra je instance out of scope gaat (de constructor is klaar) wordt je instance weer vernietigd (de disconnect is automatisch). Dat wil je dus niet. Persistente objecten maak je in Qt bij voorkeur aan op de heap.

Je oorpronkelijke probleem gaat nog ietsje verder. Uit het feit dat je een connect doet met een MyIOClass instance blijkt dat het een QObject is. Deze kan je niet kopieren, en dus ook niet by-value doorgeven. Dat zal je dus by-pointer moeten doen. Settings wil je echter vaak soort-van globaal toegankelijk hebben. Daarvoor zijn een aantal opties, waaronder een singleton of een instance aanmaken als child van je QApplication object (dat is al een singleton). Globals hebben een probleem dat je geen controle hebt over de initialisatievolgorde*. Dat kan problemen opleveren en raad ik dus af!

Meer tips:
Gebruik de nieuwe connect syntax, niet de oude string-gebaseerde voor nieuwe code. Dan krijg je compile-time checking en snellere evaluatie (en de optie om een connect naar een lambda te doen bijvoorbeeld, heel handig).

Gebruik slots met een behoorlijke naam die gaan over wat ze doen, niet over in respons waarvan ze getriggered worden. Dus geen on_PushButton_3_triggered maar showConfigurationDialog of zoiets. Gebruik tegelijk ook goede namen voor je objecten, vooral in de UI. Dus geen PushButton2 maar bijvoorbeeld cmdResetPwm.

UI instances kan je heel mooi in een QScopedPointer verpakken. Kan je ook de delete niet vergeten in je destructor...

Gebruik liever geen exec() of andere 'blocking' methods (waitFor... methods bijvoorbeeld). Voor dialogs gebruik je liever open().

Private slots zijn niet zo heel erg private: ze zijn nog steeds callable via de QMetaObject API. Beter gebruik je lambda's (die wellicht een private method callen).


*) En nog vele andere problemen...


Ps: het is Qt, niet QT. QT is QuickTime.

[ Voor 3% gewijzigd door Creepy op 12-10-2015 13:09 . Reden: Ont-spammed.... ]

My opinions may have changed, but not the fact that I am right. -- Ashleigh Brilliant


Acties:
  • 0 Henk 'm!

  • SnowDude
  • Registratie: Januari 2002
  • Nu online
ATS schreef op vrijdag 09 oktober 2015 @ 15:50:
[...]

Meer tips:
Gebruik de nieuwe connect syntax, niet de oude string-gebaseerde voor nieuwe code. Dan krijg je compile-time checking en snellere evaluatie (en de optie om een connect naar een lambda te doen bijvoorbeeld, heel handig).

Gebruik slots met een behoorlijke naam die gaan over wat ze doen, niet over in respons waarvan ze getriggered worden. Dus geen on_PushButton_3_triggered maar showConfigurationDialog of zoiets. Gebruik tegelijk ook goede namen voor je objecten, vooral in de UI. Dus geen PushButton2 maar bijvoorbeeld cmdResetPwm.
Dank je, mijn probleem is ook dat ik ten eerste geen echte programmeur ben, en de programmeer ervaring die ik heb zijn in C, Pascal en assembly. Het OOP deel heb ik dan ook nog veel moeite mee.

De nieuwe connect syntax werkt toch alleen vanaf Qt5? De laatste build die ik kon vinden voor de Raspberry Pi was 4.8. Ik kan nog steeds geen goede build (guide) vinden voor Qt5 en QtCreator 3.5. Aangezien het compilen van Qt5.5 al 12 uur duurt heb ik dat na 3 keer proberen opgegeven.

All electric components run on smoke. If you let the smoke out, they won't work anymore.


Acties:
  • 0 Henk 'm!

  • ATS
  • Registratie: September 2001
  • Laatst online: 29-09 11:31

ATS

Ja, die syntax is Qt5 only. Ik wist niet dat je nog op 4.8 zat. Compileren hoeft geen 12 uur te duren, vooral niet als je even de moeite neemt om te configureren wat je wel en niet nodig hebt. Maar weet je zeker dat hij niet te vinden is? 4.8 is in december EOL. Vooral webkit is trouwens eentje die je wil slippen met compileren als je het niet nodig hebt. Als je een slicke ui wil zou ik je adviseren ook naar QML en QtQuick te kijken. Dat is echt heel eenvoudig specificeren.

My opinions may have changed, but not the fact that I am right. -- Ashleigh Brilliant


Acties:
  • 0 Henk 'm!

  • SnowDude
  • Registratie: Januari 2002
  • Nu online
ATS schreef op vrijdag 09 oktober 2015 @ 19:40:
Ja, die syntax is Qt5 only. Ik wist niet dat je nog op 4.8 zat. Compileren hoeft geen 12 uur te duren, vooral niet als je even de moeite neemt om te configureren wat je wel en niet nodig hebt. Maar weet je zeker dat hij niet te vinden is? 4.8 is in december EOL. Vooral webkit is trouwens eentje die je wil slippen met compileren als je het niet nodig hebt. Als je een slicke ui wil zou ik je adviseren ook naar QML en QtQuick te kijken. Dat is echt heel eenvoudig specificeren.
Qt5 is wel te vinden maar QtCreator 3.5 nog niet. Het builden duurt zo lang omdat ik build op de Raspberry Pi zelf, die is niet zo rap als mijn pc

All electric components run on smoke. If you let the smoke out, they won't work anymore.


Acties:
  • 0 Henk 'm!

  • ATS
  • Registratie: September 2001
  • Laatst online: 29-09 11:31

ATS

Waarom zou je in hemelsnaam compileren op de Pi zelf? Je kan toch gewoon crosscompilen op je PC?

Creator heb je al helemaal niet nodig op je Pi. Die zet je gewoon op je PC en verwijs ja naar welke binaries hij moet gebruiken.

My opinions may have changed, but not the fact that I am right. -- Ashleigh Brilliant


Acties:
  • 0 Henk 'm!

  • SnowDude
  • Registratie: Januari 2002
  • Nu online
ATS schreef op maandag 12 oktober 2015 @ 13:07:
Waarom zou je in hemelsnaam compileren op de Pi zelf? Je kan toch gewoon crosscompilen op je PC?

Creator heb je al helemaal niet nodig op je Pi. Die zet je gewoon op je PC en verwijs ja naar welke binaries hij moet gebruiken.
Mijn PC is Windows, en heb geen ruimte op mijn boot disk om daar ook nog linux naast te booten. Daarom werk ik op de Pi.

Het begon ook als een klein projectje maar omdat dat nu wat uit de hand gelopen is heb je wel een punt en moet ik eens gaan kijken hoe ik dit fatsoenlijk kan aanpakken.

Kan ik dat het beste doen op een linux pc? Wat dat kan ik wel onder VMware draaien.
Kan ik dan nog steeds debuggen op mijn PC?

All electric components run on smoke. If you let the smoke out, they won't work anymore.


Acties:
  • 0 Henk 'm!

  • jeroen3
  • Registratie: Mei 2010
  • Laatst online: 14:32
SnowDude schreef op maandag 12 oktober 2015 @ 13:39:
[...]
Mijn PC is Windows, en heb geen ruimte op mijn boot disk om daar ook nog linux naast te booten.
Voor https://www.virtualbox.org/ met http://lubuntu.net/ is vast wel plek.
Pagina: 1