Brauche dringend Hilfe mit QPixmap!

Alles rund um die Programmierung mit Qt
kowi1134
Beiträge: 120
Registriert: 1. Mai 2005 17:48
Wohnort: Arnsberg

Brauche dringend Hilfe mit QPixmap!

Beitrag von kowi1134 »

Hallo!

Ich habe heute schon einen Beitrag geschrieben: http://qtforum.de/forum/viewtopic.php?t=798

Ich stecke immer noch an diesem Problem fest, allerdings habe ich jetzt schon gelesen, dass man kein QLabel benutzen sollte, um Bilder darzustellen, weshalb ich schon wieder umdenken muss.

Ich brauche folgendes:

Ein Widget, dass in einem QFrame eingebettet ist und mir als leeres Blatt für mein Bild dient. Vergrößert sich mein Dialog, vergrößert sich auch mein Frame. D.h. es soll sich auch mein leeres Blatt vergrößern. Jedoch soll der neu entstandene Platz nicht bloß rechts und links drangeklatscht werden, sondern das zugrundeliegende Koordinatensystem muss sich anpassen!

Wie lässt sich diese Idee realisieren?

Ciao
FlorianBecker
Beiträge: 1213
Registriert: 2. Dezember 2004 10:54
Kontaktdaten:

Beitrag von FlorianBecker »

Mh, wo besteht dein Hauptproblem?

Wenn ich das richtig verstehe skaliert sich dein Bild nicht richtig!? Dann musst du ScaleMode auf ScaleFree setzen. Ansonsten kann ich deinem Beitrag nicht so recht folgen. Welches Koordinatensystem legst du denn wo voraus?
kowi1134
Beiträge: 120
Registriert: 1. Mai 2005 17:48
Wohnort: Arnsberg

Beitrag von kowi1134 »

Hallo!

Also, wenn ich das richtig verstehe, was ich hier verbreche, dann erzeuge ich ja eine QPixmap, die mein PaintDevice darstellt. Über ein QPainter Objekt schreibe ich auf diese QPixmap (z.B. mit drawPoint()).

Ich weiß bloß nicht, wann ich wo den QPainter oder die QPixmap skalieren muss. Schreibe ich eine von QWidget abgeleitete Klasse und reimplementiere einige Event Methoden? Womit stelle ich mein Bild dar? Über ein QLabel soll man's ja nicht machen.

Kurz: Was muss ich wie ableiten, damit mein Bild in einem QFrame dargestellt und immer automatisch mit vergrößert/verkleinert wird? Ich habe gerade die totale Blockade, weil es vorher mit einem QGLWidget alles anders lief.

Ich hoffe, das Problem ist nicht noch komplizierter geworden.

Ciao
lepsai
Beiträge: 573
Registriert: 14. September 2004 21:33
Wohnort: Berlin
Kontaktdaten:

Beitrag von lepsai »

Wenn etwas in einem QFrame dargestellt werden soll, dann sollte man die eigene Klasse von QFrame ableiten. Skalieren sollte man den Painter.

überladen sollten in deinem Fall:
paintEvent()
resizeEvent()
kowi1134
Beiträge: 120
Registriert: 1. Mai 2005 17:48
Wohnort: Arnsberg

Beitrag von kowi1134 »

lepsai hat geschrieben:Wenn etwas in einem QFrame dargestellt werden soll, dann sollte man die eigene Klasse von QFrame ableiten. Skalieren sollte man den Painter.

überladen sollten in deinem Fall:
paintEvent()
resizeEvent()
Zunächst einmal Danke!

Nach einer kleinen Klausurphase und einer Erkältung mache ich mich wieder ans Werk...

Lepsai: Ich arbeite mit dem Designer, d.h. ich müsste den Frame in dem ich zeichnen will direkt hier einbauen, stimmt's?

Wenn nicht, dann würde ich Dich gerne fragen wie ich den Frame nachträglich, d.h. mit ein paar Codezeilen hinzufügen kann. Obwohl, aha, schneide ich hier zufällig das Thema "Custom Widgets" an?

Dann müsste ich also quasi im Designer einen Frame erstellen, mit der rechten Maustaste draufklicken und "Promote to custom widget" auswählen, oder?

Ciao
lepsai
Beiträge: 573
Registriert: 14. September 2004 21:33
Wohnort: Berlin
Kontaktdaten:

Beitrag von lepsai »

[quote]Dann müsste ich also quasi im Designer einen Frame erstellen, mit der rechten Maustaste draufklicken und "Promote to custom widget" auswählen, oder?
[/quote]

