Seite 1 von 1

Simulationsgrafik gesteuert updaten

Verfasst: 30. Dezember 2018 22:11
von SimuBit
Hallo liebes Forum,

nach längerem erfolglosen Suchen, wende ich mich nun an Euch. Ich arbeite mich als Hobbyprogrammierer in QT ein und beiße mir gerade an einem vermutlich einfachen Problem die Zähne aus und bin somit sehr dankbar für Hilfe.

Aufgabenstellung:
Im Rahmen eines Simulationsprogramms sollen die Daten einer Matrix (2D,int, Zellenkoordinaten = Darstellungskoordinaten) grafisch als Pixel (z.B. fillrect) dargestellt werden und gesteuert aktualisiert werden können.

3 Ziele:
1) Die Grafik soll wahlweise nach jeder Iteration aktualisiert werden oder
2) Iteration und Grafikupdate erfolgen aufgrund z.B. eines Pushbutton-signals.
3) Endziel: Ein GUI mit der Möglichkeit Parameter zu ändern und der grafischen Darstellung der Simulation (dies soll mit dem Lösungsweg möglich sein)

Zu 2): Bisher ist es mir nur gelungen, in einem weiteren Fenster(mainwindow) den button zu erstellen, ohne Verknüpfung zum paintEvent.

Einfaches Beispiel: Wasser verteilt sich über eine Oberfläche -> Pixel ändern ihre blaue Farbe abhängig von der Wassermenge an ihrem Standort.

Status derzeit:
Derzeit erhalte ich nur eine Grafik nach komplettem Durchlauf (return a.exec(); //QApplication a(argc, argv)) der main, d.h. ich erhalte nur eine Grafik und kann diese nicht mehr ändern. Verwendet wird Qpaint, paintEvent.
Grundsätzlich werden die wesentlichen Objekte (Datenmatrix...) in main erzeugt und ggf. per Referenz an andere Objekte übergeben. Die Grafikdarstellung wird in mainwindow.cpp/.h behandelt. Es ist geplant, die Iterationsschleife ebenfalls in main zu realisieren.

Kann mir bitte jemand die korrekte Vorgehensweise/Ablaufschema/Programmaufbau für die Verwendung von paintevent aufzeigen/skizzieren bzw. ein Beispiel/Tutorial nennen das meinen Fall behandelt. Schlagworte und gute Wissensquellen sind auch sehr gerne gesehen.
Meine eigene Suche hat bisher nicht wirklich hilfreiche Ergebnisse erbracht. Falls es für meine Zielsetzung sinnvollere/einfachere Vorgehensweisen, als QPaint, paintEvent gibt - bitte immer her damit.

Hintergrund:
Ich habe mir die Konstruktion für die grafische Darstellung nach Lektüre verschiedener Quellen zusammengebastelt. Es kommt mir aber so vor, als wenn ich ein Auto mit fünf eckigen Rädern ohne Lenkung gebaut hätte ;-). Den Grafik-Code finde ich noch etwas "unstrukturiert", zumal die Vorlage die meisten Funktionen komplett im header stehen hatte. Ein Versuch dies zu ändern, ist aber bisher gescheitert, was ich mangels Durchblick bisher auf die spezielle Anforderungen des paintEvent(...) geschoben habe.

Vorab vielen Dank für alle konstruktiven Antworten! :-)


*******************
Eigentlich will ich niemandem diesen Code zumuten, aber wenn's hilft...
Detaillierter Ablauf der Grafikerstellung:

main.cpp

Code: Alles auswählen


#include "datenmatrix.h"
#include "mainwindow.h"
#include <QApplication>
#include "stofftransport.h"

