Ein eigenes Koordinatensystem
-
Hallo
Der Hauptproblem dürfte sein, das der Builder mit seiner VCL eigentlich nicht für Anfänger geeignet ist, wie jedes andere GUI-Framework auch. Wenn wir von Grundlagen reden, dann meinen wir die Grundelemente der Sprache (für C++ z.B. in diesem Tutorial erklärt), die Beschränkung auf Konsole ohne GUI (geht auch im Builder), das sprachunabhängige (!) Verständnis für Paradigmen wie Speicherverwaltung, Datenstrukturen, Ablaufsteuerung, OOP, Fehlervermeidung und -beseitigung...
Solange du als Anfänger dich in erster Linie mit GUI-Elementen beschäftigt, ohne zu verstehen was dahinter steckt, wirst du nicht weiterkommen. Solche Hinweise sollen kein persönlicher Angriff sein, sondern ein guter Rat von uns, der aus eigener Einsicht kommt.
Als Beispiel nur mal THs Anmerkung zu meinem letzten Code : Für mich ist es selbstverständlich, das zu der von mir gezeigten Methodenimplementation auch noch eine Methodendeklaration an die richtige Stelle gehört. Aber hättest du es auch ohne extra Hinweis gewußt?
bis bald
akari
-
Hallo akari,
ja, das hätte ich auch selber gewusst. Entscheidend war der Trick, dass du dem Ereignis OnPaint einfach DoPaint zugewiesen hast. Das lieg an deiner Erfahrung, die ich noch nicht gemacht habe. Dass ich für eine Methode eine Deklaration machen muss, ist mir klar. So ein blutiger Anfänger bin ich dann auch nicht.Natürlich weiß ich, dass das kein persönlicher Angriff sein soll. Deswegen gebe ich mich ja auch nicht irgendwie aggressiv, sondern möchte kooperativ sein und wirklich auf eure Anregungen eingehen.
Meine Hauptbeschäftigung liegt ja auch im "C++" Forum, da ich Grundlagen weiter vertiefen möchte. Ich finde jedoch auch den Builder mit der VCL spannend. In der Schule lerne ich Delphi und wir arbeiten auch mit dem Builder (halt mit Delphi), doch da geht es nur darum: "Erstelle einen Button, der eine Ausgabe mach". Solange das in Delphi ist, soll es mir recht sein. Ich will aber mehr wissen und mehr lernen. Daher enstehen manchmal solche Fragen.
Naja, wenn ich nun eine Eigenschaft im Objektinspektor hinzufügen möchte, muss ich sicherlich was an meiner KLassendeklaration ändern. Wenn ich ein Ereigniss hinzufügen möchte, arbeite ich mit __property, doch wie funktioniert das hier? Ich habe mal mit __property gearbeitet, doch das gibt einen Fehler:
__published: __property xMax; //hier wird ein Typname erwartet, doch in meinem ersten Buch stand, dass ich das einfach so hier rein schreiben muss /*Ich möchte im Objektinspektor beispielsweise eine Eigenschaft xMax für den maximalen X Wert haben. Das Problem liegt nur am mangelnen Verständis des Builders und nicht an C++*/
Vielen Dank für eure Tipps und Anregungen.
lg, freakC++
-
Noch als Hinweis zur Komponentenerzeugung: zumindestens beim BCB 5 und 6 gibt es eine eigene (wirklich ausführliche) Hilfe-Datei dafür: bcb5cw.hlp (Komponentenentwicklung).
-
Hallo,
ich verwende die Hilfedatei des Builder 6, doch da ich auf Windows 7 arbeite, funktioniert die nicht. Ich muss also immer auf XP wechseln, um diese zu verwenden. Da guck ich aber bezüglich den Eigenschaften gleich mal nach :D.Siehe Hinzufügung im vorherigen Post.
Danke.
lg, freakC++
-
zu hlp-Dateien unter Windows Vista bzw. 7 benutzen: http://support.microsoft.com/kb/917607
(obwohl ich selber noch unter Win2000 hier arbeite -)
-
Ah, super! Vielen dank für den Tipp. Jetzt kann ich sogar die Hilfefunktion unter 7 nutzen.
Naja, ich habe mir mal die Hilfefunktion angeschaut und festgestellt, dass ich mit __property richtig liege:
__published: __property int xMax;
Das ergibt einen Fehler, da xMax wohl initialisiert werden muss. Doch sowas funktioniert nicht:
__published: __property int xMax=10;
Das ergäbe für mich auch keinen Sinn. Irgendwie verlangt der Builder da eine geschweifte Klammer. Ich möchte, dass der maximale X Wert über den Objektinspektor eingegeben wird, in einer Variablen gespeichert wird und das Koordinaten angeglichen wird. Könnt ihr mir da wieder helfen? Wie deklariere ich solch eine Eigenschaft?
Vielen Dank
lg, freakC++
-
Hallo
Wie property verwendet wird, steht ausführlich in dem Tutorial, das ich in meinem ersten Post in diesem Thread verlinkt habe. Unterseite "Methoden, Eigenschaften und Ereignisse", Abschnitt Eigenschaften.
bis bald
akari
-
Da durchforstet man die ganze Hilfe und es steht im zweiten Post. *schäm*
Danke für den Hinweis! Ich habs hinbekommen.
lg, freakC++
-
Wenn ich beispielsweise möchte, dass xMax als default Wert die Breite meiner Zeichenfläche hat, so habe ich xMax einfach im Konstruktor den entsprechenden Wert zugewiesen:
TGraph.h
class PACKAGE TGraph : public TPaintBox { private: int XMAX; protected: public: __fastcall TGraph(TComponent* Owner); __fastcall void ShowXMAX () {ShowMessage(XMAX);}; __published: __property int xMax = {read = XMAX, write = XMAX}; };
TGraph.cpp
__fastcall TGraph::TGraph(TComponent* Owner) : TPaintBox(Owner) { XMAX = Width; }
Das ist zwar von der Syntax korrekt, doch das Ergebnis ist dennoch falsch. Bei mir erscheint im Objektinspektor 105, obwohl das Objet Graph1 viel länger ist.
Es liegt wohl daran, dass diese Anweisung im Konstruktor steht. Doch wie könnte man das Problem denn am besten lösen, da schon Anfgans xMax dieser Wert zugewiesen werden soll
Vielen Dank
lg, freakC++edit: Ich habe das Problem gelöst, indem ich einfach die Zuweisung XMAX=Width in akaris DoPaint Methode geschrieben habe. Doch ist das die einzige Möglichkeit, das Problem zu lösen. Sollte man solche Zuweisungen generell nicht in den Konstruktor schreiben?
-
Wenn du auf Größenänderungen deines Controls reagieren willst bzw. dein XMAX
festlegen willst dann kanst du das OnResize Event reagieren.freakC++ schrieb:
edit: Ich habe das Problem gelöst, indem ich einfach die Zuweisung XMAX=Width in akaris DoPaint Methode geschrieben habe. Doch ist das die einzige Möglichkeit, das Problem zu lösen. Sollte man solche Zuweisungen generell nicht in den Konstruktor schreiben?
Wenn du das Property XMAX in DoPaint immer mit der Breite der Komponente
setzt, wiso hast du Überhaupt das XMAX Property ? dann kannst du auch gleich
das Width verwenden.
Wenn dein Koordinatensystem von außen Steuerbar sein soll, sollte der Benutzer
das XMAX und die anderen min/max Einstellungen selbst Eingeben können und du
nur auf Fehleingaben hinweisen und nicht selbst die Property im Control setzten.
-
Hallo VergissEs,
dein letztes Argument ist natürlich klar. Ich habe XMAX auch nur Width zugewiesen, um zu überprüfen, ob alles funktioniert. Zuerst hat es eben nicht funktioniert und somit habe ich eine mögliche spätere Fehlerquelle schon behoben. Width wird natürlich nur in irgendeinem Verhältnis zu XMAX stehen. Ich möchte halt, dass sich das Koordinatenkreuz automatisch anpasst. WIe ich das mache steht noch nicht fest....da muss ich mir noch ein paar Gedanken machen. Außerdem sollen XMAX etc. im Objektinspektor erscheinen, was sonst nicht der Fall wäre. Das OnResize Event kannte ich noch gar nicht. Das hört sich sehr gut an. ICh werde es mir bald anschauen.Ganz am Anfang dieses Threads hast Du mir gesagt, wie ich den Nullpunkt verschiebe. Dazu habe ich bezüglich noch eine Frage:
HDC hDC = Canvas->Handle; MoveWindowOrg(hDC, 300, 200);
Somit kann ich den Ursprung meines Koordinatensystems nach (300|200) verlegen. Doch was ich der Typ HDC? Das funktioniert auch:
SetViewportOrgEx(Canvas->Handle, Width/2, Height/2, NULL);
SPielt es eine Rlle, wann ich welchen Befehl erteile, denn beide machen ja das gleiche.
Vielen Dank
lg, freakC++
-
HDC ist ein Handle Device Context also das Handle der Zeichenfläche auf der du zeichnest (WinAPI).
MoveWindowOrg und SetViewportOrgEx machen erstmals das selbe aber du kannst noch mehr bei den Koordinaten manipulieren siehe:
http://msdn.microsoft.com/en-us/library/dd183475(VS.85).aspx
-
Ahh...super! Wieder was gelernt. Dann frage ich mich jedoch, warum es nicht möglich, die Nullpunktverschiebung direkt in akaris "DoPaint" Methode zu schreiben:
void __fastcall TGraph::DoPaint(TObject *Sender) { SetViewportOrgEx(Canvas->Handle, Width/2, Height/2, NULL); SetMapMode(Canvas->Handle, MM_LOENGLISH); }
Als Test habe ich mal das geschrieben, doch der Nullpunkt bleibt oben links:
Graph1->Canvas->LineTo(100,100);
Warum kann ich die Anweisung nicht in die DoPaint Methode schreiben. Liegt es daran, dass ich diese dem OnPaint Event zuweise?
Soweit ich das weiß gibt es in der Klasse TPaintBox kein OnResize Event !? Deswegen kann ich VergissEs' Tipp nicht umsetzen.
Wo sollte ich denn am besten die Nullpunktverschiebung reinschreiben?
Vielen Dank
lg, freakC++
-
Ich habe nochmal ein bisschen ausprobiert. Wenn ich folgendes in die DoPaint Methode schreibe:
SetViewportOrgEx(TGraph::Canvas->Handle, Width/2, Height/2, NULL); SetMapMode(TGraph::Canvas->Handle, MM_LOENGLISH); Canvas->LineTo(200,200);
dann wird die Linie nicht vom gewünschten Nullpunkt gezeichnet. Wenn jedoch das schreibe:
SetViewportOrgEx(TGraph::Canvas->Handle, Width/2, Height/2, NULL); SetMapMode(TGraph::Canvas->Handle, MM_LOENGLISH); TGraph::Canvas->LineTo(200,200);
dann wird die Linie "korrekt" gezeichnet. Wenn ich dann jedoch einen Button erstelle mit dem Code
Graph1->Canvas->LineTo(100,100);
dann wird nicht vom gewünschten Nullpunkt gezeichnet. Verliert die Verschiebung des Ursprungs da ihre Wirkung oder was muss ich machen, damit dieser immer verschoben bleibt?
Vielen Dank für eure Hilfe
lg, freakC++PS.: SOll ich eigentlich für solche Fragen einen neuen Thread aufmachen, da das ja mit dem Anfangsthema nichts mehr zu tun hat?
-
Hallo
Ich habe keine Erfahrung mit dem SetViewport..., aber in deinem Code ist das "Graph1->" schonmal falsch. Nocheinmal : Für deine neue Komponente müßen alle Zeichenoperationen in der TGraph::DoPaint-Methode erfolgen. Dazu steht dir die Eigenschaft Canvas zur Verfügung. Du brauchst auch nicht "TGraph::" zu benutzen. "Graph1->" ist aber gar ein Fehler. Denn in der DoPaint-Methode gibt es keine konkrete Graph1-Instanz, du schreibst doch schließlich eine allgemeine, mehrfach verwendbare Komponente.
Noch passt das in diesen Thread...
bis bald
akari
-
Nein, das "Graph1->" steht in einer ButtonClick Methode. Das war ein Text, um zu überprüfen, ob nun der Nullpunkt endlich korrekt verschoben worden ist. Leider hat dieser Test halt ergeben, dass dies nicht der Fall ist. Dennoch wird die Linie, die in der DoPaint Methode gezeichnet wird, korrekt gezeichnet (also ab dem gewünschten NullPunkt in der Mitte meiner KOmponente).
Ich verstehe also nicht, warum ich auf mein Graph Objekt nicht ab dem in der DoPaint-Methode festgelegten Nullpunkt zeichnen kann.
Wer weiß da weiter?
Vielen Dank, akari
lg, freakC++
-
Hallo
Nocheinmal : Für deine neue Komponente müßen alle Zeichenoperationen in der TGraph::DoPaint-Methode erfolgen
Egal wo du diese OnButton-Methode definiert hast, dort ist nunmal der Zugriff auf TGraph::Canvas nicht korrekt. Wenn dann solltest du von dem Button aus eine von deinen für TGraph neu implementierten Eigenschaften setzen. Mit TGraph::Refresh() löst du dann das Paint-Event aus, in dem dann die Eigenschaften ausgewertet werden und die Zeichenoperationen ausgeführt werden.
bis bald
akari
-
Aber ich habe den Button auf meinem Forumar und habe ich eine Instanz von TGraph erstellt, auf die zeichnen möchte. Diese Zeichenanweisung steht in einem Button.
Naja, egal. Auf jeden Fall stimmt dieser Code nicht und ich weiß einfach nicht warum:
void __fastcall TGraph::DoPaint(TObject *Sender) { SetViewportOrgEx(Canvas->Handle, Width/2, Height/2, NULL); SetMapMode(Canvas->Handle, MM_LOENGLISH); Canvas->MoveTo(0,Height/2); Canvas->LineTo(0,-Height/2); }
NUn sollte wenigstens die Y Achse gezeichnet werden, doch diese ist einfach nicht in der Mitte und sie geht noch nichtmal durch die ganze Graph KOmponente.
Könnt ihr mir da bitte weiterhelfen?Vielen DAnk :xmas1:
lg, freakC++
-
Du musst nach dem zeichnen den Urzustand wieder herstellen.
//Hintergrund mit Gradient überzeichnen GradientFillCanvas(Canvas, clWhite, clBlue, ClientRect, gdVertical); SetViewportOrgEx(Canvas->Handle, Width/2, Height/2, NULL); Canvas->Pen->Style = psSolid; Canvas->Pen->Color = clBlack; //Horizontale Linie Canvas->MoveTo(0, Height/2); Canvas->LineTo(0, -Height/2); //Vertikale Line Canvas->MoveTo(Width/2, 0); Canvas->LineTo(-Width/2, 0); //Urzustand wieder herstellen SetViewportOrgEx(Canvas->Handle, 0, 0, NULL);
-
Hey VergissEs,
vielen Dank für deine Hilfe. Zwei Anliegen habe ich:1.) Was ist GradientFillCanvas und der Parameter gdVertica. Die Hilfefunktion und Google kennen beides nicht (google verweist nur auf dich :D). Was muss ich machen, um diese Funktion zu nutzen.
2.) KÖnntest Du mir nochmal genau sagen, warum ich den Urzustand wiederherstellen muss. Was genau ist der Urzustand? Warum kann ich in der Do-Paint Methode nicht einfach den Nullpunkt ändern und dann eine Linie zeichnen. Diese Linie würde nicht vom Zentrum meiner KOmponente gehen.
Bitte helft mir, auch wenn das schon ein riesen Thread ist. Ich gebe zu, dass Th69 Aussage hier stimmt: Ich bin nämlich momentan ein bisschen unbeholfen und weiß einfach nicht, wie das Problem lösen kann (also dass ich dauerhaft den Ursprung verschieben kann).
Ich danke euch sehr!
lg, freakC++