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();
}
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
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();
*/
}