int main(int argc, char *argv[])
{
//[...] Erstellung aWichtigeWerte
//Objekte erstellen
    QApplication a(argc, argv);
    DatenMatrix DatenSpeicher(aWichtigeWerte);
    MainWindow Hauptfenster;
    StoffTransport StoffTransportieren;
    MainWidget mw;

//[...] Erstellung und Veränderung der Datenmatrix "DatenSpeicher"

    mw.setGrafikMatrixMW(Hauptfenster.fGrafikerstellen(0,DatenSpeicher, aWichtigeWerte));   
    Hauptfenster.show();	//testweise mit einem Pushbutton
    mw.drawNew();
    mw.show();
    mw.update();

return a.exec();
}
mainwindow.h

Code: Alles auswählen

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "stdafx.h"
#include <iostream>
#include <vector>
#include "datenmatrix.h"

#include <QWidget>
#include <QPainter>
#include <QSlider>
#include <QVBoxLayout>
#include <QApplication>

using std::vector;

typedef std::vector< double > state_type;


namespace Ui {
class MainWindow;
}
//-----------------------------------------------------------------
class MainWindow : public QMainWindow
{
    Q_OBJECT

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

    QVector<QVector<int>> fGrafikerstellen(int ZelldatenArt, DatenMatrix &raDatenmatrix, vector<vector<double>> &raWichtigeWerte);

private:
    Ui::MainWindow *ui;
    QVector<QVector<int>> *paGrafikmatrix = new QVector<QVector<int>>;		
    QVector<QVector<int>> &raGrafikmatrix = *paGrafikmatrix;			
    unsigned short int sGrafikmatrixerstellt = 0;
    unsigned short int DatenSatzAnzahlMax_X;
    unsigned short int DatenSatzAnzahlMax_Y;
    unsigned short int DatensaetzeAnzahl_X;
    unsigned short int DatensaetzeAnzahl_Y;
    unsigned short int AnzahlFarbwerte;
    unsigned short int WelcherWert;
    unsigned short int Naechster;
    vector<unsigned short int> ZellenKoord;
    unsigned short int FarbWert_Rot;
    unsigned short int FarbWert_Gruen;
    unsigned short int FarbWert_Blau;
    unsigned short int switchargument;

    state_type aTransZellenKoord;

};
//-----------------------------------------------------------------
// /*
class RenderWidget : public QWidget
{
public:
    RenderWidget():
        color(0, 0, 0)
    {
        //resize(100, 100);
    }



    void setColor(int r, int g, int b)
    {
        color = QColor(r, g, b);
    }

    void setGrafikMatrix(QVector<QVector<int>> GrafikMatrixExt)
    {
        AnzahlYWerte=GrafikMatrixExt.size();        
        AnzahlXWerte=GrafikMatrixExt[1].size();     
        GrafikMatrix.resize(AnzahlYWerte);
        for(int i=0;i<AnzahlYWerte; i++)
        {
            GrafikMatrix[i].resize(AnzahlXWerte);
            
            for(int j=0;j<AnzahlXWerte; j++)
            {
                GrafikMatrix[i][j] = GrafikMatrixExt[i][j];
            }

        }

        //Erstellung und Übertragung der (letzten) Infozeile
        GrafikMatrix[AnzahlYWerte-1].resize(GrafikMatrixExt[AnzahlYWerte-1].size());

            for(int j=0;j<GrafikMatrixExt[AnzahlYWerte-1].size(); j++)
            {
                GrafikMatrix[AnzahlYWerte-1][j] = GrafikMatrixExt[AnzahlYWerte-1][j];
            }


    }