Na ja, du erstellst deine abgeleitete Klasse und fügst sie dann im Desginer als Custom Widget hinzu... das war's...
kowi1134
Beiträge: 120
Registriert: 1. Mai 2005 17:48
Wohnort: Arnsberg

Beitrag von kowi1134 »

Also ich bin jetzt wie folgt vorgegangen:
  1. Im Designer einen Frame eingefügt (siehe Bild promoting.gif)
  2. Danach habe ich die beiden Dateien "PainterFrame.h" und "PainterFrame.cpp" erstellt (siehe unten) und in meine Projekt-Datei eingefügt.
  3. Jetzt noch qmake und make ausgeführt und es läuft.
Zur Zeit arbeite ich noch an der eigentlichen Implementierung, sodass auch wirklich etwas dargestellt wird.

Ich habe allerdings eine Frage zu der QPainter Funktion scale():
Vergrößert sie den tatsächlich sichtbaren Bereich, oder skaliert sie "nur" den Painter, indem sie vorgibt, dass die entsprechenden Ecken (unten links, oben rechts) dem Wert ihrer Funktionsargumente entsprechen?

Code: Alles auswählen

#ifndef PAINTERFRAME_H
#define PAINTERFRAME_H

#include <QtGui>
#include <QFrame>

class QPainter;
class QPixmap;

class PainterFrame : public QFrame
{
Q_OBJECT

public:
	PainterFrame       ( QWidget *parent = 0 );
	~PainterFrame      ();
	void paintEvent    ( QPaintEvent * event );
	void resizeEvent   ( QResizeEvent * event );
private:
	QPainter      *painter;
	QPixmap       *pixmap;
};

#endif

Code: Alles auswählen

#include "PainterFrame.h"

#include <QPainter>
#include <QPixmap>

/**
 * This is the PainterFrames's constructor
 * @param QWidget * parent
 * @see QFrame
 */
PainterFrame::PainterFrame ( QWidget *parent ) : QFrame( parent )
{
	painter = new QPainter();
}

/**
 * This is the PainterFrames's destructor
 */
PainterFrame::~PainterFrame()
{
	delete painter;
	delete pixmap;
}

/**
 * This function is called whenever the window system sends a paint
 * signal.
 * @param QPaintEvent * event;
 * @return void
 */
void PainterFrame::paintEvent( QPaintEvent * event )
{
    painter.drawPixmap( 0, 0, *pixmap );
}

/**
 * This function is called whenever the window system sends a resize
 * signal.
 * @param QResizeEvent * event;
 * @return void
 */
void PainterFrame::resizeEvent( QResizeEvent * event )
{
	QSize oldSize = event->oldSize();
	QSize newSize = event->size();
	
	// Only scale the painter's coordinate system if necessary
	if ( oldSize != newSize )
	{
    	painter->scale( newSize->width(), newSize->height() );
	}
}
Dateianhänge
So sieht die Ansicht im Designer aus, wenn ich meinen QFrame als Custom Widget promote.
So sieht die Ansicht im Designer aus, wenn ich meinen QFrame als Custom Widget promote.
promoting.gif (68.74 KiB) 7599 mal betrachtet
lepsai
Beiträge: 573
Registriert: 14. September 2004 21:33
Wohnort: Berlin
Kontaktdaten:

Beitrag von lepsai »

Die Implementierung ist sehr kommisch...
QPainter braucht nicht global sein und muss in paintEvent() erstellt werden:

QPainter p(this);

Skalieren lässt er sich mit:

p.setWorldMatrix(...)
lepsai
Beiträge: 573
Registriert: 14. September 2004 21:33
Wohnort: Berlin
Kontaktdaten:

Beitrag von lepsai »

in 2-3 Tagen werde ich www.ku-soft.de ein Widget für die Bildanzeige zum Download anbieten, vielleicht wird es was für dich...
kowi1134
Beiträge: 120
Registriert: 1. Mai 2005 17:48
Wohnort: Arnsberg

Beitrag von kowi1134 »

Aber Du hast doch gesagt, ich solle die resizeEvent Method überladen. Ich dachte, hier sollte ich dann den Painter skalieren.

Im Übrigen glaube ich, dass wir aneinander vorbei reden, denn setWorldMatrix gibt is nicht als QPainter Methode in Qt4!
lepsai
Beiträge: 573
Registriert: 14. September 2004 21:33
Wohnort: Berlin
Kontaktdaten:

Beitrag von lepsai »

