PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Auf vererbte Klasse zugreifen



xmarvel
29-05-2004, 11:58
hi
Habe folgenden Code geschrieben:

drawarea.h


#include <qwidget.h>
#include <qpainter.h>

class QDrawArea : public QWidget
{
Q_OBJECT

public slots:
void setToolButtonID(int id);

signals:
void sendMouseXPos(int);
void sendMouseYPos(int);

public:
QDrawArea(QWidget *parent = 0, const char *name = 0);

private:
void mousePressEvent(QMouseEvent *mouse);
void mouseMoveEvent(QMouseEvent *mouse);

int m_toolButtonID;

protected:
int getToolButtonID();
QPoint m_lastpos;
QPoint m_currentpos;
QPainter wPaint;
};

class CPaintEvents : public QDrawArea
{
public:
void freeHand();
};

drawarea.cpp

#include "drawarea.h"
#include <stdio.h>

QDrawArea::QDrawArea(QWidget *parent, const char *name) : QWidget(parent, name)
{
setPaletteBackgroundColor(QColor (255, 255, 255));
setMouseTracking(true);
}

void QDrawArea::setToolButtonID(int id)
{
m_toolButtonID=id;
}

int QDrawArea::getToolButtonID()
{
printf("getID: %i\n", m_toolButtonID);
return (m_toolButtonID);
}

void QDrawArea::mousePressEvent(QMouseEvent *mouse)
{
CPaintEvents paint;
wPaint.begin(this);

m_lastpos = mouse->pos();

switch (m_toolButtonID)
{
case 0: paint.freeHand();
break;
case 1: getToolButtonID();
break;
case 2:
break;
}
wPaint.end();
}

void QDrawArea::mouseMoveEvent(QMouseEvent *mouse)
{
m_currentpos = mouse->pos();
emit sendMouseXPos(mouse->pos().x());
emit sendMouseYPos(mouse->pos().y());
}

void CPaintEvents::freeHand()
{
//wPaint.drawLine(QPoint(80,29), QPoint(90,32));
printf("freeHandID: %i\n", getToolButtonID());
}

Jetzt wollte ich mittels getToolButtonID in der geerbten Klasse CPaintevents holen.
Jetzt bekomme ich aber in der Methode freeHand() von der geerbeten Klasse CPaintEvents nur falsche Werte von getToolButtonID().
Nur wieso ? Wenn ich die Methode getToolButton() in der Klasse QDrawArea aufrufe dann bekomme ich den richtigen Wert.
Hoffe um Hilfe sitzt schon seit zwei Tagen an den Problem

Gruss
xmarvel

bmann
29-05-2004, 12:56
Moin

In der Methode void QDrawArea::mousePressEvent(QMouseEvent *mouse) erzeugst du als erstes ein neues Objekt der Klasse CPaintEvents:


CPaintEvents paint;


Die erste Methode die du für dieses Objekt aufrufst, ist freehand():