    void paintEvent(QPaintEvent* event)
    {
        QPainter painter(this);


        AnzahlYWerte=GrafikMatrix.size();       //Achtung: Letzte Zeile enthält Zusatzinfos über Art der darzustellenden Daten
        AnzahlXWerte=GrafikMatrix[1].size();

        switch (GrafikMatrix[AnzahlYWerte-1][0])
        {
        case -1:    //Zustand
            for(int yWert=0;yWert<AnzahlYWerte-2; yWert++)
            {
                for(int xWert=0;xWert<AnzahlXWerte; xWert++)
                {
                    switch(GrafikMatrix[yWert][xWert])
                    {
                    case 0: //inaktive Zelle / tote Zelle schw.
                        setColor(0,0,0);
                        //painter.setPen(QPen(color, 200));
                        break;

                    case 1: // aktive Blattzelle gruen
                        setColor(0, 255,0);
                        //painter.setPen(QPen(color, 200));
                        break;

                    case 2: // aktive Ader rot
                        setColor(255,0,0);
                        //painter.setPen(QPen(color, 200));
                        break;
                    default:
                        setColor(0,0,0);
                        break;
                    }

                    painter.fillRect(xWert*10,yWert*10,10,10,color);
                }
            }
            break;

        case 0:     //Zellvolumen (~Wasservolumen) 
            for(int yWert=0;yWert<AnzahlYWerte-2; yWert++)
            {
                for(int xWert=0;xWert<AnzahlXWerte; xWert++)
                {
                    Grafikwert = (GrafikMatrix[yWert][xWert] * 10/ GrafikMatrix[AnzahlYWerte-1][10]) ;     //Skalierung mit max. Zellvolumen -> Werte zwischen 0 und 10
                    switch(Grafikwert)
                    {
                    case 0: //inaktive Zelle / tote Zelle schw.
                        setColor(255,255,255);
                        //setColor(0,0,0);
                        //painter.setPen(QPen(color, 200));
                        break;

                    case 1: // aktive Blattzelle gruen
                        setColor(0, 0,25);
                        //painter.setPen(QPen(color, 200));
                        break;

                    case 2: // aktive Ader rot
                        setColor(0,0,50);
                        //painter.setPen(QPen(color, 200));
                        break;

                    case 3: // aktive Ader rot
                        setColor(0,0,75);
                        //painter.setPen(QPen(color, 200));
                        break;

                    case 4: // aktive Ader rot
                        setColor(0,0,100);
                        //painter.setPen(QPen(color, 200));
                        break;

                    case 5: // aktive Ader rot
                        setColor(0,0,125);
                        //painter.setPen(QPen(color, 200));
                        break;

                    case 6: // aktive Ader rot
                        setColor(0,0,150);
                        //painter.setPen(QPen(color, 200));
                        break;
                    case 7: // aktive Ader rot
                        setColor(0,0,175);
                        //painter.setPen(QPen(color, 200));
                        break;

                    case 8: // aktive Ader rot
                        setColor(0,0,200);
                        //painter.setPen(QPen(color, 200));
                        break;

                    case 9: // aktive Ader rot
                        setColor(0,0,225);
                        //painter.setPen(QPen(color, 200));
                        break;

                    case 10: // aktive Ader rot
                        setColor(0,0,250);
                        //painter.setPen(QPen(color, 200));
                        break;

                    default:
                        setColor(0,0,0);
                        break;
                    }

                    painter.fillRect(xWert*10,yWert*10,10,10,color);
                }
            }
                break;
        default:
            setColor(0,50,0);
            painter.fillRect(10,10,100,100,color);
            // --- bisher keine Fehlermeldung vorgesehen
            break;
        }   //switch (GrafikMatrix[0][0])


        //painter.drawRect(GrafikMatrix,5,5,5);
        //setColor(200,0,0);
        //painter.setPen(QPen(color, 200));
        //painter.drawPoint(0, 0);

        painter.end();
    }


private:
    QColor color;
    QVector<QVector<int>> GrafikMatrix;
    int AnzahlXWerte=1;
    int AnzahlYWerte=1;
    int Grafikwert = 0;

};      //class RenderWidget : public QWidget



//-----------------------------------------------------------------

class MainWidget : public QWidget
{
    Q_OBJECT
public:
    MainWidget():
        layout(this),
        renderWidget()
        // ,
//        redSlider(Qt::Horizontal),
//        greenSlider(Qt::Horizontal),
//        blueSlider(Qt::Horizontal)

