3 verschiedene Frames gleichzeitig aktualisieren
-
Hallo liebe Leute,
habe angefangen mich mit dem MFC auseinander zu setzen.
Ich habe den Hauptframe in 4 Frames gesplittet.
Jetzt würde ich gerne 3 von diesen Frames gleichzeitig ansprechen (also z.b. einen Kreis auf jedem Malen).
Ist sowas überhaupt möglich? Habe gelesen dass man ewtl. mit SetActiveView den gewünschten View setzen muss, dann diesen ansprechen und zum nächsten weiter wechseln - oder habe ich da was falsch verstanden?
Danke vielmals,
Grüsse - Mischa
-
na ja eigentlich die Daten in den entsprechenden Views setzen und dann mit UpdateAllViews() die Views aktualisieren also zum neuzeichnen bringen.
-
cool, also gehts doch - danke werde es gleich ausprobieren
Aber um einzelne Views anzusprechen muss ich schon SetActiveView nutzen gel?
-
Ja Du hast was falsch verstanden.
SetActiveView benötigt man nur um den "aktiven" für die Eingabe bedeutsamen View zusetzen.
Jeder View zeichnet sich selbst. Das davon 4 in einem Frame liegen interessiert nicht einen der Views und auch nicht den Frame...
-
Habs versucht aber irgendwie klappts nicht ganz:
CMainFrame *pMainWnd = (CMainFrame *)AfxGetMainWnd(); pMainWnd->m_splitterWnd->SetActivePane(0,0); pMainWnd->RecalcLayout(); COLORREF qCircleColor = RGB(0,255,0); CPen qCirclePen(PS_SOLID, 7, qCircleColor); CPen* pqOrigPen = m_pDC->SelectObject(&qCirclePen); m_pDC->Ellipse(200,200,300,300); m_pDC->SelectObject(pqOrigPen); /////////////////// pMainWnd->m_splitterWnd->SetActivePane(0,1); pMainWnd->RecalcLayout(); qCircleColor = RGB(0,255,255); CPen qCirclePen2(PS_SOLID, 7, qCircleColor); pqOrigPen = m_pDC->SelectObject(&qCirclePen2); m_pDC->Ellipse(200,200,300,300); m_pDC->SelectObject(pqOrigPen);
Es wird nur ein Kreis gemalt und zwar auf "0,1"
Was mache ich falsch?
-
Schön wäre gewesen wenn du mal gezeigt hättest wo du zeichnest, sind die einzelnen Splitter mit eigenen View-Klassen verbunden dann musst du schon in der OnPaint() der einzelnen Klassen zeichen.
-
Hi,
ich arbeite mit SDI. in mainframe splitte ich so:void CMainFrame::onViewStaticSplitter() { CCreateContext context; memset( &context, 0, sizeof(context) ); CRect rect; GetClientRect(&rect); CView *curView = (CView *)m_splitterWnd->GetPane(0,0); context.m_pCurrentDoc = curView->GetDocument(); CSplitterWnd *newSplitter = new CSplitterWnd; newSplitter->CreateStatic( this, 2, 2 ); newSplitter->CreateView( 0, 0, RUNTIME_CLASS(CMFCKlasseView), CSize(rect.Width()/2, rect.Height()/2), &context ); newSplitter->CreateView( 0, 1, RUNTIME_CLASS(CMFCKlasseView), CSize(rect.Width()/2, rect.Height()/2), &context ); newSplitter->CreateView( 1, 0, RUNTIME_CLASS(CMFCKlasseView), CSize(rect.Width()/2, rect.Height()/2), &context ); newSplitter->CreateView( 1, 1, RUNTIME_CLASS(CMFCKlasseView), CSize(rect.Width()/2, rect.Height()/2), &context ); // Remove all but first pane from dynamic splitter if( m_splitterWnd->GetRowCount()>1 ) m_splitterWnd->DeleteRow(1); if( m_splitterWnd->GetColumnCount()>1 ) m_splitterWnd->DeleteColumn(1); context.m_pCurrentDoc->RemoveView(curView); m_splitterWnd->DestroyWindow(); delete m_splitterWnd; m_splitterWnd = newSplitter; m_splitterWnd->SetActivePane(0,1); OnUpdateFrameTitle(TRUE); RecalcLayout(); }
ist es was du wissen wolltest? (sorry, bin noch n noob
)
-
so wie ich das sehe gehört jedes Pain zur Klasse CMFCKlasseView also musst du doch auch in CMFCKlasseView::OnPaint deine zeichenaktion durchführen
qCircleColor = RGB(0,255,255); CPen qCirclePen2(PS_SOLID, 7, qCircleColor); pqOrigPen = m_pDC->SelectObject(&qCirclePen2); m_pDC->Ellipse(200,200,300,300); m_pDC->SelectObject(pqOrigPen);
dort hast du auch den einzigen DC mit dem du auch zeichnen kannst, ich kann zumindest nicht sehen wie du zu m_pDC gekommen bist.
-
srry, so siehts ihm view aus:
void CMFCKlasseView::OnDraw(CDC* pDC) { m_pDC = new CClientDC(this); CMFCKlasseDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; } void CMFCKlasseView::OnDrawCircle(){ CMainFrame *pMainWnd = (CMainFrame *)AfxGetMainWnd(); pMainWnd->m_splitterWnd->SetActivePane(0,0); pMainWnd->RecalcLayout(); COLORREF qCircleColor = RGB(0,255,0); CPen qCirclePen(PS_SOLID, 7, qCircleColor); CPen* pqOrigPen = m_pDC->SelectObject(&qCirclePen); m_pDC->Ellipse(200,200,300,300); m_pDC->SelectObject(pqOrigPen); /////////////////// pMainWnd->m_splitterWnd->SetActivePane(0,1); pMainWnd->RecalcLayout(); qCircleColor = RGB(0,255,255); CPen qCirclePen2(PS_SOLID, 7, qCircleColor); pqOrigPen = m_pDC->SelectObject(&qCirclePen2); m_pDC->Ellipse(200,200,300,300); m_pDC->SelectObject(pqOrigPen); return; }
also passiert das zeichnen im View.
-
warum erzeugst dui mit m_pDC = new CClientDC(this); in der OnDraw einen neuen DC wenn du den übergeben bekommst? Den DC den du übergeben bekommst ist auch der einzige DC mit dem du in dieser Funktion zeichnen kannst.
Und ich rate mal einfach und würde sagen das du OnDrawCircle() über einen button oder so aufrufst, da geht aber nicht, du kannst einzig umnd alleine in der OnDraw/OnPaint (je nachdem welche vorhanden ist) zeichnen, alles andere geht schief. Einfacher Versuch, lass mal deine kreise zeichnen und schiebe dann das Window über den rand deine Bildes wieder hinaus und dann wieder zurück, wirst du feststellen das deine Kreise weg sind.
-
oje du hast vollkommen recht - wohl eine von den Grundlagen die mir fehlt.
Aber wie soll das dann passieren?
ich will z.b. mit der maus ein objekt in einem frame bewegen und während er sich bewegt, sollen sich ähnliche objekte in anderen frame auch bewegen (bzw. neu zeichnen)das kann ich also nich in ondraw packen, denn soweit ich es verstanden habe wird ondraw nur am anfang aufgerufen
-
Warum soll OnDraw nur einmal am Anfang aufgerufen werden?
Gegenfrage wenn du deine Zeichenfunktion irgendwo in deinem Programm machst, wie soll das das Framwork wissen was zum neuzeichnen aufgerufen werden muss, wenn über deinem Window zum Beispiel ein anderes gelegen hat und jetzt wieder verschwunden ist?
Also bleibt doch nur die OnDraw zum zeichnen, und wie du das jetzt im einzelnen realisierst, musst du dir selbst überlegen, aber in deiner Funktion die hinter dem Button liegst kannst du nuir die zu zeichnenden Daten aufbereiten und dann das Framwork dazu bringen alles neu zu zeichnen und damit die anzeige aktualisieren.
Das ist der einzige gängige Weg, um das zeichnen Systemkonform zu machen. Bissel mal irgendow zeichnen und sich mal nen DC irgendwo her holen damit ist es niocht getan.
Ach so und denk dran viele Objekte wie zum beispiel der DC den du in der OnDraw übergeben bekommst sind eventuell Temporäre Objekte die nach Ende der Funktion wieder ungültig sind also nich gespeichert werden dürfen.
-
ja, habe jetzt etwas tiefer die doku durchgelesen - mach sinn was du schreibst. keine ahnung wieso ich das so falsch gemerkt habe.
habe es jetzt auch mit trace gesehen, dass das FW diese funktion ständig aufruft.
habe jetzt also alles in die ondraw gepackt.komischerweise werden jetzt in allen 4 frames die selben kreise gezeichnet, wobei ich mit setactivepane den aktuellen frame vor dem zeichnen setzte:
(m_pDC könnte man hier auch weg lassen :))void CMFCKlasseView::OnDraw(CDC* pDC) { //m_pDC = new CClientDC(this); m_pDC=pDC; CMFCKlasseDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; CMainFrame *pMainWnd = (CMainFrame *)AfxGetMainWnd(); pMainWnd->m_splitterWnd->SetActivePane(0,1); pMainWnd->OnUpdateFrameTitle(TRUE); pMainWnd->RecalcLayout(); COLORREF qCircleColor = RGB(0,255,0); CPen qCirclePen(PS_SOLID, 7, qCircleColor); CPen* pqOrigPen = m_pDC->SelectObject(&qCirclePen); m_pDC->Ellipse(200,200,300,300); /////////////////// pMainWnd->m_splitterWnd->SetActivePane(1,0); pMainWnd->OnUpdateFrameTitle(TRUE); pMainWnd->RecalcLayout(); qCircleColor = RGB(0,255,255); CPen qCirclePen2(PS_SOLID, 7, qCircleColor); pqOrigPen = m_pDC->SelectObject(&qCirclePen2); m_pDC->Ellipse(200,200,300,300); }
-
Erstens du hast wieder den DC in einen lokale Variable gespeichert, aber na ja zum test geht das schon.
Da alle deine Pains von der gleichen Klasse sind und du die Zeichenfunktion in der Draw hast, dann ist das doch Logisch das überall die gleichen kreise gezeichnet werden. Willst du immer unterschiedliche Sachen zeichnen die auf den gleichen Daten berugen, dann solltest du die Daten in deinem Dokument ablegen und für jedes Pain eine andere Klasse erstellen die dann die Daten aus dem Dokument unterschiedlich aufbereitet beim zeichnen.
Wobei ist es niocht einfacher wenn dir schon die grundlagen fehlen das ganze erstmal mit einen View zu versuchen und dann sich an Splitterwindows zu wagen?
SetAcxtivePain setzt doch auch nur das aktive Pain welchen den Eingabefocus hat.
Mit GetPain(0,0) bekommst du einen CWnd Zeiger den du meiner Meinung mit InvalidateRect() aktualisieren kannst, ob das so geht kann ich dir aber nicht mit sicherheit sagen, ist nur eine vermutung.
-
ich danke dir vielmals. Werde es jetzt weiter versuchen, aber ich weiß jetzt, (was ich befürchtet habe) dass eine View klasse hierbei nicht ausreichen würde.
Werde deinem Rat folgen und erstmal mit kleineren Sachen testen.
Vielen Vielen DANK!!!!
Grüsse - Mischa
-
na ja das geht schon mit einer View-Klasse, dann musst du nur irgendwie auswerten welches Pain es ist und dann in der Draw mit ner Switch Verzweigen, ob das dann übersichtlich wird steht auf einen anderen Blatt.
-
ja stimmt, ich kann es ja so machen:
CMFCKlasseView *pView1 = new CMFCKlasseView(101); CMFCKlasseView *pView2 = new CMFCKlasseView(110); ... newSplitter->CreateView( 0, 0, pView1->GetRuntimeClass() , CSize(rect.Width()/2, rect.Height()/2), &context ); newSplitter->CreateView( 0, 1, pView2->GetRuntimeClass(), CSize(rect.Width()/2, rect.Height()/2), &context );
und der Viewer wäre dann so:
class CMFCKlasseView : public CView { protected: // Nur aus Serialisierung erstellen DECLARE_DYNCREATE(CMFCKlasseView) public: CMFCKlasseView(int cols); int iCurrentPain; ... } CMFCKlasseView::CMFCKlasseView(int cols){ iCurrentPain = cols; } void CMFCKlasseView::OnDraw(CDC* pDC){ ... if(iCurrentPain == 101) ... else if(iCurrentPain == 110) ... }
habs schnell ausprobiert, aber blöderweise krieg ich dabei nen compiler fehler
MainFrm.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: __thiscall CMFCKlasseView::CMFCKlasseView(void)" (??0CMFCKlasseView@@QAE@XZ)" in Funktion ""protected: void __thiscall CMainFrame::onViewStaticSplitter(void)" (?onViewStaticSplitter@CMainFrame@@IAEXXZ)".
-
der Konstructor is Protected den kannst du nicht überschreiben, aber du kannst durch aus die Variable nach dem erstellen befüllen, das sollte den gleichen effekt haben.
CMFCKlasseView *pView1 = new CMFCKlasseView(); pView1->iCurrentPain = 101; CMFCKlasseView *pView2 = new CMFCKlasseView(); pView2->iCurrentPain = 110;
wobei du auch ganz einfach da mit 1,2,3 und 4 arbeiten kannst solange du weisstwelche Pain gemeint ist. Was auch noch geht und ich meist bei soplchen Sachen benutze ist enum da kannst du anstatt Nummern zu Verwenden direkt namen benutzen für Pain_links_oben, Pain_rechts_oben und so weiter was dann die Lesbarkeit erhöht.
-
genau das habe ich auch bereits probiert.
Ich initialisiere das Klassenobjekt und setze meine Variable auf einen bestimmten Wert.
CMFCKlasseView *pView1 = new CMFCKlasseView(); pView1->iCurrentPain=1; newSplitter->CreateView( 0, 0, pView1->GetRuntimeClass(), CSize(rect.Width()/2, rect.Height()/2), &context );
In der OnDraw habe ich dann:
CString s; s.Format(TEXT(" \n Pain: %d"),iCurrentPain); TRACE0(s); COLORREF qCircleColor; if(iCurrentPain==4){ qCircleColor = RGB(0,255,0); CPen qCirclePen(PS_SOLID, 7, qCircleColor); CPen* pqOrigPen = pDC->SelectObject(&qCirclePen); pDC->Ellipse(200,200,300,300); }
in der Ausgabe habe ich:
Pain: -842150451
Das scheint, aber die Registeradresse zu sein
-
Das kann so nicht gehen. CreateView erzeugt selbst das View Objekt. Das Objekt, dass Du hier erzeugst wird nicht verwendet!
Wo denn auch? Übergibst Du dieses pView Objekt an irgend jemanden?
Wer soll es denn benutzen.
Es ist einfach nur ein Speicherleck.Tipp: Entsprechende Daten sollen nicht im View stehen sondern im Dokument.
Wenn Du an den View ran willst, den CreateView erzeugst musst Du ihn Dir holen mit GetPane.