eigene Klasse für QGraphics Elemente

Du bist neu in der Welt von C++? Dann schau hier herein!
Antworten
Artemus
Beiträge: 15
Registriert: 14. Januar 2012 16:50

eigene Klasse für QGraphics Elemente

Beitrag von Artemus »

Hallo Leute,

ich bin relativ neu was C++ im allgemeinen und Qt im speziellen angeht. Habe bis jetzt eher Mikrocontroller in C programmiert (auch ARM Cortex-M) und u.a. ein Projekten mit einem Umfang von >40k Zeilen Quellcode. Trotzdem wird euch meine Frage jetzt vielleicht "doof" vorkommen :oops:

Ich will eine Klasse erstellen die mehrere Objekte in einer QGraphicsScene zusammen fasst.
Zuerst einmal reichen mir 4 gerade Linien (später sollen dann u.a. noch 4 acrTo, 1 Linie, 2 Textfelder, sowie ein Array aus Zeigern auf andere Elemente der selben Klasse dazu kommen).

Da ich mehrere dieser Gruppen dieses Typs in einer QGraphicsScene verwenden will muss ich ja einen Zeiger auf die Scene übergeben, richtig?

Code: Alles auswählen

public:
    QGraphicsScene* pq_scene;
außerdem benötige ich 4 Koordinaten (zwischen denen ich die Linien zeichnen will)

Code: Alles auswählen

static qreal ax, ay, bx, by, cx, cy, dx, dy;

Wie muss ich die Linien (Typ: QGraphicsLineItem) jetzt deklarieren (und kann man diese auch private machen)?


Also der Code geht nich:

Code: Alles auswählen

class pr_state : public QMainWindow
{
    Q_OBJECT
public:
    QGraphicsScene* pq_scene;
    explicit pr_state(QWidget *parent = 0);
    static qreal ax, ay, bx, by, cx, cy, dx, dy;
    void draw_state(void);

signals:

public slots:

private:

    QGraphicsLineItem q_line1, q_line2, q_line3, q_line4;

};

void pr_state::draw_state(void)
{
    q_line1 = pq_scene.addLine( ax, ay, bx, by, QPen() );
    q_line2 = pq_scene.addLine( bx, by, cx, cy, QPen() );
    q_line3 = pq_scene.addLine( cx, cy, dx, dy, QPen() );
    q_line4 = pq_scene.addLine( dx, dy, ax, ay, QPen() );
}
almboa
Beiträge: 21
Registriert: 27. September 2009 11:52

Re: eigene Klasse für QGraphics Elemente

Beitrag von almboa »

Dein Compiler sagt dir, warum das nicht geht!
Kannst ja mal schauen was addLine zurückgibt...
Artemus
Beiträge: 15
Registriert: 14. Januar 2012 16:50

Re: eigene Klasse für QGraphics Elemente

Beitrag von Artemus »

Ich habe gestern noch ein bisschen rumprobiert und die Funktionalität erst einmal ohne Klasse umgesetzt:

Code: Alles auswählen

typedef struct
{
    QGraphicsLineItem* pq_line1;
    QGraphicsLineItem* pq_line2;
    QGraphicsLineItem* pq_line3;
    QGraphicsLineItem* pq_line4;
}ST_STATE;

void state_init( ST_STATE* pst_state, QGraphicsScene* pq_scene )
{
    pst_state->pq_line1 = pq_scene->addLine(0,0,0,0,QPen());
    pst_state->pq_line2 = pq_scene->addLine(0,0,0,0,QPen());
    pst_state->pq_line3 = pq_scene->addLine(0,0,0,0,QPen());
    pst_state->pq_line4 = pq_scene->addLine(0,0,0,0,QPen());
}

// und zum Testen:
void MW::btn_1_handler(void)
{
    static int i;
    static ST_STATE st_state1;
    i++;

    if(i==1 )
    {
        ui->view->setScene(&scene);
        state_init(&st_state1, &scene);
    }

    if(i==2 ) st_state1.pq_line1->setLine( 0,0,  0,20);
    if(i==3 ) st_state1.pq_line2->setLine(10,0, 10,30);
    if(i==4 ) st_state1.pq_line3->setLine(20,0, 20,40);
    if(i==5 ) st_state1.pq_line4->setLine(30,0, 30,50);
    if(i==6 ) st_state1.pq_line3->setLine(40,0, 40,40);
    if(i==7 ) st_state1.pq_line2->setLine(50,0, 50,30);
    if(i==8 ) st_state1.pq_line1->setLine(60,0, 60,20);

    ui->view->show();
    ui->log->append("done..");
}
das Ganze als Klasse sieht jetzt so aus:

Code: Alles auswählen

#define KONSTRUCT_STATE CL_STATE

class CL_STATE
{
public:
    CL_STATE( QGraphicsScene* pq_scene );
    QGraphicsScene* pq_scn;
    QGraphicsLineItem* pq_line1;
    QGraphicsLineItem* pq_line2;
    QGraphicsLineItem* pq_line3;
    QGraphicsLineItem* pq_line4;

signals:

public slots:

private:
};

CL_STATE::CL_STATE( QGraphicsScene* pq_scene ):
    pq_scn(pq_scene)
{
    pq_line1 = pq_scn->addLine(0,0,0,0,QPen());
    pq_line2 = pq_scn->addLine(0,0,0,0,QPen());
    pq_line3 = pq_scn->addLine(0,0,0,0,QPen());
    pq_line4 = pq_scn->addLine(0,0,0,0,QPen());
}

// zum Testen
void MW::btn_1_handler(void)
{
    static int i;   
    i++;
    static CL_STATE cl_state1 = KONSTRUCT_STATE(&scene);

    if(i==1 ) ui->view->setScene(&scene);

    if(i==2 ) cl_state1.pq_line1->setLine( 0,0,  0,20);
    if(i==3 ) cl_state1.pq_line2->setLine(10,0, 10,30);
    if(i==4 ) cl_state1.pq_line3->setLine(20,0, 20,40);
    if(i==5 ) cl_state1.pq_line4->setLine(30,0, 30,50);
    if(i==6 ) cl_state1.pq_line3->setLine(40,0, 40,40);
    if(i==7 ) cl_state1.pq_line2->setLine(50,0, 50,30);
    if(i==8 ) cl_state1.pq_line1->setLine(60,0, 60,20);

    ui->view->show();
    ui->log->append("done..");
}
Mal von Konstruktor und Destruktor abgesehen ist eine Klasse ja wie ein Struct aus Daten und Funktionszeigern...zumindest hilft es wenn ich mir das so Vorstelle :wink:
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: eigene Klasse für QGraphics Elemente

Beitrag von franzf »

Nur ein paar Sachen:
* Daten-Member einer Klasse sollten wg. Kapselung private sein. (Gibt Ausnahmen, dein Fall ist aber keine!)
* CL_STATE ist problematisch, denn ALLES_IN_GROSSBUCHSTABEN deutet auf Konstanten oder Präprozessor-Makros hin.
* Was soll der Präfix "CL" bedeuten? Wenn es ne Abkürzung ist: Lass es, schreib es aus. Es existiert keine Beschränkung (mehr) in der Länge der Namen deiner Bezeichner.
* Selbiges gilt für "MW".

Ansonsten: Ja class und struct sind EXAKT das GLeiche mit dem einen Unterschied, dass bei struct default alles public ist, bei class alles private (Sichtbarkeit der Member, Vererbung)
Artemus
Beiträge: 15
Registriert: 14. Januar 2012 16:50

Re: eigene Klasse für QGraphics Elemente

Beitrag von Artemus »

erstmal danke für die Hinweise.
franzf hat geschrieben: * CL_STATE ist problematisch, denn ALLES_IN_GROSSBUCHSTABEN deutet auf Konstanten oder Präprozessor-Makros hin.
* Was soll der Präfix "CL" bedeuten? Wenn es ne Abkürzung ist: Lass es, schreib es aus. Es existiert keine Beschränkung (mehr) in der Länge der Namen deiner Bezeichner.
Die zwei oben genannten sachen sind einfach Angewohnheiten die ich eientlich auch so beibehalten will.
Alles was ich komplett groß schreibe sind Definitionen, also Konstanten und Makros mittels #define, und Structs/Enums/Unions mittels typedef.
Wenn aus der Typdefinition dann eine Variable wird schreibe ich es wieder klein.