    {
//        redSlider.setRange(0, 255);
//        greenSlider.setRange(0, 255);
//        blueSlider.setRange(0, 255);

        layout.addWidget(&renderWidget);

//        layout.addWidget(&redSlider);
//        layout.addWidget(&greenSlider);
//        layout.addWidget(&blueSlider);




//        connect(&redSlider, SIGNAL(valueChanged(int)),
//                this, SLOT(draw()));
//        connect(&greenSlider, SIGNAL(valueChanged(int)),
//                this, SLOT(draw()));
//        connect(&blueSlider, SIGNAL(valueChanged(int)),
//                this, SLOT(draw()));

        resize(250, 250);   //Größe des Fensters in dem die Grafik dagestellt wird
    }

    void drawNew(){draw();}


    //Von extern aufrufbare Funktion, die die Funktion "setGrafikMatrix" von RenderWidget aufruft
    void setGrafikMatrixMW(QVector<QVector<int>> GrafikMatrixMWExt)
    {
    renderWidget.setGrafikMatrix(GrafikMatrixMWExt);
    }


    //Erstellung einer TestMatrix
    QVector<QVector<int>> GrafikMatrixErstellen(int anzahlXWerte, int anzahlYWerte)
    {
        GrafikMatrixNeu.resize(anzahlXWerte);
        int k=0;
        for(int i=0;i<anzahlXWerte; i++)
        {
            GrafikMatrixNeu[i].resize(anzahlYWerte);
            //GrafikMatrix[i][j] = GrafikMatrixExt[i][j];
            k=0;
            for(int j=0;j<anzahlYWerte; j++)
            {
                if(k<3)
                {
                    GrafikMatrixNeu[i][j] = k;
                    k=k+1;
                }
                else
                {
                    k=0;
                    GrafikMatrixNeu[i][j] = k;
                    k=k+1;
                }

            }

        }

        return GrafikMatrixNeu;
    }   //QVector<QVector<int>> GrafikMatrixErstellen(int anzahlXWerte, int anzahlYWerte)


private Q_SLOTS:
    void draw()
    {
        //renderWidget.setColor(redSlider.value(), greenSlider.value(), blueSlider.value());
        renderWidget.update(); // -> update aktiviert -> void paintEvent(QPaintEvent* event)
    }

private:
    QVBoxLayout layout;
    RenderWidget renderWidget;
    QVector<QVector<int>> GrafikMatrixNeu;

//    QSlider redSlider;
//    QSlider greenSlider;
//    QSlider blueSlider;

};      //class MainWidget : public QWidget

// */


#endif // MAINWINDOW_H
mainwindow.cpp

Code: Alles auswählen



#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
#include <vector>
#include <QVector>
using namespace std;
using std::vector;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

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

