Zeichnen unter QT

Alles rund um die Programmierung mit Qt
Antworten
MaXgOeKy
Beiträge: 5
Registriert: 30. Dezember 2012 09:55

Zeichnen unter QT

Beitrag von MaXgOeKy »

Hallo QT-Profis!

Ich programmiere des Spaßes wegen gerade eine Simulation - nix dolles.
Die Simulation sieht in der Theorie wie folgt aus: http://de.wikipedia.org/wiki/Wator

Das Grundgerüst steht soweit. Ich habe also bis jetzt die Initialisierung der Spielwelt implementiert.
Um zu Testen, ob es nach meinen Wünschen angeordnet wird, möchte ich die Spielwelt nun Visualisieren.

Das eigendliche Spielfeld habe ich in eine "Matrix", welche aus zwei verschachtelten Vectoren besteht, gespeichert.
Diese möchte ich nun mittels QT ausgeben.
Im Moment gebe ich das in QT wie folgt aus:

Code: Alles auswählen

    try
    {
        //Erstelle Painter
        QPainter playingField(_pixMap);
        playingField.setPen(*_freePan);
        
        //Zähler für die Spielwelt
        int counter_x   = 0;
        int counter_y   = 0;
        int fishCounter = 0;
        int haiCounter  = 0;
        int freeCounter = 0;
    
        //Zeichne Spielfeld
        for (int x = 0; x < _playingField_x_width; x+=4) //x
        {
            //Setze zurück
            counter_y = 0;
            
            for (int y = 0; y < _playingField_y_height; y+=4) //y
            {
                //Paint individuum
                switch (_worldWator->getIndividumType(counter_x, counter_y))
                {
                    case 1: //Fisch
                        playingField.setPen(*_fishPan);
                        fishCounter++;
                        break;
                    case 2: //Hai
                        playingField.setPen(*_sharkPan);
                        haiCounter++;
                        break;
                    case 3: //Wasser | Leer
                        playingField.setPen(*_freePan);
                        freeCounter++;
                        break;
                    default: //fehler
                        playingField.setPen(Qt::white);
                        break;
                }//end switch
                
                playingField.drawPoint(x, y);
                
                counter_y ++;
            }//end for y
        
            counter_x ++;
        }//end for x

        //Schließe Zeichnen ab
        playingField.end();
        ui->labelPlayingField->setPixmap(*_pixMap);
    
    }//end try
    
    catch (...)
    {
    }
Durch die zwei Schleifen wird der ganze Spaß natürlich sehr langsam.

Meine Fragen nun an Euch:
1. Gibt es eine Möglichkeit die Zeichnung irgendwie im Speicher zu Berechnen und es im Anschluss an die Berechnung erst anzuzeigen?
2. Gibt es eine elegantere Variante sachen zu Zeichnen?

Vielen Dank im Voraus,

Grüße
MaX
prog
Beiträge: 4
Registriert: 10. Februar 2013 22:27

Re: Zeichnen unter QT

Beitrag von prog »

Ich würde dir empfehlen als Datenstrucktur ein QImage zu verwenden. Das kannst du folgendermaßen Initiallisieren:

Code: Alles auswählen

QImage playing_field(width, height, QImage::Format_Indexed8);
Damit hast du gleich eine zweidimensionale Struktur, die praktischerweise auch noch mit

Code: Alles auswählen

painter.drawImage(...);
gezeichnet werden kann. Jeder Pixel hat einen Wert zwischen 0 und 255. Welcher Wert was bedeutet, kannst du ja dann selbst festlegen. Um was zu sehen gibst du dem Image eine Farbpalette:

Code: Alles auswählen

playing_field.setColorTable(const QVector<QRgb> colors);
In dem Vector kannst du deinem jeweiligen Index also die Farbe zuordnen, die du dafür gern hättest.

Vielleicht wäre es auch noch eine gute Idee, ein enum zu verwenden, um Namen statt Zahlen schreiben zu können.

Edit:

Da du auf eine Label ausgibst, kannst du statt drawImage() natürlich einfach

Code: Alles auswählen

label->setPicture(playing_field);
verwenden.
MaXgOeKy
Beiträge: 5
Registriert: 30. Dezember 2012 09:55

Re: Zeichnen unter QT

Beitrag von MaXgOeKy »

Hallo danke erstmal für Deine Antwort!

Ich habe das gerade mal implementiert, funktioniert leider nicht. Hier der Code:

Code: Alles auswählen

    //Erstelle Spielfeld
    QImage playingField(_playingField_x_width, _playingField_y_height, QImage::Format_RGB32);
    playingField.fill(Qt::blue);
    
    QRgb fish = Qt::green;
    QRgb shark = Qt::red;
    QRgb water = Qt::blue;
    QRgb error = Qt::white;
    
    //Zähler für die Spielwelt
    int counter_x   = 0;
    int counter_y   = 0;
    int fishCounter = 0;
    int haiCounter  = 0;
    int freeCounter = 0;
    
    //Zeichne Spielfeld
    for (int x = 0; x < _playingField_x_width; x+=4) //x
    {
        //Setze zurück
        counter_y = 0;
        
        for (int y = 0; y < _playingField_y_height; y+=4) //y
        {
            //Paint individuum
            switch (_worldWator->getIndividumType(counter_x, counter_y))
            {
                case 1: //Fisch
                    playingField.setPixel(counter_x, counter_y, fish);
                    fishCounter++;
                    break;
                case 2: //Hai
                    playingField.setPixel(counter_x, counter_y, shark);
                    haiCounter++;
                    break;
                case 3: //Wasser | Leer
                    playingField.setPixel(counter_x, counter_y, water);
                    freeCounter++;
                    break;
                default: //fehler
                    playingField.setPixel(counter_x, counter_y, error);
                    break;
            }//end switch
            
            counter_y ++;
        }//end for y
        
        counter_x ++;
    }//end for x
    
    //Zeichne Spielfeld
    QPixmap test;
    test.fromImage(playingField);
    ui->labelPlayingField->setPixmap(test);
