2.te ViewKlasse in SDI Anwendung



  • Hallo alle zusammen,

    ich habe da gerade ein kleines Verständnisproblem.
    Um mein Fenster zu splitten benötige ich innerhalb meiner SDI Anwendung eine 2.te Viewklasse, welche mit einer neuen von CFormView abgeleiteten Resource.

    Habe jetzt soweit alles fertig. Es scheint auch zu laufen. Habe auf der Resource ein PictureCtrl gesetzt. Dieses wird mir auch angezeigt.
    Nun habe ich 2 Probleme. Wenn ich die 2.te View mit CSplitterWnd.CreateView anlege, dann wird die OnInitialUpdate nicht angesprochen und wenn ich aus der Resource mit GetDlgItem das PictureCtrl ansprechen möchte ist die m_hWnd aus CWnd Null und somit bekomme ich ein Assertion bei der Prüfung auf IsWindow aus der GetDlgItem.

    Hier mal meine Klasse zu der Resource.

    //Header Datei
    #pragma once
    
    #include "resource.h"
    #include "DisplayView.h"
    
    class CHeaderView : public CFormView
    {
    public:
    	CHeaderView(void);
    	~CHeaderView(void);
    	enum{ IDD = IDD_TOPVIEW };
    	void DoPaint(CDC& dc);
    	afx_msg void OnSize(UINT nType, int cx, int cy);
    	CDisplayView m_wndDispView;
    
    protected:
    	DECLARE_DYNCREATE(CHeaderView)
    	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
    	DECLARE_MESSAGE_MAP()
    	afx_msg void OnPaint();
    	virtual void DoDataExchange(CDataExchange* pDX);
    	virtual void OnInitialUpdate();
    };
    
    //Cpp - Datei
    #include "StdAfx.h"
    #include "HeaderView.h"
    
    IMPLEMENT_DYNCREATE(CHeaderView, CFormView)
    
    CHeaderView::CHeaderView(void) : CFormView(CHeaderView::IDD)
    {
    	OnInitialUpdate();
    }
    
    CHeaderView::~CHeaderView(void)
    {
    }
    
    BEGIN_MESSAGE_MAP(CHeaderView, CFormView)
    	ON_WM_PAINT()
    	ON_WM_SIZE()
    END_MESSAGE_MAP()
    
    void CHeaderView::OnInitialUpdate()
    {
    	CRect cr;
    	CWnd* pWnd = GetDlgItem(IDC_HEADER_PLACEHOLDER); //Hier die Assertion
    	pWnd->GetWindowRect(&cr);
    	ScreenToClient(&cr);
    	pWnd->DestroyWindow();
    	m_wndDispView.Create(AfxRegisterWndClass(0, LoadCursor(NULL, IDC_ARROW), NULL, NULL), "header",
    		WS_CHILD|WS_VISIBLE, cr, this, IDC_DISPLAY);
    	m_wndDispView.DisableHeader();
    }
    
    void CHeaderView::OnPaint()
    {
    	Default();
    	CClientDC dc(this);
    	//DoPaint(dc);
    }
    
    BOOL CHeaderView::PreCreateWindow(CREATESTRUCT& cs)
    {
    	if(!__super::PreCreateWindow(cs))
    		return FALSE;
    
    	return TRUE;
    }
    
    void CHeaderView::OnSize(UINT nType, int cx, int cy)
    {
    	__super::OnSize(nType, cx, cy);
    	if(m_wndDispView.m_hWnd == NULL)
    		return;
    	DWORD dwErr ;
    	HDWP hdwp = BeginDeferWindowPos(1);
    	if(hdwp == NULL)
    		dwErr = GetLastError();
    	CRect rcHeader, rcClient;
    	GetClientRect(&rcClient);
    	m_wndDispView.GetWindowRect(&rcHeader);
    	ScreenToClient(&rcHeader);
    	rcHeader.bottom = rcClient.bottom - rcHeader.left;
    	DeferWindowPos(hdwp, m_wndDispView.m_hWnd, NULL, rcHeader.left, rcHeader.top,
    		rcHeader.Width(), rcHeader.Height(), SWP_NOZORDER);
    	EndDeferWindowPos(hdwp);
    
    }
    
    void CHeaderView::DoDataExchange(CDataExchange *pDX)
    {
    	CFormView::DoDataExchange(pDX);
    }
    
    //Und in Mainframe so erstellt
    void CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext *pContext)
    {
    	CRect cr;
    	GetWindowRect(&cr);
    
    	if(!m_wndSplitter.CreateStatic(this, 2, 1))
    	{
    		TRACE("Fehler bei CreateStatic");
    		return FALSE;
    	}
    	if(!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CHeaderView), CSize(cr.Width(), 100), pContext))
    	{
    		TRACE("Fehler bei Splitter - CreateView");
    		return FALSE;
    	}
             return TRUE;
    }
    

    Was könnte ich denn falsch machen?

    Gruß


  • Mod

    Wo legst Du den ertsen View an?
    Ich sehe grundsätzlich nur einen...



  • Hi Martin,
    der erste View ist der der vom MFC Assistenten erstellt wurde.
    Den legeg ich ebenfalls mit Create View an.
    Insgesamt sieht die OnClientCreate so aus

    BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext *pContext)
    {
    	CRect cr;
    	GetWindowRect(&cr);
    
    	if(!m_wndSplitter.CreateStatic(this, 2, 1))
    	{
    		TRACE("Fehler bei CreateStatic");
    		return FALSE;
    	}
    	if(!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CHeaderView), CSize(cr.Width(), 100), pContext))
    	{
    		TRACE("Fehler bei Splitter - CreateView");
    		return FALSE;
    	}
    	if(!m_wndSplitter.CreateView(1, 0, RUNTIME_CLASS(CTestSplitWindowsView), CSize(cr.Width(), cr.Height() - 100), pContext))
    	{
    		TRACE("Fehler bei Splitter - CreateView");
    		return FALSE;
    	}
    	return TRUE;
    }
    




  • Da ich insgesamt nicht von CFrameWnd ableite, sondern von einer internen von CFrameWnd abgeleiteten Klasse kann ich dies leider nicht von CSDIFrameWnd ableiten. Daher ist das Beispiel von Codeguru nicht unbedingt was für mich bzw. ich müsste die Methode ActivateView für mich schreiben.
    Aber dennoch danke für den Aritkel.


  • Mod

    Wenn Du alles normal über das CDocTemplate erzeugst muss auch OnInitialUpdate aufgerufen werden. Den OnInitialUpdate wird durch CSingleDocTemplate::OpenDocumentFile für alle erzeugten Views aufgerufen.

    Was machst Du in InitInstance?



  • Ich arbeite nicht mit dem DocTemplate zumindest nicht extern, was in unseren internen Klassen passiert weiß ich leider selbst nicht. Darüber bekommt man keine Infos, sondern muss sich selsbt durchwurschteln und da bin ich noch nicht komplett zu gekommen.

    Meine InitInstance sieht folgendermaßen aus:

    BOOL CTestSplitWindowsApp::InitInstance()
    {
    	// InitCommonControlsEx() is required on Windows XP if an application
    	// manifest specifies use of ComCtl32.dll version 6 or later to enable
    	// visual styles.  Otherwise, any window creation will fail.
    
    	InitCommonControls();
    
    	CWinApp::InitInstance();
    
    	// Initialize OLE libraries
    	if (!AfxOleInit())
    	{
    		AfxMessageBox(IDP_OLE_INIT_FAILED);
    		return FALSE;
    	}
    	AfxEnableControlContainer();
    
    	CMainFrame* pFrame = new CMainFrame;
    	if(!pFrame)
    		return FALSE; 
    	m_pMainWnd = pFrame;
    	pFrame->LoadFrame(IDR_MAINFRAME, 
    		WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, NULL);
    
    	pFrame->ShowWindow(SW_SHOW);
    	pFrame->UpdateWindow();
    	return TRUE;
    }
    

    Im ersten View also den vom Assistenten erzeugten wird auch OnInitialUpdate aufgerufen.


  • Mod

    Das ist aber nicht der Standard-Code, den der Wizard erzeugt hat...

    Du musst Dich nicht wundern, wenn Du Low-Level-Routinen wie LoadFrame verwendest, wenn anadere Standardfunktionen eben nicht aufgerufen werden.

    Der Standard ruft einfach nur ProcessShellCommand bei einer SDI Applikation auf.
    Diese Funktion erzeugt den Frame und alles andere...



  • Ok das hätte ich erwähnen müssen, das ich den Wizard Code an einigen Stellen ändern musste um mit unseren Klassen zu arbeiten. Sorry.

    Aber was kann tun? Was ist mit allem anderen?
    Welche Methoden muss ich noch aufrufen?


  • Mod

    mr. main schrieb:

    Ok das hätte ich erwähnen müssen, das ich den Wizard Code an einigen Stellen ändern musste um mit unseren Klassen zu arbeiten. Sorry.

    Aber was kann tun? Was ist mit allem anderen?
    Welche Methoden muss ich noch aufrufen?

    Wieso musst Du den Wizard Code genau bei der Stelle ändern in der das CDocTemplate die Instanz erzeugt?
    Raff ich nicht...

    Was macht ProcessShellCommand zuviel?

    Wenn Du alles selber machen willst, Debugge Dich durch den MFC Code (ist nicht schwer) und sorge eben für die entsprechenden Aufrufe (Siehe CSingleDocTemplate::OpenDocumentFile).



  • Ich muss mich doch noch mal erst ein wenig durch unsere Klassen wühlen, mir ist hier noch so einiges aufgefallen was nicht so läuft wie von MFC.
    Bevor ich das ganze nicht verstehe, kann ich hier soviel fragen wie ich will, kann die Unterschiede nicht so rüberbringen.

    Also so wie ich das bei uns bisher verstanden habe, nehmen wir einzig den Rahmen und arbeiten gar nicht mit der Document Klasse. Der Hintergrund des Fensters wird komplett selbst gezeichnet und darauf dann die Views aufgebracht.
    Ist dann so halt schwer es zu erklären. Allerdings sind unsere Klasse nun mal von den meisten MFC Klassen abgeleitet somit wird über den Assistenten das Projekt angelegt, dass man schon mal die ganzen Sachen von wegen vorkompilierten Headern und alles drin hat. Sehr seltsam alles ich weiß:D:D


  • Mod

    Also wenn Du kein Document hast, dann kannst Du auch keine View Klasse verwenden... denn die benötigt immer ein Document. Dann kan es natürlich auch kein OnUpdate oder OnInitialUpdtae geben.

    Ohne Doc/View musst Du alles selber machen.



  • Ok, ich bin jetzt dabei das ganze selbst zu machen.

    Durch Abfangen von OnMouseMove und Prüfung ob Linke Maustaste geklickt ist(MK_LBUTTON) bin ich jetzt soweit, das ich meine Controls in eine Richtung vergrößern/verkleinern kann.
    Sprich ich vergrößere das 1.Element und verkleinere bzw. verschiebe gleichzeitig das 2. und das 3.
    Nun möchte ich dies auch in die andere Richtung machen, sprich ich verkleinere das erste Element wieder und vergrößere bzw. verschiebe das 2. und 3.

    Hatte gedacht, wäre ganz einfach. Merken der letzten Cursorposition und wenn die aktuelle kleiner als die gemerkte ist, dann alles umgekehrt machen.
    Leider klappt es so nicht.

    Hier mal die OnMouseMove von mir.

    void CChildView::OnMouseMove(UINT nFlags, CPoint point)
    {
    	CRect crContact, crSubject, crMessage;
    	HCURSOR hCurs;
    	int nDiff = 0;
    	CPoint curPoint, oldPoint;
    	GetCursorPos(&oldPoint);
    	m_wndContactView.GetWindowRect(&crContact);
    	m_wndSubjectView.GetWindowRect(&crSubject);
    	m_wndMessageView.GetWindowRect(&crMessage);
    	ScreenToClient(&crContact);
    	ScreenToClient(&crSubject);
    	ScreenToClient(&crMessage);
    	DWORD dwErr ;
    	HDWP hdwp = BeginDeferWindowPos(4);
    	if(hdwp == NULL)
    		dwErr = GetLastError();
    	//m_noldCursorPos = point.x;
    	if((point.x > crContact.right) && (point.x < crSubject.left)
    		&& (point.y >= crContact.top) && (point.y <= crContact.bottom)) 
    	{
    		hCurs = LoadCursor(NULL, IDC_SIZEWE);
    		SetCursor(hCurs);
    
    			if((nFlags & MK_LBUTTON) == MK_LBUTTON)
    			{
    				if(m_noldCursorPos == 0)
    					m_noldCursorPos = point.x;
    
    				if(crMessage.Width() > (m_nDefWidthMessageView / 3))
    				{
    					nDiff = point.x - crContact.right;
    					crContact.right = point.x;
    					crSubject.left += nDiff;
    					crSubject.right += nDiff;
    					crMessage.left += nDiff;
    					DeferWindowPos(hdwp, m_wndContactView.m_hWnd, NULL, crContact.left, crContact.top,
    					crContact.Width(), crContact.Height(), SWP_NOZORDER);
    					DeferWindowPos(hdwp, m_wndSubjectView.m_hWnd, NULL, crSubject.left, crSubject.top,
    						crSubject.Width(), crSubject.Height(), SWP_NOZORDER);
    					DeferWindowPos(hdwp, m_wndMessageView.m_hWnd, NULL, crMessage.left, crMessage.top,
    						crMessage.Width(), crMessage.Height(), SWP_NOZORDER);
    					m_noldCursorPos = point.x;
    				}
    				if(crSubject.Width() > (m_nDefWidthSubjectView / 3))
    				{
    					nDiff = point.x - crContact.right;
    					crContact.right = point.x;
    					crSubject.left += nDiff;
    					DeferWindowPos(hdwp, m_wndContactView.m_hWnd, NULL, crContact.left, crContact.top,
    					crContact.Width(), crContact.Height(), SWP_NOZORDER);
    					DeferWindowPos(hdwp, m_wndSubjectView.m_hWnd, NULL, crSubject.left, crSubject.top,
    						crSubject.Width(), crSubject.Height(), SWP_NOZORDER);
    					m_noldCursorPos = point.x;
    				}
    
    			}
    	}
    	else if((point.x > crSubject.right) && (point.x < crMessage.left)
    		&& (point.y >= crContact.top) && (point.y <= crContact.bottom))
    	{
    		if((nFlags & MK_LBUTTON) == MK_LBUTTON)
    		{
    			if(crMessage.Width() > (m_nDefWidthMessageView / 3))
    			{
    				nDiff = point.x - crSubject.right;
    				crSubject.right = point.x;
    				crMessage.left += nDiff;
    
    				DeferWindowPos(hdwp, m_wndContactView.m_hWnd, NULL, crContact.left, crContact.top,
    				crContact.Width(), crContact.Height(), SWP_NOZORDER);
    				DeferWindowPos(hdwp, m_wndSubjectView.m_hWnd, NULL, crSubject.left, crSubject.top,
    					crSubject.Width(), crSubject.Height(), SWP_NOZORDER);
    				DeferWindowPos(hdwp, m_wndMessageView.m_hWnd, NULL, crMessage.left, crMessage.top,
    					crMessage.Width(), crMessage.Height(), SWP_NOZORDER);
    				m_noldCursorPos = point.x;
    			}
    
    		}
    		hCurs = LoadCursor(NULL, IDC_SIZEWE);
    		SetCursor(hCurs);
    	}
    	else
    	{
    		hCurs = LoadCursor(NULL, IDC_ARROW);
    		SetCursor(hCurs);
    	}
    
    	EndDeferWindowPos(hdwp);
    	CFormView::OnMouseMove(nFlags, point);
    }
    

Anmelden zum Antworten