QVector<QVector<int>> MainWindow::fGrafikerstellen(int ZelldatenArt, DatenMatrix &raDatenmatrix, vector<vector<double>> &raWichtigeWerte)
//Legende, ZelldatenArt: -1: Zustand; 0-16 entsprechend Liste in main.cpp für Zelldaten
{

    DatenSatzAnzahlMax_X= raWichtigeWerte[0][3];    //Max. Anzahl Zellen in x-Richtung, vorgegeben
    DatenSatzAnzahlMax_Y= raWichtigeWerte[0][4];    //Max. Anzahl Zellen in y-Richtung, vorgegeben
    DatensaetzeAnzahl_X = raWichtigeWerte[0][0];    //Anzahl Zellen in x-Richtung
    DatensaetzeAnzahl_Y	= raWichtigeWerte[0][1];    //Anzahl Zellen in y-Richtung
    AnzahlFarbwerte = 3;
    WelcherWert = 0; //(Zustand) soll ausgewertet werden
    ZellenKoord.resize(2);

    switch(ZelldatenArt)
    {
    case -1:    //Zustand
        WelcherWert = 0;
        Naechster = 0;
        break;

    default:
        if (0<= ZelldatenArt <17)
        {
            WelcherWert = ZelldatenArt;
            Naechster = 1;
        }
        else
        {
            WelcherWert = 0;
            Naechster = 0;
        }
        break;

    }


    if (sGrafikmatrixerstellt != 1)
    {
    //Grafiktabelle erstellen und mit Werten befuellen:
        //Referenz nutzen
        if (paGrafikmatrix == NULL)
        {
            cout << "------  Kritischer Fehler - konnte Grafikmatrix nicht erstellen !!! (MainWindow::fGrafikerstellen)  ------" <<endl;
            //return 1;
        }
        raGrafikmatrix.resize(DatenSatzAnzahlMax_Y);		// Anzahl Y-Datens?tze (Zeilen) festlegen
        for (int iy = 0; iy < DatensaetzeAnzahl_Y; iy++)
        {
            ZellenKoord[0] = iy;
            raGrafikmatrix[iy].resize(DatenSatzAnzahlMax_X);		// Anzahl X-Datens?tze (Spalten) festlegen
            //--aktive Zellen: Daten abrufen
            for (int ix = 0; ix < DatensaetzeAnzahl_X; ix++)
            {
                //-->> Daten von raDatenmatrix holen und auswerten; double DatenMatrix::fDatenLesenEinzeln(vector<unsigned short int> ZellenKoord, unsigned short int Naechster, vector<unsigned short int> ZaehlerStartWertKoord, unsigned 

short int WelcherWert, double MindestGF, unsigned short int Blockieren, vector<vector<double> > &raWichtigeWerte, state_type(&raTransZellenKoord))					// Methode zum Auslesen von Einzelwerten (keine 

ZelldatenSätze!)
                ZellenKoord[1] = ix;
                //vargumentuebergabe.resize(1);

                //Zustandswerte aus Eigenschaftsmatrix in Grafikmatrix übertragen:
                raGrafikmatrix[iy][ix] = raDatenmatrix.fDatenLesenEinzeln(ZellenKoord, Naechster, {0,0}, WelcherWert, 0, 0, raWichtigeWerte, aTransZellenKoord);


                /*
                switchargument = raDatenmatrix.fDatenLesenEinzeln(ZellenKoord, 0, {0,0}, WelcherWert, 0, 0, raWichtigeWerte, aTransZellenKoord);

                switch (switchargument)
                {
                case 0:
                    FarbWert_Rot = 0;
                    FarbWert_Gruen = 0;
                    FarbWert_Blau = 0;

                case 1:
                    FarbWert_Rot = 0;
                    FarbWert_Gruen = 200;
                    FarbWert_Blau = 0;

                default:
                    FarbWert_Rot = 0;
                    FarbWert_Gruen = 0;
                    FarbWert_Blau = 0;
                 }      //switch

                raGrafikmatrix[iy][ix].resize(AnzahlFarbwerte);		// Anzahl Farbwerte festlegen

                raGrafikmatrix[iy][ix][0] = FarbWert_Rot;
                raGrafikmatrix[iy][ix][1] = FarbWert_Gruen;
                raGrafikmatrix[iy][ix][2] = FarbWert_Blau;
                */

                /*
                for (int ip = 0; ip < AnzahlFarbwerte; ip++)
                {
                    //raGrafikmatrix[iy][ix][ip] = 1;				// jeden Parametersatz mit "1" befuellen

                    raGrafikmatrix[iy][ix][ip] = raDatenmatrix.fDatenLesenEinzeln(ZellenKoord, 0, {0,0}, WelcherWert, 0, 0, raWichtigeWerte);					// Methode zum Auslesen von Einzelwerten (keine ParaSätze!)
                }
                */
            }   // for (int ix = 0; ix < DatensaetzeAnzahl_X; ix++)

            //---restliche (inaktive) Zellen mit "0" füllen
            for (int ix = DatensaetzeAnzahl_X-1; ix < DatenSatzAnzahlMax_X; ix++)
            {
                //-->> Daten von raDatenmatrix holen und auswerten; double DatenMatrix::fDatenLesenEinzeln(vector<unsigned short int> ZellenKoord, unsigned short int Naechster, vector<unsigned short int> ZaehlerStartWertKoord, unsigned 

short int WelcherWert, double MindestGF, unsigned short int Blockieren, vector<vector<double> > &raWichtigeWerte, state_type(&raTransZellenKoord))					// Methode zum Auslesen von Einzelwerten (keine 

ParaSätze!)
                ZellenKoord[1] = ix;


                raGrafikmatrix[iy][ix] = 0;
                //raGrafikmatrix[iy][ix] = 0;
                //raGrafikmatrix[iy][ix] = 0;


                //raGrafikmatrix[iy][ix].resize(AnzahlFarbwerte);		// Anzahl Farbwerte festlegen

                //raGrafikmatrix[iy][ix][0] = 0;
                //raGrafikmatrix[iy][ix][1] = 0;
                //raGrafikmatrix[iy][ix][2] = 0;

            }   //for (int ix = DatensaetzeAnzahl_X-1; ix < DatenSatzAnzahlMax_X; ix++)

        }   //for (int iy = 0; iy < DatensaetzeAnzahl_Y; iy++)



        //--restliche, inaktive Zellen befüllen
        for (int iy = DatensaetzeAnzahl_Y-1; iy < DatenSatzAnzahlMax_Y; iy++)
        {
            ZellenKoord[0] = iy;
            raGrafikmatrix[iy].resize(DatenSatzAnzahlMax_X);		// Anzahl X-Datens?tze (Spalten) festlegen

            //---inaktive Zellen mit "0" füllen
            for (int ix = 0; ix < DatenSatzAnzahlMax_X; ix++)
            {
                //-->> Daten von raDatenmatrix holen und auswerten; double DatenMatrix::fDatenLesenEinzeln(vector<unsigned short int> ZellenKoord, unsigned short int Naechster, vector<unsigned short int> ZaehlerStartWertKoord, unsigned 

short int WelcherWert, double MindestGF, unsigned short int Blockieren, vector<vector<double> > &raWichtigeWerte, state_type(&raTransZellenKoord))					// Methode zum Auslesen von Einzelwerten (keine 

ParaSätze!)
                ZellenKoord[1] = ix;

                raGrafikmatrix[iy][ix] = 0;
                //raGrafikmatrix[iy][ix] = 0;
                //raGrafikmatrix[iy][ix] = 0;

                //raGrafikmatrix[iy][ix].resize(AnzahlFarbwerte);		// Anzahl Farbwerte festlegen

                //raGrafikmatrix[iy][ix][0] = 0;
                //raGrafikmatrix[iy][ix][1] = 0;
                //raGrafikmatrix[iy][ix][2] = 0;

            }   //for (int ix = 0; ix < DatenSatzAnzahlMax_X; ix++)

        }   //for (int iy = DatensaetzeAnzahl_Y-1; iy < DatenSatzAnzahlMax_Y; iy++)


        //Anhängen von Infozeile an raGrafikmatrix zwecks Informationsweitergabe wie z.B. welche Auswertetabelle in "paintEvent" verwendet werden soll!
        raGrafikmatrix.resize(DatenSatzAnzahlMax_Y+1);
        raGrafikmatrix[DatenSatzAnzahlMax_Y].resize(21);            //max. 20 Infos können derzeit übergeben werden
        raGrafikmatrix[DatenSatzAnzahlMax_Y][0] = ZelldatenArt;     //Zelldatenart übergeben
        //Legende, ZelldatenArt: -1: Zustand; 0-16 entsprechend Liste in main.cpp für Zelldaten
        switch(ZelldatenArt)
        {
        case -1:
            break;

        case 0:
            raGrafikmatrix[DatenSatzAnzahlMax_Y][10] = raWichtigeWerte[4][0];    //max. Zellvolumen übergeben
            break;
        }


        // Die Grafikmatrix liegt nun in der Referenz "raGrafikmatrix" vor. (Dimensionen: y_max X x_max; inaktive Zellen wurden mit (0) gefüllt, letzte Zeile -> Infos.)
        sGrafikmatrixerstellt = 1;
        return raGrafikmatrix;
    }