Außerdem verwende ich für alle variablen präfixe die auf den Typ hinweisen:
st -> struct
en -> enum
un -> union
a -> array
p -> pointer
u8, u16, u32 -> unsigned integer X
s8, s16, s32 -> signed integer X
f32 -> float

also z.B. apst_xyz ist ein Array aus Zeigern auf eine Struktur.
Wenn man mal einen Zeiger auf ein Array aus Zeigern auf eine Strutur erstellen muss die u.a. eine Union enthält, welche einen Zeiger auf ein zweidimensionales Feld aus Zeigern auf Zeichenketten aufnimmt, dann ist das ganz nützlich um den Durchblick zu behalten.
Leider unterstützen nicht alle IDEs für den Embedded Bereich Autovervollständigung des Quellcodes :?

Seid ich mit C++ arbeite sind halt cl für Class und c für char dazu gekommen (vorher waren meine Zeichenketten immer vom Typ uint8 also -> au8_xyz).
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Re: eigene Klasse für QGraphics Elemente

Beitrag von RHBaum »

Seid ich mit C++ arbeite sind halt cl für Class und c für char dazu gekommen
Man sollte aber lieber vorhandene Notationen verwenden, als seine eigenen kreieren :-)
Generelle Prefixe die nur Typen bedeuten sind mittlerweile eher verpohnt, aber trotzdem findet man es noch oft. Siehe Disskussion, C-Klassen Prefix bei MFC. Mit namespaces liesse sich das alles besser und einfacher loesen. DIe Notationen entwickeln sich halt auch weiter, gemeinsam mit den Compileren.
dann ist das ganz nützlich um den Durchblick zu behalten.
Ja das ist wichtig. Nur frage Dich auch, ob andere auch dadurch den Überblick behalten ...
Also mit au8_xxx koennt ich zum Beispiel gar nix anfangen, ich hoffe du hasst das gut dokumentiert :-)
Leider unterstützen nicht alle IDEs für den Embedded Bereich Autovervollständigung des Quellcodes
Autovervollständigung ist natürlich sehr nützlich, aber manchmal kontraproduktiv zur Lesbarkeit.
Autovervollständigung sollte also wirklich keinerlei einfluss auf deine Notation haben ...

ciao
Artemus
Beiträge: 15
Registriert: 14. Januar 2012 16:50

Re: eigene Klasse für QGraphics Elemente

Beitrag von Artemus »

RHBaum hat geschrieben:
Seid ich mit C++ arbeite sind halt cl für Class und c für char dazu gekommen
Man sollte aber lieber vorhandene Notationen verwenden, als seine eigenen kreieren :-)
In dem Forum wo ich mich sonst bewege würde man dich für dieses Satz steinigen :lol:

das Problem ist z.B. das ein "int" je nach Zielsystem und Compiler 16 oder 32 bit groß sein kann. Wenn man auf einem 8-Bit-System ne Variable braucht für die 16Bit ausreicht, der Compiler aber ne 32Bit draus macht, wird unnötig Programmspeicher verschwendet (für Arithmetik-Libraries) und das Programm unnötig langsam. Brauch man aber volle 32Bit und beim Wechsel auf andere IDE oder anderes System wird aus dem int ne 16Bit hat man ein großes Problem den ganzen Quellcode zu überarbeiten und bei jeder variablen neu zu überlegen welchen Bereich man benötigt.
Wenn du schon mal ein System mit 8 kByte RAM und 128 kByte Programm/Datenspeicher programmiert hast weißt du wovon ich rede. (Manch einer würde sich wundern was man damit alles machen kann ^^).

Datentypen wie uint16 und sint8 habe ich mir nicht selbst ausgedacht, sie zeugen von guten Programmierstiel im Embedded-Bereich und sind in vielen Firmen in internen Programmierstandards vorgeschrieben.

Stichwort MISRA-C.
RHBaum hat geschrieben:Generelle Prefixe die nur Typen bedeuten sind mittlerweile eher verpohnt, aber trotzdem findet man es noch oft.
Ich finde sie eher hilfreich beim lesen von fremden Quelltext. Schließlich Kommentiert man ja nicht was ein Quellcodeabschnitt macht (das wäre ja redundant) sonder WARUM er es (so) macht. Beim verstehen was da vor sich geht ist es IMO sehr hilfreich.

