PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Zeichenmöglichkeit in QT



FireWare
29-11-2002, 19:29
Hi Leute !
Bin noch nicht sehr bewandert mit QT und dergleichen, aber der Designer und QT allgemein gefallen mir sehr gut...

Ich wollte deshalb mal fragen, wie man am einfachsten ein Control erstellt, wo man reinzeichnen kann. Im Speziellen möchte ich einzelne pixel malen können (es soll mal ne sinuskurve anzeigen).

Wie geht das am einfachsten ? Danke schonmal im voraus...

tuxipuxi
29-11-2002, 22:37
hi,

ich hab dein problem nicht ganz verstanden.
meinst du, dass der benutzer des programms reinzeichnen koennen soll?
dann solltest du dir mal die klasse QPainter angucken.


ciao michi

FireWare
30-11-2002, 12:16
ne, sorry wenn ich mich missverständlich ausgedrückt habe....


ich suche einfach ne fläche, in die man Programmseitig ne Sinuskurve reinzeichnen kann....

Wie in Delphi zum Beispiel n Imagecontrol, da kann man mit SetPixel reinzeichnen....

hoffe jetzt ist es klar....

anda_skoa
30-11-2002, 13:01
lane hat schon recht.
Du kannst mit einem QPainter auf jede Art von QPaintDevice zeichnen, d.h. zB auf jedes Widget.

Oder in ein QPixmap.

Ein QImage leraubt die direkt Manipulation der Pixeldaten, aber für das Zeichnen von Kurven, etc ist sicher QPainter eher geeignet.

Für Lurven hat dir vielleicht sogra jemand die Arbeit abgenommen.
Sie dir zB QWT an http://qwt.sourceforge.net/

Ciao,
_

FireWare
30-11-2002, 14:58
hmm mir reicht schon ein widget in das ich einzelne pixel reinsetzten kann...so komplex werden die kurven ja nich...einfache sinuskurven...

kann ich zum beispiel ein mit dem designer ein QPixmap widget auf meinen dialog machen und dann mit nem QPainter drauf pixel setzen ?

anda_skoa
30-11-2002, 16:05
Ein QPixmap ist kein Widget.

Du kannst mit QPainter auf QPaintDevice zeichnen.
QPixmap ist ein QPaintDevice, QWidget ist ein QPaintDevice.

Du kannst mit einem QPainter also direkt in das Hauptfenster zeichnen, in einen Dialog, oder einfach in einen leeren Frame.

Ciao,
_

FireWare
30-11-2002, 17:22
hmm kompliziert...

also ich hab jetzt im designer nen QFrame auf meine hauptform gemacht.....das programm lässt sich auch einwandfrei compilieren, wie zeichne ich jetzt genau da einen pixel in diesen QFrame rein ???

:confused:

anda_skoa
30-11-2002, 20:14
Das einfachste wird folgendes sein.

Nimm als Element im Desiger ein Pixmap Label.

Dann im Programm, wenn du neue Daten hast macht du dann



QPixmap* pixmap = label->pixmap();
QPainter p;
p.begin(pixmap);
///zeichnen
p.end();


Ciao,
_

tuxipuxi
01-12-2002, 10:43
da hab ich mal n beispielcode fuer dich:

header:



#ifndef _FUNCTIONPLOT_H
#define _FUNCTIONPLOT_H

#include <qapplication.h>
#include <qwidget.h>

typedef struct {
double x, y;
} valuePair;

