anfängerproblem getter-methode
-
haaaalloooo moderator,
gehört das ins MFC-Forum??
kann man das verschieben oder soll ich das ganze nochmals posten?
-
Dieser Thread wurde von Moderator/in HumeSikkins aus dem Forum C++ in das Forum MFC mit dem Visual C++ verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
bevor meine freundin mich rausschmeisst, weil ich von der kiste hier nicht mehr wegkomme...
Erpresser!
Klasse vs. Instanz sagtdir was? (evtl. mal die 10kg durchsuchen....)
Der Fehler liegt hier:
void CStatForm2::OnBnClickedButton1() { CString x; [b]CStatForm1 form1; x = form1.GetServer();[/b] SetDlgItemText(IDC_EDIT1, x); UpdateData(FALSE); }
Du erzeugst eine neue Instanz von CStatForm1. Die weiß natürlich nix von der anderen.
Lösung: Du mußt deiner Form2-Instanz einen Zeiger auf die Form1-Instanz mitgeben, am ehesten an der Stelle, wo du beide Forms erzeugst.
Dabei mußt du nur darauf achten, daß Form2 den Zeiger nur solange verwendet, wie er gültig ist, bzw. Form2 darüber informiert wird, wenn Form1 gelöscht wird.(Es gibt auch andere Mechanismen, die Änderungen von Daten in Form1 zu propagieren, die werden in komplexeren Szenarien empfehlenswert)
-
Hi,
danke für die ausführungen.der zeiger auf form1 hätte dann doch wohl das folgende aussehen:
CStatForm1 *pForm1; //in StatForm1.h pForm1 = NULL; // zB. im konstruktor von Form2 (wichtig, les ich immer wieder) pForm1 = new CStatForm1; // in StatForm1.cpp
ist das soweit o.k?
jetzt geht es doch noch ums WO.
wenn ich jetzt versuche, im konstructor von form2 einen zeiger auf form1 als dessen parameter mitzugeben, bekomme ich immer einen fehler: kein geeigneter standardkonstruktor verfügbar.ja, wo werden die forms erzeugt?
beim aufruf ihres konstruktors? denn müsste der obige ansatz ja irgendwie klappen oder in MainFrm.cpp wo das splitterfenster definiert wird.
wie man von dort was übergibt erschliesst sich mir aber nicht sofort.glaube eher, dass mir die nutzung eines geeigneten standardkonstruktors durch folgendes verwehrt bleibt: IMPLEMENT_DYNCREATE(CStatForm2, CFormView)
nehm ich das nämlich raus, kommt auch nicht der fehler mit dem standardkonstruktor, allerdings kommt es dann bei start des programms zu problemen mit der erstellung des dokuments.und mit diesem problem müsste ich im mfc-formum ja richtig aufgehoben sein?
diese zeigerübergabe per konstruktor hab ich gestern mit zwei forms auf einem nicht gesplitteten view eingeübt - klappt! auch vom form zum view, kein problem.
hier hab ich aber zwei von formview abgeleitete klassen. da versagt dieser mechanismus so wie ich ihn gestern gelernt habe.
Erpresser!
war nie meine absicht.
hab die gute gestern auch früh zum osterfeuer geschickt.
und hat sich gelohnt.
hab mir drei zugriffsmethoden erarbeitet, die alternativ zum obigen szenario auch funzen:- variablem per AfxGetApp über die anwendung selbst austauschen
- zugriff auf die splitts per GetPane()
- globale variablen
funktioniert alles drei
will nur sagen, ich möchte c++/mfc verstehen, ist halt son anspruch.
die kommunikation zwischen zwei views scheint mir recht wichtig zu sein, deshalb möchte ich es eigentlich auch so machen.
wäre froh, wenn du mich nicht gleich aufgibts
und entschuldigt mein gequatsche, wenn ich das hier geschnallt hab, sollte es auch weniger werden - ist halt was grundsätzlichesgruss
der ferngesteuerte
-
Ganz ehrlich... du solltest erstmal ein bißchen C++ aufholen, eh' du dich auf die MFC stürzt.
Deine Frage ist nicht ungewöhnlich (was es dir aber nicht leichter macht). Mit der MFC kommst du langfristig nur mit soliden Grundlagen sowohl in C++ als auch der Win32 API klar, und mußt außerdem noch die MFC-Architektur und den Wizard-generierten Code verstehen.- variablem per AfxGetApp über die anwendung selbst austauschen
- zugriff auf die splitts per GetPane()
- globale variablen
Aber Du scheinst dich ja durchgebissen zu haben
Ich geh mal davon aus du hast beide Forms als views in einem Splitter.
Diese werden in der MFC mit CreateView erzeugt - und das ist die perfekte Stelle, an der du einem den Zeiger auf den anderen mitgeben kannst:
(pseudo-code)
// das steht schon irgendwo: splitter->CreateView(0,0, RUNTIME_CLASS(CStatForm1), ...); splitter->CreateView(0,1, RUNTIME_CLASS(CStatForm2), ...); // jetzt kannst du den splitter nach den gerade erzeugten instanzen fragen, und die beiden miteinander verbinden CWnd * pane1wnd = splitter.GetPane(1); // (A) _ASSERTE(pane1wnd && pane1wnd->IsKindOf(RUNTIME_CLASS(CStatForm1)); // (B) CStatForm1 * form1 = (CStatForm1 * form1); // (C) CWnd * pane2wnd = splitter.GetPane(2); _ASSERTE(pane2wnd && pane1wnd->IsKindOf(RUNTIME_CLASS(CStatForm2)); CStatForm1 * form2 = (CStatForm2 * form1); form2->m_pForm1 = form1; // (D)
Die drei häßlichen Zeilen:
(A) holt einen Zeiger auf ein Splitter-Feld (scheinst du ja schon gefunden zu haben)
(B) Überprüft über einen MFC-internen mechanismus, ob das Teil tatsächlich ein CStatForm1 (bzw. davon abgeleitet) ist. Das würde man "heutzutage" über RTTI + dynamic_cast lösen, gab es damals aber noch nicht...
An dieser Stelle nur ein Assert, weil dein eigener Code das ja eigentlich sicherstellt.
(C) macht dann den Cast.In (D) greif ich einfach mal frech auf den Member zu, du kannst natürlich auch eine Setter- (bzw. Attach-) Methode verwenden.
Wenn es mehrere solche Fenster gibt, kannst du sie "direkt" verbinden, wie oben gezeigt.
Ansonsten ist ein Austausch über das Application - Objekt ist nicht unüblich. Wenn die beiden Forms singletons sind (es also nur einen Splitter mit den beiden Forms pro Anwendung gibt), kannst du diese auch als public member im App-Objekt eintragen.
Dazu noch einen kleinen Tip:
für eine MFC-EXE kannst du in <myapp>.h unter der CMyApp - Klasseklaration (oder wie auch immer diese heißt) deklarieren:extern CMyApp theApp;
Das theApp-Objekt wird in <myapp>.cpp sowieso instanziert, die kannst du so allen Übersetzungsunits zugänglich machen.
-
Hi und frohe Ostern,
vielen Dank für das beispiel.
das man das zeigersetzen im mainframe macht war schon eine erhellende sache.aber insgesamt klappt das so bei mir nicht.
entweder bekomme ich gemeldet: "irgendwas kann nicht in irgendwas* konvertiert werden" noch hab ich dann irgendwie Zugriff mit den erzeugten zeiger in meinen formviews.
Da kann ich mainframe-header in die forms einbinden oder vorwärtsdeklarieren so viel ich will.
Besonders das hierCStatForm1 * form1 = (CStatForm1 * form1); // (C)
will mir nicht in die birne.
wenn ich das recht verstehe kann man das assert weglassen?
das hier ist der besagte teil aus mainfrm.cpp
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) { if(!splitter.CreateStatic(this,1,2) || !splitter.CreateView(0,0, RUNTIME_CLASS(CStatForm1),CSize(165,0),pContext) || !splitter.CreateView(0,1, RUNTIME_CLASS(CStatForm2),CSize(0,0),pContext)) { return false; } { return true; } }
bitte sein doch so nett und schreib hier mal kurz den code rein, vielleicht auch nicht in pseudo-code. es ist wirklich nicht so, dass ich nicht wüsste was zeiger und was casts sind, aber hier hab ich wohl das berühmte brett vom kopf.
der zugriff von form2 auf form1 reicht auch völlig aus9999
gruss
der ferngesteuerte
-
CStatForm1 * form1 = (CStatForm1 * form1); // (C)
böser Typo
soll heißen
CWnd * pane1wnd = splitter.GetPane(1); // (A) _ASSERTE(pane1wnd && pane1wnd->IsKindOf(RUNTIME_CLASS(CStatForm1)); // (B) CStatForm1 * form1 = (CStatForm1 *) pane1wnd; // (C)
Nochmal in Kurzform: (A) holt sich dasform als CWnd * (basisklasse), (B) checkt, ob es sich dabei tatsächlich um ein StatForm1 handelt, (C) macht den cast.
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) { if(!splitter.CreateStatic(this,1,2) || !splitter.CreateView(0,0,RUNTIME_CLASS(CStatForm1),CSize(165,0),pContext) || !splitter.CreateView(0,1, RUNTIME_CLASS(CStatForm2),CSize(0,0),pContext)) return false; CWnd * w1 = splitter.GetPane(0,0); _ASSERTE(w1 && w1->IsKindOf(RUNTIME_CLASS(CStatForm1)); // (B) CStatForm1 * form1 = (CStatForm1 *) w1; // (C) CWnd * w2 = splitter.GetPane(0,1); _ASSERTE(w2 && w2->IsKindOf(RUNTIME_CLASS(CStatForm2)); // (B) CStatForm2 * form2 = (CStatForm2 *) w2; // (C) form2->m_pForm1 = form1; // (D) }
Ist natürlich nciht compiler-getestet, aber sollte gehen
-
Hi,
vielen dank.
klappt soweit mit dem kompilieren.
aber irgendwie kann mir nicht vorstellen, wie ich diese zeiger dann in den formviews nutzen kann (war klar, dass das jetzt kommt , oder?)
hab jetzt mehrere varianten des einbindens von mainframe in die views versucht.
von neudefinition bis unbekannt waren alle fehlermeldungen dabei.dann probiert, einen zeiger auf mainframe zu setzen, um an die zeiger zu kommen, die ich zuvor mal in der mainfrm.h dekl. habe.
CMainFrame *pMainFrame = (CMainFrame*)GetParentFrame();
leider auch erfolglos.aber wenn ich das so mache, kann ich ja auch die jetzt laufende variante:
CMainFrame *pMainFrame = (CMainFrame*)GetParentFrame(); CMyTreeView *pTree = (CMyTreeView*)pMainFrame->splitter.GetPane(0,0);
benutzen.
dein zugriff (D) funktioniert doch höchstens in mainframe?
wobei ich form2->m_pForm1 = form1, also die zuweisung eines zeigers an einen zeiger, der auf seinen member zugreift, gar nicht checke.eigentlich wollte ich ja, "nur" den zeiger auf das andere form haben, um auf seine memeber zugreifen zu können.
wie nutze ich die zeiger in den forms???
(bitte um den finalen rettungsschuss, damit ich das hier endlich los bin
)
aber erstmal 99999
gruss
der ferngesteuerte
-
m_pForm1 sollte ein member (CStatForm1
von CStatForm2 sein. Den initialisierst du im Konstruktor schön brav auf NULL, und im OnCreateClient gibst du dort dann den Zeiger auf den anderen View zurück.
Über m_pForm1 können alle Memberfunktionen von CStatForm2 auf das erste form zugreifen.
Das war doch, was du wolltest, oder?
-
hier geht die sonne auf!
wie kann ich dir danken!aber fieseste pferdefüsse noch gefunden:
1)
in StatForm2.cpp muss die (statform1.h) vor die statform2.h
(aber irgendwie klar, wenn mans genauer anschaut - erst tanken dann losfahren)
- die deklaration von m_pForm1 in StatForm2.h darf man nicht einfach ans ende des public-blocks setze, sonst fehler: kein zugriff aud protected-element das in statform2 dekl. wurde (???), sondern direkt hinter den konstruktor statform2() - da war ich heute morgen schon und habs nicht geschnallt.
Mal ehrlich, das macht einen newbee doch irre!?!
aber die geschichte "zeiger mitgeben" is jetzt klar.aber sei's drum. dafür muss man in c++ wohl nie sagen: "geht nicht".
also super 1000 dank und noch einen schönen feiertag.
gruss
der ferngesteuerte
-
Mal ehrlich, das macht einen newbee doch irre!?!
100%
Mein Problem ist ein ganz anderes dabei: Die Frage taucht in ähnlicher Form oft auf, und ist "irre simpel" (zumindest für jemanden der wie ich seit ca. 8 Jahren intensiv mit C++ "dabei" ist). Man sieht einfach die Hürden nicht mehr.
Darf ich dich also fragen: wieviel C++ hast du vorher gemacht? Kurse, Projekte usw.
-
Hi,
c++ hab ich im studium ein pflichtsemester machen müssen.
damals schlechter abgeschnitten und wieder alles vergessen.
bis dato nix mehr gemacht.
zur zt arbeitet ich als datenbank und netzwerkadmin und programmiere in php, gtk-php, auto-it und sehr viel sql. also eher scripting.
will jetzt in windows einsteigen, da lag c++/mfc nahe.
was mich jetzt schon wieder etwas annervt, ist die frage:mfc, rtti, wfc, atl etc pp - da muss ich mich erstmal schlau machen.
wo soll das hinführengruss
der ferngesteuerte
-
Du hast das .NET-Framework vergessen
Aber ich will mal behaupten wenn man es schafft durch die MFC und WinAPI durchzublicken kann einen "fast" nix mehr abschrecken
-
Ich denke nicht mal, das es so verkehrt ist, die "Grundlagen" zu lernen.
Man lernt nur halt drei Sachen auf einmal:
C++ (Syntax+Konzepte)
WinAPI (Windows-Programmierung allgemein)
MFC (WinAPI-Wrapper / "Halb-Plattform")Und das ist ohne Frage schwierig.
-
Ich hab' vor einer Weile mal auf eine Frage "How to become a (C++/MFC) Pro" eine sozusagen Roadmap geschrieben, welche Reihenfolge ich empfehlen würde:
http://www.codeproject.com/script/profile/whos_who.asp?msg=900509&id=175#xx900509xx
-
wahrscheinlich ist deine road-map ein guter weg zum erfolg.
allerdings ist es doch auch möglich, ein konkretes projekt vor augen zu haben und das ganze erstmal in einem einfachem dialog zu machen.
da sind es doch immer wieder dieselben dinge: daten einlesen (per tastatur, file oder datenbank) dann verarbeiten , dann in geeigneter form ausgeben.
der nächste schritt sind dann zwei forms und deren komunikation, dann zwei views usw. die probleme, die dann auftauchen, versucht man zu lösen.
für viele ist das lösen von aufgaben anhand von beispielen wesentlich einfacher als über syntaxbeschreibungen. der mensch denkt in bildern! die wenigsten anfänger werden wissenschaftlich-strukturiert vorgehen.
wenn man dann mal eine map braucht, schaut man sich die stl dinger an und baut das ein.
ich denke da auch an die motivatorischen ereignissen, wenn also das erste windows-fenster das erste tree-control anzeigt z.b.
ich glaub so machen es viele anfänger, und auch viele bücher gehen diesen weg.
die c++-techniken in konkreten gui-kleinprojekten anwenden und dann auf die gabe der abstraktionsfähigkeit hoffen, damit das gelernt anderweitig anwendbar wird.
der trend geht doch auch zu diesen rap-tools, die die ganze c++ zeigerei vor den user verbergen- deswegen ist wohl auch java so erfolgreich. und selbst c++ hat mit der einführung von referenzen dem wohl ein wenig rechnung tragen wollen.
denke, die nutzung und kommunikation zwischen der wesentlichen datenstruktur in c++, der klassen, ist mit das wichtigste, alles weitere kommt dann schon. dazu braucht man natürlich c++ und sein zeigerkonzept
die wahrheit hat viele gesichter ...gruss
der ferngesteuerte
-
ein guter weg zum erfolg
Auf all Fälle, ist ja eher eine Anregung. Ich habe selbst "Am lebenden Objekt" gelernt, und wollte man sich an die Liste halten, bräuchte man auf jeden Fall kleine Projekte, die die einzelnen Schritte "mit Leben" füllen.
Die Liste spiegelt meine Erfahrungen (mit mir selbst und anderen) wieder was man alles braucht. Die Reihenfolge ist eher akademisch.
Trotz aller Individualität halte ich ein solides C++ - Fundament langfristig für unabdingbar. Dazu gehört viel mehr als nur die Sprache, im Prinzip ein ganzes "Gesetzeswerk", was gut ist und was nicht.
Um dein Beispiel aufzugreifen - natürlich kann man sich bei Bedarf mit der Doku hinsetzen und sich std::map anschauen - so wird sicherlich jeder seine ersten Erfahrungen mit der STL sammeln. Und das genügt für Hobby, Uni, und abgeschlossene Ein-Mann-Projekte durchaus.
Solltest Du dich jemals bei mir bewerben (
), erwarte ich schon, daß du über die STL etwas mehr als nur "da gibt es map und set und vector" weißt (bzw. bereit und fähig bist, dir das "nebenbei" anzueignen). Und das bekommt mit mit ein, zwei gezielten fragen ganz fix raus.
Insofern kann man meine Liste als Anregung sehen, das angesammelte Wissen Stück für Stück zu systematisieren, wenn man sich langfristig in der C++ - Desktopentwicklung spezialisieren will