switch (m_toolButtonID)
{
case 0: paint.freeHand();
[...]


CPaintEvents::freeHand() gibt einfach getToolButtonID(), d.h. m_toolButtonID aus. Soweit so gut.
Nun schauen wir uns doch mal an welchen Wert paint.m_toolButtonID zu dem Zeitpunkt hat.
Also wie gesagt rufst du zwischen Erzeugung des Objektes und Aufruf von freeHand() keine Methoden auf, also ist lediglich der Konstruktor von CPaintEvents und von QDrawArea interessant.
Von CPaintEvents hast du keinen Konstruktor gepostet, ich nehme also an du hast da keinen relevanten. Es bleibt QDrawArea. Da rührst du m_toolButtonID aber gar nicht an.

Der Effekt: m_toolButtonID hat zu dem Zeitpunkt, an dem du freeHand() aufrufst genau den Wert, der grade (bei der Erzeungung des Objektes in mousePressEvent()) an der entsprechenden Stelle im Speicher stand, also mit anderen Worten: Datenmüll. Das kann jeder beliebige Wert sein, aber garantiert nicht der Wert den du erwartest.

Was soll denn der Code bewirken?

CU
Andi

xmarvel
29-05-2004, 13:53
wenn ich CPaintEvents paint aufrufe da erzeuge ich doch ein neues Objekt von CPaintEvents.
Aber wird da auch gleichzeitig ein neues Objekt von QDrawArea erzeugt ?

Desweiteren kann ich doch garnichts im Konstrukter von QDrawArea schreiben was mit der Variable m_toolButtonID zu tuen hat da die Variable ja immer neu gesetzt wird.
Wie soll ich die Methode sonst aufrufen damit er nicht auf Datenmüll zugreift und eben die aktuelle m_toolButtonID Variable nimmt ?

Die Funktionsweise ist eigentlich simpel. Ich habe verschiedene ToolButtons in ein ButtonGroup zusammengefügt.
Bei jedem Klick wird per slot/signal Technik die aktuelle ID des ToolButtons über QDrawArea::setToolButtonID(int id) die Variable m_toolButtonID gesetzt.
Dann wird in der QDrawArea::mousePressEvent entschieden was bei welchem Button passiert.
Nur was passiert wollte ich auslagern in eine neue Klasse. Dazu habe ich mir die Klasse CPaintEvents erzeugt . Nur um darauf zu reagieren bräuchte ich ein paar Parameter. Wie z.B. den QPainter wPaint oder m_lastpos und m_currentpos. Die ToolButtonID bräuchte ich zwar nicht in der Klasse aber zum Testen ist sie besser geeignet.

Gruss
xmarvel

anda_skoa
29-05-2004, 15:10
Original geschrieben von xmarvel
wenn ich CPaintEvents paint aufrufe da erzeuge ich doch ein neues Objekt von CPaintEvents.
Aber wird da auch gleichzeitig ein neues Objekt von QDrawArea erzeugt ?

Die CPaintEvent Instanz ist so ein Objekt.



Desweiteren kann ich doch garnichts im Konstrukter von QDrawArea schreiben was mit der Variable m_toolButtonID zu tuen hat da die Variable ja immer neu gesetzt wird.


Initialisieren schaded generell nicht.



Wie soll ich die Methode sonst aufrufen damit er nicht auf Datenmüll zugreift und eben die aktuelle m_toolButtonID Variable nimmt ?

Er nimmt den aktuellen Wert der Variable, nur da die Variable bis zu diesem Zeitpunkt nicht setzt oder initialisiert wurde, ist der Wert zufällig.



Bei jedem Klick wird per slot/signal Technik die aktuelle ID des ToolButtons über QDrawArea::setToolButtonID(int id) die Variable m_toolButtonID gesetzt.

Dazu wäre aber logischerweise eine Signal/Slot Verbindung notwendig, oder?

Ciao,
_

xmarvel
29-05-2004, 15:57
Initialisieren schaded generell nicht.
dann wird doch immer die initilaisierte aufgerufen. Aber nicht das gesetzte.


Er nimmt den aktuellen Wert der Variable, nur da die Variable bis zu diesem Zeitpunkt nicht setzt oder initialisiert wurde, ist der Wert zufällig.
Die Variable wurde ja eigentlich gesetzt aber in der Klasse QDrawArea dort kann ich
sie ja auch abfragen.


Dazu wäre aber logischerweise eine Signal/Slot Verbindung notwendig, oder?
Die Verbindung besteht aber woanders. ;)

Da ich das immer noch nicht verstanden habe wie ich das umgehen kann und ich es warscheinlich auch schlecht erklären kann habe ich mal das komplette (nicht sehr grosses Programm) rangehängt in der Hoffnung das sich mal jemand es anschaut. Es geht eigentlich nur um die beiden Dateien drawbox.h und drawbox.cpp
Wenn man den Knopf 0 drückt dann wird die Methode freeHand aufgerufen der wiederum getToolButtonID holt. Nur eben nur Müll.
Bei Knopf 1 wird direkt getToolButton aufgerufen.
Knopf 3 macht nix :D

Gruss
xmarvel

P.S.: zum compilieren einfach qmake -project && qmake && make eingeben oder direkt starten.

anda_skoa
29-05-2004, 18:02
Original geschrieben von xmarvel
dann wird doch immer die initilaisierte aufgerufen. Aber nicht das gesetzte.

Es wurde zu dem Zeitpunkt noch kein Wert gesetzt, das Objekt wurde ja gerade erst erzeugt!



Die Variable wurde ja eigentlich gesetzt aber in der Klasse QDrawArea dort kann ich
sie ja auch abfragen.

Also du setzt die Variable eines Objektes und wunderst dich dann, wenn ein anderes Object diesen Wert nicht hat?



Die Verbindung besteht aber woanders. ;)

Schön, aber dann kannst du auch nicht erwarten, dass das neue Objekt einen Wert in seiner Variable hat, wenn ein ganz anderes Objekt diesen bekommen hat, oder?

Ciao,
_

xmarvel
29-05-2004, 19:09
Ich will jetzt nicht blöde klingen und warscheinlich denken jetzt einige der Kerl soll lieber die Finger von der Sache lassen und lieber auf Visual Basic umsteigen :D . Aber trotzdem habe ich das Problem noch nicht lösen können. (Ausser ich mache die Methoden nicht extra in einer Klasse rein).
Ich weiss das ich ein neues Objekt erstelle aber wieso kann das neue Objekt denn nicht auf das alte Objekt zugreifen. Das verschwindet doch nicht.


Also du setzt die Variable eines Objektes und wunderst dich dann, wenn ein anderes Object diesen Wert nicht hat?
Ich wundere mich eher warum das andere Object (hier CPaintEvents) nicht auf das erste Object (hier QDrawArea) zugreifen kann ?