//TEST:
/*
    MainWidget mw;
    mw.setGrafikMatrixMW(raGrafikmatrix);
    mw.setGrafikMatrixMW(mw.GrafikMatrixErstellen(20,20));
    mw.drawNew();
    mw.show();
*/


}

Re: Simulationsgrafik gesteuert updaten

Verfasst: 3. Januar 2019 12:19
von Tomaxx
Ich denke du wärst über signals und slots am Besten bedient...

Re: Simulationsgrafik gesteuert updaten

Verfasst: 7. Januar 2019 22:28
von SimuBit
Danke Thomaxx für Deinen Hinweis. Ja, die benötige ich auf jeden Fall. Gäb es denn Alternativen? Ich habe mir nun QT-Online-Kurse gekauft und werde diese studieren. Es haben sich auch bereits ein paar Fragezeichen geklärt.
Dadurch werde ich es hoffentlich hinbekommen das fremde Konstrukt mit paintevent selber in einer Weise aufzubauen, dass ich es verstehe und nicht sämtlicher Code im Header stehen muss.

Drei Fragen hätte ich aber schonmal vorab:
1) Gibt es keine einfachere Darstellungsmethode, als dieses paintevent, um auf Knopfdruck eine Simulation eine weitere Iteration durchführen zu lassen und diese dann als z.B. Pixelbild darzustellen? Als Ergebnis der Simulationsberechnung habe ich z.B. einen 2D-Vektor mit int-Werten, die dann Farbwerten zugeordnet werden. Alternativ kann natürlich auch ein 3D-Vektor mit bereits vorausgefüllten RGB-Werten bereitgestellt werden.