Aber wir kommen anscheinen aus zwei unterschiedlichen Welten des Programmierens. 8)
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: eigene Klasse für QGraphics Elemente

Beitrag von franzf »

Datentypen wie uint16 und sint8 habe ich mir nicht selbst ausgedacht, sie zeugen von guten Programmierstiel im Embedded-Bereich und sind in vielen Firmen in internen Programmierstandards vorgeschrieben.
uint8_t usw. kommen direkt aus stddef.h, da muss sich keine Firma was ausdenken. sint (für signed int?) ist doof, intN_t erfüllt das eh schon. Und wenns um Perfomance geht, nimmst du eben NICHT uint32_t, sondern uint_fast32_t.
Das u als Präfix ist hier im übrigen nötig, da man selber keinen typedef wie "unsigned int32" machen darf, denn für eigene Bezeichner (trifft auch für normale Header wie stddef.h zu) ist das Leerzeichen Tabu.
Ich finde sie eher hilfreich beim lesen von fremden Quelltext.
Es hilft nur was, wenn die Prä/Postfixe dokumentiert sind. Und für alle möglichen Fälle einen Präfix, da setzt es irgendwann aus ;)
Der Bezeichner sollte genügend Auskunft darüber geben, was mit ihm bezweckt wird, da braucht es mMn. keine Präfixe. Zum Code pflegen kann es sogar recht umständlich werden. Stell dir vor, ihr stellt von rohen Arrays auf Containerklassen um. Dann müssen ALLE Bezeichner den Präfix a (Array) nach v (vector) ändern. Die ganze Zeigerarithmetik weicht dann Iteratoren -> wieder Präfixe in ALLEN Codeteilen ändern.
Und alles vollkommen umsonst, denn viele Teile hätten nur minimal geändert werden müssen. (pa_pos++ -> it++, usw. könnten bleiben), wenn man schon bei den Arrayzugriffen konsequent auf std::begin() setzt, bleibt sogar noch weniger.
Schließlich Kommentiert man ja nicht was ein Quellcodeabschnitt macht (das wäre ja redundant) sonder WARUM er es (so) macht. Beim verstehen was da vor sich geht ist es IMO sehr hilfreich.
Beim Verstehen ist es eigentlich auch wurscht, ob der Indextyp signed oder unsigned ist, ob man jetzt mit char oder wchar_t arbeitet, ob der Typ ein struct, Klasse oder typedef ist. Der NAME (Bezeichern) ist ausschlaggebend. first_name, second_name, usw. Da noch mit "ca_first_name" rumzuwerkeln ist überflüssig.
Aber wir kommen anscheinen aus zwei unterschiedlichen Welten des Programmierens. 8)
Nö, es liegen nur unterschiedliche Ansichten vor, die Welt ist die selbe.
Artemus
Beiträge: 15
Registriert: 14. Januar 2012 16:50

Re: eigene Klasse für QGraphics Elemente

Beitrag von Artemus »

franzf hat geschrieben:sint (für signed int?) ist doof, intN_t erfüllt das eh schon.
Welch brillantes Argument :D
IMHO ist es doch Wurst ob man sint32 oder int32 oder int32_t schreibt solange der Typ eindeutig beschrieben ist.
franzf hat geschrieben:Und wenns um Perfomance geht, nimmst du eben NICHT uint32_t, sondern uint_fast32_t.
Wenn du mir nen Mikrocontroller zeigst der mit 64Bit-Integer schneller rechnet als mit nem 32Bit-Integer dann mach ich das. Da aber nicht mal die 8Bit-Mikrocontoller so wirklich vom Markt verdrängt wurden kann es noch ne gaaaanze weile dauern bis es so weit ist.
franzf hat geschrieben: Stell dir vor, ihr stellt von rohen Arrays auf Containerklassen um. Dann müssen ALLE Bezeichner den Präfix a (Array) nach v (vector) ändern. Die ganze Zeigerarithmetik weicht dann Iteratoren -> wieder Präfixe in ALLEN Codeteilen ändern.
Vektoren gibts in MISRA-C nicht. Ich bin mir nicht mal sicher obs die in C99 gibt.
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: eigene Klasse für QGraphics Elemente