Schön, aber dann kannst du auch nicht erwarten, dass das neue Objekt einen Wert in seiner Variable hat, wenn ein ganz anderes Objekt diesen bekommen hat, oder?
ja aber das neue Objekt soll ja vom "alten" Object ja den Wert holen denn das alte Object hat den Wert ja gesetzt bekommen.

Gruss
xmarvel

anda_skoa
29-05-2004, 19:36
Original geschrieben von xmarvel
Ich weiss das ich ein neues Objekt erstelle aber wieso kann das neue Objekt denn nicht auf das alte Objekt zugreifen. Das verschwindet doch nicht.

Nein, aber es ist ein anderes Objekt.
Wenn du zwei Äpfel hast und aus einem die Kerne rausnimmst, sind sie ja immer noch im zweiten Apfel drinnen.
Wenn du bei einem Objekt einen Wert änderst, lässt das jedes andere Objekt ziemlich kalt :)


ja aber das neue Objekt soll ja vom "alten" Object ja den Wert holen denn das alte Object hat den Wert ja gesetzt bekommen.


Das ist kein Problem, du musst nur am ersten Objekt das get aufrufen und dann ein set am neuen Objekt, dann haben beide den gleichen Wert.

Ciao,
_

xmarvel
29-05-2004, 20:24
so langsam macht es *klick* bei mir.
Das heisst man kann auf keine Variablen einer Klasse zugreifen wenn man dafür keine Methode besitzt (z.B. get oder set). Das gilt auch für veerbte Klassen.
Wenn man was hollen will dann muss man in der ziel Klasse selber eine lokale Variable erzeugen wo man den geholten Wert zwischenspeichert.
Methoden mit return Werten wären also sinnlos bei zugriffen von anderen Klassen.
Habe ich das so richtig verstanden ?

Gruss
xmarvel

anda_skoa
30-05-2004, 15:29
Das hat weniger mit verschiedenen Klassen zu tun, sondern viel mehr mit verschiedenen Instanzen von Klassen.
Auch zwei Instanzen der selben Klasse haben eigene Variablen, eine Klasse ist eine Beschreibung eines Objekts, aber erst die Realisierung, also die Instanz bekommt Speicher zugeordnet (*)

Deine Ableitung war auch sehr ungünstig gewählt.
Die DrawArea ist ein Widget, das CPaintEvent ist damit auch eins, obwohl es keines sein muss, es sollte ja, wenn ich das richtig verstanden habe, nur die Events für die DrawArea bearbeiten.

Der Ansatz ansich ist nicht schlecht, nur würde es reichen, einmal pro DrawArea ein Objekt der CPaintEvent Klasse anzulegen und nicht jedes mal in zB mousePressEvent.

Ciao,
_

(*) Es gibt schon die Möglichkeit, Variablen zwischen Instanzen zu teilen, sogenannte "static members", aber hier ist der Fall einer falschen Ableitung das Hauptproblem, eine Ableitung sollte immer eine "ist ein" Beziehung sein, also zB die DrawArea ist ein Widget.

Ciao,
_

xmarvel
31-05-2004, 09:59
thx für die ganzen Anwtorten was würde ich ohne das Forum machen. :p

hab es jetzt folgender Masse gemacht:



#include <qwidget.h>
#include <qpainter.h>

class CPaintEvents
{
protected:
void freeHand(QPainter* &draw);

void setLastPos(QPoint pos);
void setCurrentPos(QPoint pos);

private:
QPoint m_lastpos;
QPoint m_currentpos;
};


class QDrawArea : public QWidget, public CPaintEvents
{
Q_OBJECT

public slots:
void setToolButtonID(int id);

signals:
void sendMouseXPos(int);
void sendMouseYPos(int);

public:
QDrawArea(QWidget *parent = 0, const char *name = 0);

private:
void mousePressEvent(QMouseEvent *mouse);
void mouseMoveEvent(QMouseEvent *mouse);

QPainter* draw;
int m_toolButtonID;
};

Jetzt wird auch kein neues Objekt bei jedem Mausklick erzeugt.

MFG
xmarvel

anda_skoa
31-05-2004, 11:06
Nur ein paar stilistische Anmerkungen:


Original geschrieben von xmarvel
void freeHand(QPainter* &draw);

Hier reicht QPainter*, du arbeitest nur mit dem Painter Objekt, seinen Pointer willst du nicht verändern.



void setLastPos(QPoint pos);
void setCurrentPos(QPoint pos);


Bei der Übergabe von Objekten nimmt man üblicherweise const &, das erlaubt dem Compiler das selbe Objekt zu benutzen und er muss für den Methodenaufruf keine lokale Kopie erzeugen


void setLastPos(const QPoint& pos);


Ciao,
_