2) Damit die Berechnung der Simulationsdaten und die grafische Darstellung zur Laufzeit stets wieder neu, ggf. mit veränderten Parametern erfolgen kann, müssen alle Programmteile (auch die Simulationsberechnung) in diesen Q_Objects eingebettet werden, oder?

3) Über welche Barrieren können Signals und slots nicht kommunizieren? Vorausgesetzt, es handelt sich um Objekte von QT-Klassen. Ich versuche da einem Kommunikationsproblem auf die Spur zu kommen...

Danke und Gruß! :)

Re: Simulationsgrafik gesteuert updaten

Verfasst: 8. Januar 2019 21:31
von veeman
Zu 1:
Das paintEvent wird immer dann Aufgerufen wenn dein Widget/Control neugezeichnet werden muss:
- Beim erstmaligen Anzeigen
- Bei Größenänderungen
- Ggf. beim Bewegen des Fensters
Dh. hier solltest du nach Möglichkeit einen statischen Zustand zeichnen.

Wenn du also eine Animation oder eine fortschreitenden Bildänderung erzielen möchtest solltest du das in einer separaten Funktion (z.b. recalculate) machen, die jeweils den nächsten Zustand darzustellenden Zustand berechnet. Diese sollte QWidget::update() aufrufen um ein neuzeichnen des Bildes zu veranlasse.
QWidget::update() hat den vorteil, dass wenn diese Funktion mehrmals in kurzer Zeit aufgerufen wird, dein Widget jedoch nur ein Mal neugezeichnet wird, dies schont Ressourcen und die Anwendung fühlt sich flüssiger an.