//.................................................. . Klasse FunctionPlot
class FunctionPlot : public QWidget
{
public:
//... Konstruktor, dem die Anzahl der Wertepaare fuer
//... die zu plottende Funktion uebergeben wird
FunctionPlot( int n, QWidget *p=0, const char *name=0 );

//... Destruktor; gibt den fuer die Wertepaare
//... reservierten Speicherplatz wieder frei
~FunctionPlot() { delete [] values; }

//... setzt das i.te Wertepaar auf die Werte v.x und v.y
void setValue( int i, valuePair v );

//... setzt die ersten n Wertepaare auf die Werte aus dem Array v
void setValues( int n, valuePair v[] );

//... legt die minimalen und maximalen x- und y-Werte
//... des Bereichs fest, der von der Funktion anzuzeigen ist
void setPlotView( double minx, double miny, double maxx, double maxy );

//... bewirkt, dass die Funktion gezeichnet wird
void plotIt( void );

protected:

//... bewirkt ein Vergroessern des Funktionsbereichs
//... "Cursor rechts": negative x-Achse wird verlaengert
//... "Cursor links" : positive x-Achse wird verlaengert
//... "Cursor hoch" : negative y-Achse wird verlaengert
//... "Cursor tief" : positive y-Achse wird verlaengert
virtual void keyPressEvent( QKeyEvent *ev );

//... leitet ein Zoomen (Verkleinern des Funktionsbereichs) ein
virtual void mousePressEvent( QMouseEvent *ev );

//... Zoomen (Verkleinern des Funktionsbereichs) findet gerade statt
virtual void mouseMoveEvent( QMouseEvent *ev );

//... Zoomen (Verkleinern des Funktionsbereichs) wird abgeschlossen
virtual void mouseReleaseEvent( QMouseEvent *ev );

//... bewirkt ein Neumalen der Funktion in dem aktuell
//... festgelegten Funktionsbereich
virtual void paintEvent( QPaintEvent *ev );

private:

//... zeichnen die x- bzw. y-Achse
void drawXScale( QPainter *p, double i, int yp );
void drawYScale( QPainter *p, double i, int xp );

int valueNo; // Anzahl der Wertepaare der Funktion

valuePair *values; // enthaelt die einzelnen Wertepaare

bool plotViewSet; // zeigt an, ob explizit ein eigener
// anzuzeigender Funktionsbereich festgelegt
// wurde, also setPlotView() aufgerufen wurde.
// plotViewSet=false, werden die minimalen
// und maximalen x- und y-Werte des
// anzuzeigenden Bereichs implizit bestimmt

double minX, minY, maxX, maxY, // minimale und maximale x- und y-Werte
// des anzuzeigenden Bereichs
xFactor, yFactor; // interne Projektionsfaktoren

QPoint startPos, letztePos, neuePos; // Mauspositionen, die fuer
// das Zoomen mit der Maus
// benoetigt werden.
bool dragging, ersteMal; // fuer Ziehen der Maus benoetigt

QColor farbe; // zeigt an, ob Zoomen aktiviert ist (gruen)
// oder nicht (rot)
};

#endif


implementierung:



#include <qpainter.h>
#include <stdio.h>
#include "functionplot.h"

//.............................................. Konstruktor FunctionPlot
FunctionPlot::FunctionPlot( int n, QWidget *p, const char *name )
: QWidget( p, name ) {
valueNo = n;
values = new valuePair [n];
for ( int i=0; i<n; i++ )
values[i].x = values[i].y = 0.0;
plotViewSet = false;
}

//.................................................. ............ setValue
void FunctionPlot::setValue( int i, valuePair v ) {
if ( i >= valueNo || i < 0 )
return;
values[i] = v;
}

//.................................................. ........... setValues
void FunctionPlot::setValues( int n, valuePair v[] ) {
for ( int i=0; i<n; i++ )
setValue( i, v[i] );
}

//.................................................. ......... setPlotView
void FunctionPlot::setPlotView( double minx, double miny,
double maxx, double maxy ) {
plotViewSet = true;
minX = minx;
minY = miny;
maxX = maxx;
maxY = maxy;
}

//.................................................. ............ plotIt
void FunctionPlot::plotIt( void ) {
if ( !plotViewSet ) {
minX = maxX = values[0].x;
minY = maxY = values[0].y;
for ( int i=1; i<valueNo; i++ ) {
if ( values[i].x < minX ) minX = values[i].x;
if ( values[i].x > maxX ) maxX = values[i].x;
if ( values[i].y < minY ) minY = values[i].y;
if ( values[i].y > maxY ) maxY = values[i].y;
}
//.... Sicherstellen, dass Achsen sichtbar
if ( minX > 0 ) minX = 0;
if ( maxX < 0 ) maxX = 0;
if ( minY > 0 ) minY = 0;
if ( maxY < 0 ) maxY = 0;
}
repaint();
}

//.................................................. ..... keyPressEvent
void FunctionPlot::keyPressEvent( QKeyEvent *ev ) {
double diffX = (maxX-minX) / 10,
diffY = (maxY-minY) / 10;
switch (ev->key() ) {
case Key_Right: minX -= diffX; repaint(); break;
case Key_Left: maxX += diffX; repaint(); break;
case Key_Up: minY -= diffY; repaint(); break;
case Key_Down: maxY += diffY; repaint(); break;
}
}

//.................................................. ... mousePressEvent
void FunctionPlot::mousePressEvent( QMouseEvent *ev ) {
ersteMal = true;
dragging = false;
startPos = ev->pos();
repaint( false );
}