Die von Dir vorgeschlagene Methode:

Code: Alles auswählen

label->setPicture(playing_field);
funktioniert leider nicht

Ich habe es auch mit

Code: Alles auswählen

QImage::fill()

probiert, aber auch damit bekomme ich keine Farbe auf das Label :| .

Grüße
MaX
prog
Beiträge: 4
Registriert: 10. Februar 2013 22:27

Re: Zeichnen unter QT

Beitrag von prog »

Du hast auch nicht so ganz gemacht, was ich gesagt habe ;)

Das QImage muss mit QImage::Format_Indexed8 erstellt werden und dann muss eine Farbpalette für die Indizes zugewiesen werden, sonst ist das Bild schwarz. Ich hab das jetzt nicht getestet, aber der Code müsste etwa so aussehen:

Code: Alles auswählen

//Erstelle Spielfeld
enum Type{
	water = 0,
	fish  = 1,
	shark = 2,
	error = 255,
};

QImage playingField(_playingField_x_width, _playingField_y_height, QImage::Format_Indexed8);
QVector colors(256);
colors[water] = Qt::blue;
colors[fish]  = Qt::green;
colors[shark] = Qt::red;
playingField.setColorTable(colors);

//Zähler für die Spielwelt
int counter_x   = 0;
int counter_y   = 0;
int fishCounter = 0;
int haiCounter  = 0;
int freeCounter = 0;

//Zeichne Spielfeld
for (int x = 0; x < _playingField_x_width; x+=4) //x
{
	//Setze zurück
	counter_y = 0;

	for (int y = 0; y < _playingField_y_height; y+=4) //y
	{
		//Paint individuum
		switch (_worldWator->getIndividumType(counter_x, counter_y))
		{
			case 1: //Fisch
				playingField.setPixel(counter_x, counter_y, fish);
				fishCounter++;
				break;
			case 2: //Hai
				playingField.setPixel(counter_x, counter_y, shark);
				haiCounter++;
				break;
			case 3: //Wasser | Leer
				playingField.setPixel(counter_x, counter_y, water);
				freeCounter++;
				break;
			default: //fehler
				playingField.setPixel(counter_x, counter_y, error);
				break;
		}//end switch
	
		counter_y ++;
	}//end for y

	counter_x ++;
}//end for x

//Zeichne Spielfeld
ui->labelPlayingField->setImage(playingField);
Edit:

Ich seh grad, was du gemacht hast müsste auch funktionieren, is aber vermutlich langsamer. Dein Fehler liegt in der vorletzten Zeile. fromImage() ist eine statische Funktion, die die Pixmap zurückgibt. Müsste heißen:

Code: Alles auswählen

QPixmap test = QPixmap::fromImage(playingField);
MaXgOeKy
Beiträge: 5
Registriert: 30. Dezember 2012 09:55

Re: Zeichnen unter QT

Beitrag von MaXgOeKy »

Hallo Prog!

Also ich habe den Code jetzt umgeschrieben:

Code: Alles auswählen

//Erstelle Spielfeld
    QImage playingField(_playingField_x_width, _playingField_y_height, QImage::Format_Indexed8);

    enum Type
    {
        fish = 1,
        shark = 2,
        water = 3,
        error = 255
    };//end enum
    
    QVector<QRgb> colors(256);
    colors[fish] = Qt::green;
    colors[shark] = Qt::red;
    colors[water] = Qt::blue;
    colors[error] = Qt::white;

    playingField.setColorTable(colors);
    
    playingField.fill(colors[fish]);
    
    //Zähler für die Spielwelt
    int fishCounter = 0;
    int haiCounter  = 0;
    int freeCounter = 0;
    
    //Zeichne Spielfeld
    for (int x = 0; x < _playingField_x_width; x++) //x
    {
        
        for (int y = 0; y < _playingField_y_height; y++) //y
        {
            //Paint individuum
            switch (_worldWator->getIndividumType(x, y))
            {
                case 1: //Fisch
                    playingField.setPixel(x, y, fish);
                    fishCounter++;
                    break;
                case 2: //Hai
                    playingField.setPixel(x, y, shark);
                    haiCounter++;
                    break;
                case 3: //Wasser | Leer
                    playingField.setPixel(x, y, water);
                    freeCounter++;
                    break;
                default: //fehler
                    playingField.setPixel(x, y, error);
                    break;
            }//end switch
            
        }//end for y
        
    }//end for x
    
    //Zeichne Spielfeld
    QPixmap test = QPixmap::fromImage(playingField);
    ui->labelPlayingField->setPixmap(test);
Das Programm funktioniert leider immer noch nicht....es knallt nun, er sagt aber nur das es ne exception gab, nicht welche. Kannst du erkennen, wo der Fehler liegt? -> Also nicht mehr aktuell. Edit: Fehler gefunden! :)

Die von Dir beschriebene Methode

Code: Alles auswählen

ui->labelPlayingField->setImage(playingField);
besitzt QLabel nicht. Hast du dich vllt vertan und meintest etwas anderes?
Das ist auch der Grund, warum ich das ganze erst in ne PixMap schiebe.

€dit: Was ist jetzt genau der Unterschied von Format_Indexed8 zu der, die ich erst genutzt habe?
€dit2: Da ich den Fehler oben gefunden habe, hier der Nächste: Er zeichnet nur schwarz?!

Grüße
MaX
Antworten