in resizeEvent() berechnest du den Zoomfaktor, aber angewendet wird dieser in paintEvent()...

Wie es in Qt 4 mit setWorldMatrix aussieht, weiss ich nicht, aber auch da wird ei eine Möglichkeit geben, painter zu skalieren... Meine Vorschläge beziehen sich immer auf Qt3... Bis Ende dieses Jahres jedenfalls :)
kowi1134
Beiträge: 120
Registriert: 1. Mai 2005 17:48
Wohnort: Arnsberg

Beitrag von kowi1134 »

So, ich bekomme mein Pixmap jetzt angezeigt, wenn und skaliert, wenn ich meinen QPainter in der paintEvent Methode erzeuge und zwar nicht als Zeiger.

Wenn ich jetzt aber nur den Teil meines Feldes neuzeichnen lassen will, der sich verändert hat (das wären dann zwei Punkte), wie kann ich denn dann auf meinen QPainter einwirken und z.B. "void drawPoint ( int x, int y )" aufrufen?
Immerhin kann ich von außen nicht auf den QPainter zugreifen?
Die einzige Möglichkeit besteht für mich darin, dem QFrame, in dem gezeichnet wird, ein Signal zu schicken, dass er eine bestimmte Region neuzeichnen soll.

Sehe ich das richtig?

Ciao
lepsai
Beiträge: 573
Registriert: 14. September 2004 21:33
Wohnort: Berlin
Kontaktdaten:

Beitrag von lepsai »

ich verstehe nicht, was du letztendlich willst... beschreib mal dein Vorhaben etwas ausführlicher, dann kann man dir vielliecht helfen... So nicht...
kowi1134
Beiträge: 120
Registriert: 1. Mai 2005 17:48
Wohnort: Arnsberg

Beitrag von kowi1134 »

Also gut!

Ich habe ein Array mit Zufallswerten, von denen ich den kleinsten, den größten und die Anzahl der Werte kenne. In einem Sortieralgorithmus soll das Array sortiert werden und bei jedem Vertauschen von zwei Werten muss ein Signal gesendet werden. Es kann auch sein, dass erst nach mehreren Vertauschungen ein Signal gesendet wird, das hängt ganz von der gewählten Aktualisierungsrate ab.

Zum Signal: Jedes Signal, welches über eine Änderung im Feld informiert, übermittelt die beiden X- und Y-Werte, die sich verändert haben. Mein Frame, in dem gezeichnet wird, soll dieses Signal entgegennehmen und die beiden entsprechenden Bereiche neuzeichnen.

Mein vorherige Lösung sah vor, dass einfach nur über eine Änderung im Feld informiert wurde, aber nicht gesagt wurde wo sich diese Änderung befindet. Das bedeutet, dass immer wieder alles neu gezeichnet werden musste. Es sei hier angemerkt, dass diese Lösung noch OpenGL verwendete, womit man sowie so nur alles neu zeichnen kann (glaube ich).

Zurück zum Problem.

Ich muss also, sobald ich meine Werte vom Zufallsarray bekomme einmal alles zeichnen und sobald etwas geändert wurde, nur noch den entsprechenden Bereich aktualisieren. Ich vermute mal, dass diese Lösung schneller ist, als immer c.a. 100.000.000 Elemente neuzuzeichnen.

Wenn alles soweit implementiert ist, dann werden allerdings noch folgende Probleme auftreten:
  1. Wenn aufgrund der Aktualisierungsrate nicht immer jede Veränderung im Feld signalisiert wird, dann muss ich mir diese Aktualisierungen aber trotzdem merken und sie später zeichnen lassen. Das dürfte aber kein Problem sein.
  2. Wie rechne ich die einfachen Indices und Werte in meinem Zufallsarray in die zu zeichnenden Koordinaten um?

Ich hoffe, mein Problem ist jetzt etwas klarer geworden.

Ciao
lepsai
Beiträge: 573
Registriert: 14. September 2004 21:33
Wohnort: Berlin
Kontaktdaten:

Beitrag von lepsai »

Nun, du musst natürlich nur Regionen zeichnen, die aktualisiert wurden. Da dir zu einem Zeitpunkt die neuen Koordinaten vorliegen, ist es auch kein Problem. Definiere in deiner Klasse eine zusätzliche Variable, die das Update steuern würde. Und frag diese in paintEvent() ab. So kannst du steuern, ob ein komplettes oder ein partielles Update stattfinden soll. Für das partielle Update musst du in deiner Klasse die entpsrechende Punkte festhalten. z.B. in einem QPoint Objekt.
Antworten