//.................................................. .... mouseMoveEvent
void FunctionPlot::mouseMoveEvent( QMouseEvent *ev ) {
if ( !dragging )
//.... Dragging (Ziehen) einschalten, wenn
//.... neue Position mind. 20 Pixel entfernt ist
if ( QABS( startPos.x() - ev->pos().x() ) >= 20 ||
QABS( startPos.y() - ev->pos().y() ) >= 20 )
dragging = true;
if ( dragging ) {
neuePos = ev->pos();
//.... Farbe zeigt an, ob Zoom aktiviert ist
if ( QABS( startPos.x() - ev->pos().x() ) >= 50 &&
QABS( startPos.y() - ev->pos().y() ) >= 50 )
farbe = Qt::green.light( 60 );
else
farbe = Qt::red.light( 150 );
repaint( false );
}
}

//.................................................. . mouseReleaseEvent
void FunctionPlot::mouseReleaseEvent( QMouseEvent *ev ) {
//.... Bedingung soll versehentliches Zoomen verhindern
if ( QABS( startPos.x() - ev->pos().x() ) >= 50 &&
QABS( startPos.y() - ev->pos().y() ) >= 50 ) {
if ( ev->pos().x() > startPos.x() ) {
maxX = ev->pos().x() / xFactor + minX;
minX = startPos.x() / xFactor + minX;
} else {
maxX = startPos.x() / xFactor + minX;
minX = ev->pos().x() / xFactor + minX;
}

if ( ev->pos().y() > startPos.y() ) {
minY = maxY - ev->pos().y() / yFactor;
maxY = maxY - startPos.y() / yFactor;
} else {
minY = maxY - startPos.y() / yFactor;
maxY = maxY - ev->pos().y() / yFactor;
}
}
dragging = false;
repaint();
}

//.................................................. ........ paintEvent
void FunctionPlot::paintEvent( QPaintEvent * ) {
QPainter p( this );

double xp, yp, diffX, diffY, i;

xFactor = width() / (maxX -minX),
yFactor = height() / (maxY -minY);

if ( dragging ) {
if ( !ersteMal )
p.eraseRect( QRect( startPos, letztePos ) );
p.fillRect( QRect( startPos, neuePos ), farbe );
letztePos = neuePos;
ersteMal = false;
}

p.setPen( Qt::yellow ); //.... x- und y-Achsen zeichnen
xp = -minX * xFactor;
yp = maxY * yFactor;
p.drawLine( 0, yp, width(), yp ); // x-Achse
p.drawLine( xp, 0, xp, height() ); // y-Achse

diffX = (maxX-minX) / 10; //.... x-Skalen zeichnen/beschriften
for ( i = -diffX; i>=minX; i-=diffX )
drawXScale( &p, i, yp );
for ( i = diffX; i<=maxX; i+=diffX )
drawXScale( &p, i, yp );

diffY = (maxY-minY) / 10; //.... y-Skalen zeichnen/beschriften
for ( i = -diffY; i>=minY; i-=diffY )
drawYScale( &p, i, xp );
for ( i = diffY; i<=maxY; i+=diffY )
drawYScale( &p, i, xp );

//.... Funktion zeichnen
xp = ( values[0].x - minX ) * xFactor;
yp = ( maxY - values[0].y ) * yFactor;
p.moveTo( xp, yp );
p.setPen( Qt::black );
p.setBrush( Qt::black );
p.drawEllipse( xp-1, yp-1, 2, 2 );

for ( i=1; i<valueNo; i++ ) {
xp = ( values[(int)i].x - minX ) * xFactor;
yp = ( maxY - values[(int)i].y ) * yFactor;
p.setPen( Qt::blue.light( 140 ) );
p.lineTo( xp, yp );
p.setPen( Qt::blue.light( 120 ) );
p.drawEllipse( xp, yp, 2, 2 );
}
}

//.................................................. .......... drawXScale
void FunctionPlot::drawXScale( QPainter *p, double i, int yp ) {
QString text;
double xs = (i-minX) * xFactor;

text.sprintf( "%.3g", i );
p->drawLine( xs, yp-2, xs, yp+2 );
p->drawText( xs+1, yp-2, text );
p->setPen( QPen( Qt::yellow, 0, Qt::DotLine ) ); // Raster
p->drawLine( xs, 0, xs, height() );
p->setPen( QPen( Qt::yellow, 0, Qt::SolidLine ) );
}

