Ein eigenes Koordinatensystem
-
Hallo
Die Eventmethode muß eben in die neue Komponente integriert werden, nicht ins Form.
// Konstruktor __fastcall TGraph::TGraph(...) { OnPaint = DoPaint; // Event wird durch Quellcode zugewiesen } // Eventmethode für TGraph void __fastcall TGraph::DoPaint(TObject *Sender) { Canvas->Pen->Color = clBlack; Canvas->MoveTo(ClientWidth/2, 0); Canvas->LineTo(ClientWidth/2, ClientHeight); Canvas->MoveTo(0, ClientHeight/2); Canvas->LineTo(ClientWidth, ClientHeight/2); }
bis bald
akari
-
freakC++, du stellst dich wirklich manchmal etwas "unbeholfen" an (habe ich auch schon bei deinen anderen Posts gesehen). Deine armen Lehrer, wenn du dich in der Schule auch so anstellst...
Du mußt beim Programmieren schon die Fähigkeit entwickeln, etwas abstrakter zu denken und nicht nur vorgefertigte Lösungen zu erwarten.
Wie Dieter Nuhr schon sagt: "erst Hirn einschalten" -)
Noch als Hinweis zu akari's Code: die Deklaration für die DoPaint-Methode mußt du dann natürlich auch noch in die entsprechende Klassendefinition (in die Header-Datei) packen.
-
Hallo akari und Th69,
vielen Dank für die Hilfe. Ich habe das Problem nun lösen können. Ihr seit top:@Th69: Ich verstehe, dass Du den Anschein von mir hast, dass ich manchmal keine Lust oder vielleicht auch nicht in der Lage bin, mir selbst zu helfen. Ich gebe zu, dass meine Posts für euch manchmal grenzwertig sind. Doch dann beantworte mir doch bitte die folgende Frage:
Ich bringe mir C++ aus reiner Leidenschaft durch Bücher bei und habe keinen, den ich fragen kann. Da mir häufig von euch gesagt worden ist - und ich euch da sehr vertraue - erstmal Grundlagen zu lernen, arbeite ich erstmal Grundlagenbücher durch. Da steht aber noch lange nichts vom Builder drin. Wie hast Du das gelernt und wie soll ich es lernen, damit ich solche Fragen verhindern kann. Ich persönlich lerne dadurch am besten, indem ich lese, ausprobiere und nachfrage. Vielleicht hast Du ja eine bessere Strategie. Ich kann ich dir jedoch versichern, dass ich mich in der Schule nicht so anstelle, da ich dort Lehrer habe, ich ich ansprechen kann. Neben meinen Büchern seit ihr meine Lehrer, die ich fragen kann!
Ich hoffe wirklich, dass ich mich nicht unbeliebt mache, doch wie soll ich sonst lernen, als immer wieder zu lesen, auszuprobieren und nachzufragen. Wenn ihr Anregunggen habt, dann her damit! Ich bin euch jedoch sehr dankbar.
Eine Frage noch: Wo kann ich denn nachlesen (denn ich bin durchaus willig, eigenständig zu arbeiten) oder wie kann ich erfahren, wie ich Eigenschaften in den Objektinspektorhinzufügen kann, z.B. xMax oder yMax meines Koordinatensystems. Dazu gibt die Suchfunktion und auch Google keine Informationen (ich habe jedoch keine gefunden). In meinen Büchern steht dazu nichts, deswegen gilt auch hier wieder: Woher soll ich das denn wissen? Nachfragen ist hoffentlich nicht verboten und ich hoffe, dass ich auch in Zukunft fragen darf, auch wenn es vielleicht für euch Pille-Palle ist.
Vielen Dank für die Hilfe, Th69!
lg, freakC++
-
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