Beitrag von solarix »

Ich verstehe grundsätzlich das Bedürfnis, Bewährtes beizubehalten (das ist Menschlich.. das macht der Malermeister genauso wie der Software-Entwickler). Trotzdem bin ich gleicher Meinung wie franzf und RHBaum: vermische Äpfel nicht mit Birnen! Ich verstehe deine Welt schon, aber du schreibt in einem Qt-Forum! Die Entwicklung von Software unter einem Betriebsystem mit einem (Klassen)Framework ist eine andere Disziplin als das Schreiben von Firmware ab grüner Wiese..

Daher nur folgende Punkte:
Man sollte aber lieber vorhandene Notationen verwenden, als seine eigenen kreieren :-)

In dem Forum wo ich mich sonst bewege würde man dich für dieses Satz steinigen
Kann ich nicht glauben. Du widersprichst dir da auch selber mit "sind in vielen Firmen in internen Programmierstandards vorgeschrieben". Also nutzt du ja bereits kein eigener, sondern ein "vorhandenen Standard". Das ist das was franz meinte: erfinde nicht selbst einen Standard, sondern nehme den des Frameworks/der Firma/des Projektes/whatever.. aber kein _neuer_!

Weiter...

Code: Alles auswählen

class CL_MYWIDGET : public QWidget
.. sieht sch.. aus. Musst du selbst zugeben. Daher die Anregung: sieh dir die Doku von Qt an und überlege, ob du im Qt-Projekt nicht gleich diesen Stil übernehmen kannst. "class PrjWidget : public QWidget" sieht homogener aus.

Weiter: Nutze in der Qt-Welt -soweit du die Wahl hast- auch Qt-Möglichkeiten. z.B. QList & CO anstelle C-Arrays.

Weiter : Die Namensgebung der Variabeln würde ich mir auch gut überlegen. Auf Hardware-Ebene können Datentypen als Bestandteil des Namens schon Sinn machen, aber bei der OOP-Entwicklung von Server/Desktop-Software (Dienste, GUIs usw.) sind mir(!) die "Rollen" der Variabeln wichtiger (Klassen-Member, Laufvariabel, Methoden-Argument, temporär, usw.). Ich empfinde also

Code: Alles auswählen

mVariable = aVariable;  // Klassenmember wird mit Methoden-Argument überschrieben
sinnvoller als

Code: Alles auswählen

uint32_variable = uint32_anderevariabel;
Aber ich muss ja auch nicht deine Software maintainen ;). Sei einfach offen gegenüber der Qt-Welt und gegenüber Veränderungen. Wenn du von der Firmware-Entwicklung in ein ASP.NET-Team welchseln würdest (Gott bewahre), würdest du dich auch auch um die typischen Vorgehensweisen und Standards bemühen (des SW-Teams, der Programmiersprache und den bestehenden Applikationen).

hth!
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Re: eigene Klasse für QGraphics Elemente

Beitrag von RHBaum »

denk mal, das zwischen Embedded C Programmierung und C++ schon Welten liegen ...
und sind in vielen Firmen in internen Programmierstandards vorgeschrieben
Richtig, letztlich kam unser ProjektManager auch mit Coding Standards, und die kamen offensichtlich aus der Embedded C Welt :twisted:

Das su8 kam mir also gar ned so unbekannt vor :-)

Das problem nur, dass man die Standards nicht auf C++ anwenden sollte. Das ist wie, wenn C++ standards versuchst in Python einzuhalten.
Coding standards sollten zu leserlicheren Code fuehren, und da rangiert allein C++ auf ganz anderer Ebene als wie C !

Die Hälfte vom Inhalt des Dokuments konnt Ich eh gleich rausstreichen, weil kein Style, sondern Sprachmittel :-)
Da stand wörtlich drinn: "Virtuelle Funktionen sind mit dem Schlüsselwort 'virtual' zu kennzeichnen! "
Und nein, sie meinten nicht eine überschriebene virtuelle Funktion, sondern auch neue :-)

Gab es in irgendeinen C-Dialekt / Objective C mal nen optionales Schlüsselwort "virtual" ?