Um die Animation bzw. die fortschreitende Bildänderung zu vervollständigen kannst du dein recalculate als Slot definieren und mit z.b einem "Next" Button verknüpfen oder durch einen Zeitgesteuerten update; und zwar mittels
eines QTimer Objects, entweder im Interval oder einmallig per QTimer::singleShot


Zu 2:
Nicht unbedingt, wenn du von QObject ableitest hasst du den vorteil, dass Signale und Slots entsprechend automatisch verarbeitet werden. Dafür muss man diese natürlich nutzen.

Zu 3:
Damit Signale und Slots funktionieren muss die Klasse wie schon erwähnt von QObject abgeleitet worden sein, entspreche Signale und Slots angelegt und verknüpft (!) worden sein und der Qt Event Prozessor muss laufen (QApplication::exec) und nicht blockiert sein (z.B. durch lang laufende Funktionen).

Mal etwas von mir zu diesem Thema und ist vielleicht auch interessant: Qt Custom Widget

Re: Simulationsgrafik gesteuert updaten

Verfasst: 13. Januar 2019 22:34
von SimuBit
Vielen Dank veeman für Deine Antworten und das verlinkte Beispiel, dessen Erklärungen mir auch sehr weitergeholfen haben. Mittlerweile habe ich den Grafik-Code neu aufgebaut und eine Iteration mit Grafikdarstellung funktioniert auch.

Nun habe ich jedoch das Problem, dass ich Referenzen auf Objekte (in main erzeugt) an mein Grafik-QWidget dauerhaft übergeben will und diese (Adressen) dann auch noch an weitere Objekte weitergegeben werden sollen. Ist das generell großer Unfug oder kann man das über eine Verkettung von Pointern und Referenzen machen?? Mir hat da irgenwann der Kopf geraucht...

Der konkrete Fall:
In Main erzeuge ich das Datenspeicherobjekt (mit Zugriffsfkt.) und einen Vektor mit wichtigen Programmparametern, die überall benötigt
werden. Diese habe ich bisher immer von main aus per Referenz an die jeweils aufgerufenen Objekte zwecks z.B. Neuberechnng von Teilen des Datenspeichers übergeben.
Nun wollte ich im Grafik-QWidget eine per Slot erreichbare Funktion einrichten, die dann diese Neuberechnungs-Objekte aufruft, eine neue Grafikmatrix aus dem Datenspeicher erstellt und dann paintevent per "update" aktiviert.

Am Liebsten würde ich schon im Constructor die Referenzen bzw. Adressen übergeben und dann dauerhaft im Grafik-QWidget speichern. {edit: Hat sich erledigt: Hier hatte ich aber Probleme, weitere Argumente unterzubringen (explicit QSimuGrafik(QWidget *parent = nullptr);).} Dann habe ich versucht die Referenzen per Holfunktion ins QWidget zu bekommen. Diese sollte direkt nach der Erstellung des Objektes in main von dort aus aufgerufen werden und dann die Speicherung der Adressen im QWidget vornehmen. Der Versuch, die Erzeugung des DatenSpeichers und des Programmparametervektors ins QWidget zu verlagern, hat auch nicht funktioniert, da zur Erzeugung des Datenspeichers der Programmparametervektor benötigt wird, der erst im Constructor befüllt wird...
Ich würde eigentlich gerne überall mit Referenzen arbeiten, habe aber den Verdacht, dass ich nicht mehr um die Zeiger rumkomme...

Kann mir jemand Stichworte bzw. Beispiele nennen, die mir bei meiner Aufgabenstellung weiterhelfen können bzw. falls mein Vorhaben Unfug ist, die richtige Vorgehensweise skizzieren.

Vielen Dank im Voraus!

Re: Simulationsgrafik gesteuert updaten

Verfasst: 16. Januar 2019 21:29
von veeman
Pointer, Referenzen sind mal ein Ansatz. Ansonsten wäre es auch sicherlch mit einem nicht so gern gesehenem Singleton möglich.