//.................................................. .......... drawYScale
void FunctionPlot::drawYScale( QPainter *p, double i, int xp ) {
QString text;
double ys = (maxY-i) * yFactor;

text.sprintf( "%.3g", i );
p->drawLine( xp-2, ys, xp+2, ys );
p->drawText( xp+4, ys, text );
p->setPen( QPen( Qt::yellow, 0, Qt::DotLine ) ); // Raster
p->drawLine( 0, ys, width(), ys );
p->setPen( QPen( Qt::yellow, 0, Qt::SolidLine ) );
}


und das beispiel dafuer:


#include <qapplication.h>
#include <qwidget.h>
#include <math.h>
#include "functionplot.h"

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

const double pi = 4*atan(1);
valuePair v;
int i=0, z=0;

for ( double x=-2*pi; x<3*pi; x+=0.01 ) // Zaehlen der Werte
z++;

FunctionPlot* plotWindow = new FunctionPlot( z );
plotWindow->resize( 500, 500 );
for ( v.x=-2*pi; v.x<=3*pi; v.x+=0.01 ) {
v.y = sin(v.x);
plotWindow->setValue( i, v );
i++;
}

plotWindow->plotIt();

myapp.setMainWidget( plotWindow );
plotWindow->show();
return myapp.exec();
}


Quelle: Das Qt-Buch, SuSE Press von Helmut Herold kapitel 18.

das duerfte das sein was dich interessiert.

gruss michi

anda_skoa
01-12-2002, 12:25
Boah, dass nenn ich Einsatz :)

Btw, ich glaube


#include <qapplication.h>

in functionplot.h ist nicht nötig.

und die Includes der C++ Standardheader sollten so lauten



#include <cstdio>




#include <cmath>


jeweils mit using namespace std; oder entsprechenden std:: vor den Funktionen.

Ab GCC3.2 gibt es sonst Schwierigkeiten.

Ciao,
_

FireWare
01-12-2002, 15:08
cool danke...

das nenn ich Hilfsbereitschaft.....

Gleich mal ausprobiern :D

FireWare
01-12-2002, 15:30
hmm....

jetzt hab ich nochn problem, der compiler meint....




/usr/lib/qt-3.0.4/bin/uic mainform.ui -i mainform.h -o .ui/mainform.cpp
g++ -c -pipe -Wall -W -O2 -DQT_NO_DEBUG -I/usr/lib/qt-3.0.4/include -I.ui/ -I/Development/sinus -I.moc/ -I/usr/lib/qt-3.0.4/mkspecs/default -o .obj/mainform.o .ui/mainform.cpp
In file included from .ui/mainform.cpp:21:
/Development/sinus/mainform.ui.h: In function `void init()':
/Development/sinus/mainform.ui.h:15: `label' undeclared (first use this function)
/Development/sinus/mainform.ui.h:15: (Each undeclared identifier is reported only once
/Development/sinus/mainform.ui.h:15: for each function it appears in.)
make: *** [.obj/mainform.o] Error 1




ich habe aber das Label richtig umbenannt.... von PixmapLabel1 in label...und in die datei auch die notwendige #include "mainform.h" , wo "label" definiert ist eingetragen....funzt trotzdem net....
weiss jemand warum ? ;-)

anda_skoa
02-12-2002, 16:20
Hmm, in mainform.cpp sollte label schon bekannt sein.

Hab aber noch nie so ein ui.h File gehabt, vielleicht muß man da was beachten.

Ciao,
_

FireWare
02-12-2002, 16:41
hmm :mad:

kann doch net so schwer sein *hmpf*

dieses ui.h file generiert "uic" nach einem make...

eigentlich muss ja die deklaration von dem label mit übernommen werden, weil die richtige datei #include'd wurde...

wenns nich zuviel arbeit macht könnte mal bitte jemand n simples programm zammstöpseln und mir an kixxass@gmx.net schicken, oder so ?

ich werd nochmal bissl rumprobieren, glaub aber nich dass ich das noch hinkriege :eek:

tuxipuxi
02-12-2002, 17:14
Original geschrieben von FireWare
hmm :mad:

kann doch net so schwer sein *hmpf*

dieses ui.h file generiert "uic" nach einem make...

eigentlich muss ja die deklaration von dem label mit übernommen werden, weil die richtige datei #include'd wurde...

wenns nich zuviel arbeit macht könnte mal bitte jemand n simples programm zammstöpseln und mir an kixxass@gmx.net schicken, oder so ?

ich werd nochmal bissl rumprobieren, glaub aber nich dass ich das noch hinkriege :eek:
was fuern programm?
versteh deine frage net