Fuer das meiste braucht man keinen "Industriellen" Coding Standard ... C++ Style schreibt zum Glueck schon ne Menge vor, mit eigenen coding styles.
Wir sind gar nicht so "frei" wie C-Entwickler :-)
Die Firmen-internen sollten das nur ergänzen, und kein c++ Lehrbuch zitieren

Ciao ...

p.s.
Ich hab noch keinen wirklich guten ergänzenden firmeninternen Coding Style-Guide fuer C++ gesehen.
Aber es gibt Sie sicherlich ! ....... irgendwo da draussen
Ich würd gern mal einen bekommen, um den meinen Managern .....
Artemus
Beiträge: 15
Registriert: 14. Januar 2012 16:50

Re: eigene Klasse für QGraphics Elemente

Beitrag von Artemus »

solarix hat geschrieben: Weiter : Die Namensgebung der Variabeln würde ich mir auch gut überlegen. Auf Hardware-Ebene können Datentypen als Bestandteil des Namens schon Sinn machen, aber bei der OOP-Entwicklung von Server/Desktop-Software (Dienste, GUIs usw.) sind mir(!) die "Rollen" der Variabeln wichtiger (Klassen-Member, Laufvariabel, Methoden-Argument, temporär, usw.). Ich empfinde also

Code: Alles auswählen

mVariable = aVariable;  // Klassenmember wird mit Methoden-Argument überschrieben
sinnvoller als

Code: Alles auswählen

uint32_variable = uint32_anderevariabel;
Für die Geltungsbereich verwendete ich in C auch Bezeichner im Präfix:
g -> global
m -> modul (also nur in dieser Übersetzungseinheit gültig)
nix -> lokal
außerdem haben Laufvariablen die z.B. nur in einer for-Schleife verwendet werden gar keinen Präfix. (das üblich for(i=0;... kann man also weiter verwenden)

Die Notwendigkeit zwischen Argumenten und temporären Variablen zu unterscheiden sehe ich (zumindest bei C) nicht da man ja Argumente meist nicht direkt zuweist sondern weiterverarbeitet, ansonsten könnte man ja gleich ein Makro schreiben um sich die Zeit für Funktions-Eintritt und Funktions-Austritt zu sparen. (wie gesagt auf C bezogen)

Code: Alles auswählen

uint32_variable = uint32_anderevariabel;
Das Beispiel ist natürlich so banal das es Sinn der Präfixe nicht ersichtlich wird, mal davon abgesehen das man so erkennen würde wenn man einen uint32 in einen uint16 kopiert. (btw. ich verwende u32_variable und nicht uint32_variable.)

Wie man mit einem Element umgeht ist ja abhängig von dessen Typ, z.B.

Code: Alles auswählen

s32_x == cl_current_Element.s32_x1
s32_x == pcl_current_Element->s32_x1
s32_x == acl_current_Element[i].s32_x1
s32_x == apcl_current_Element[i]->s32_x1

pcl_current_Element = gapcl_all_Elements[i];

if( gapcl_all_Elements[i]->pcl_linked_Element == pcl_Element )

usw.
nicht verwendete Präfixe in C führen teilweise zu sinnlosen Gebilden wie "&Element[0]" was das selbe ist wie "Element". Wenn es einzeln da steht ist das ganze noch leicht zu lesen, in einem längeren Ausdruck dauert es dann aber schon länger um denn Sinn zu verstehen wie in diesem realen Beispiel aus einem anderen Forum:

Code: Alles auswählen

(*((unsigned long*)&netmask[0])) = (*((unsigned long*)&cache.netmask[0]));
(mal davon abgesehen ob man das kopieren mittels cast aus einem array als sinnvoll erachtet.)

_______________________________________________________________________________

Das diese Präfixe auch in C++ bzw. mit Qt sinnvoll sind habe ich so nicht behauptet, aber statt mich hier missionieren lasst mich doch selber Entscheiden ob ich sie weiter verwenden will oder nicht.
Da ich bis jetzt noch nichts wirklich kompliziertes in C++ programmiert habe steht meine Entscheidung noch nicht fest ob ich diese Angewohnheit über den Haufen werfen will.
Antworten