Probleme mit Grafik



  • Habe folgendes Problem, versuche in ein PictureControl zu zeichnen, dessen Handle ich vorher mit

    CWnd* hWndGraphArea = GetDlgItem(IDC_GRPH_AREA_ONE);
    

    ermittelt habe. Nun rufe ich DrawChart auf:

    m_pLeftGraph->DrawChart(m_pLeftFile, hWndGraphArea);
    

    und ein zu zeichnender Datensatz und das Handle auf den Zeichenbereich werden übergeben.

    void CGraphics::DrawChart(CDataSet* myDataSet, CWnd* myGraphHandle)
    {
        int x1, x2, y1, y2;
        // Initialisierung
        CClientDC dc(myGraphHandle);
        LPRECT PaintRect = new RECT;
        myGraphHandle->GetClientRect(PaintRect);
        CPen penBlack(PS_SOLID, 1, RGB(0,0,0));
    
        x1 = PaintRect->left;
        y1 = PaintRect->top;
        x2 = PaintRect->right;
        y2 = PaintRect->bottom;
    
        ...
    }
    

    Problem ist, wie kann ich verifizieren, ob bei der Initialisierung des Zeichnens alles klar geht? Die Zeile myGraphHandle->GetClient... sollte die RECT-Struktur füllen, tut sie aber nicht. Kommt aber auch keine Fehlermeldung? Wie gehe ich hier vor?

    Wie finde ich die Ursache?



  • Hi,

    GetClientRect liefert keine Vernünftigen Daten? Es kann sein, das dein Handle
    auf das Window-Objekt nicht mehr gültig ist, den GetDlgItem liefert unter
    Umständen nur ein temporäres Handle zurück, und kann nur innerhalb
    der Funktion verwendet werden.

    MSDN:

    Return Value
    Returns a pointer to the given control or child window. If no control with the integer ID given by the nID parameter exists, the value is NULL.

    The returned pointer may be temporary and should not be stored for later use.

    Kannst Du der Zeichenfunktion nicht die ID des Controls übergeben und
    erst in der Zeichenfunktion GetDlgItem aufrufen?
    Dann sollte GetClientRect die richtigen Werte liefern.

    BTW würde ich die RECT Struktur nicht per new anlegen (Heapfragmentation und
    Gefahr von Speicherleck).
    Lieber:

    CClientDC dc(myGraphHandle);
        RECT PaintRect;
        myGraphHandle->GetClientRect(&PaintRect);
    

    Gruss
    EB



  • Danke, das mit dem RECT funktioniert schon mal...

    Leider habe ich mich nicht genau ausgedrückt. Die Klasse, in der GetDlgItem(nID) aufgerufen wird, ist die Dlg-Applikatonsklasse. Dort funktioniert es ohne zu murren. In der CGraphics-Klasse sagt er immer

    GetDlgItem : Funktion akzeptiert keine 1 Argumente
    

    warum auch immer. Wie kann ich ihm klar machen, welche GetDlgItem() es ist?



  • Hi,

    deine CGraphícs-Klasse ist also unabhängig vom Dialog. CGraphics verwendet
    dann GetDlgItem aus der WINAPI und benötigt daher ein Handle auf ein
    Fenster (CDialog in deinem Fall). An das Handle kannst Du auf verschiedene
    Arten kommen. Wenn es dann Fehlerfrei kompiliert, bezweifle ich jedoch,
    das deine Zeichenroutine funktioniert. Bzw. sie wird zwar ausgeführt, jedoch
    siehst Du sehr wahrscheinlich nichts, da das PictureControl deine Aktion
    wieder überzeichnet.

    Ich würde das Programmdesign nochmal überlegen.

    Mein Vorschlag: Du leitest eine Klasse vom PictureControl, welches ja nur ein
    CStatic ist ab, und überschreibst dann die OnPaint-Methode um deine Daten zu
    zeichnen. Du setzt ein Picture-Control im Editor auf deinen Dialog, gibst dem
    eine ID z.B. IDC_CHARTCTRL und erstellst eine Membervariable dafür.
    Dann änderst Du den Datentyp der Membervariable in deine Klasse um.

    Ein Beispiel habe ich mal angeheftet:

    // ChartDlg.h : Headerdatei
    //
    
    #pragma once
    #include "afxwin.h"
    #include <afxtempl.h> // benötigt für CArray
    
    // CChartcontrol 
    class CChartControl : public CStatic
    {
    public:
    	DECLARE_MESSAGE_MAP()
    	afx_msg void OnPaint();
    };
    
    // CChartDlg Dialogfeld
    class CChartDlg : public CDialog
    {
    // Konstruktion
    public:
    	CChartDlg(CWnd* pParent = NULL);	// Standardkonstruktor
    
    // Dialogfelddaten
    	enum { IDD = IDD_CHART_DIALOG };
    
    	protected:
    	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV-Unterstützung
    
    // Implementierung
    protected:
    	HICON m_hIcon;
    
    	// Generierte Funktionen für die Meldungstabellen
    	virtual BOOL OnInitDialog();
    	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    	afx_msg void OnPaint();
    	afx_msg HCURSOR OnQueryDragIcon();
    	DECLARE_MESSAGE_MAP()
    public:
    	CChartControl m_wndChartCtrl;
    	CArray<UINT, UINT> m_arrData; // array für ein paar Daten
    };
    
    // ChartDlg.cpp : Implementierungsdatei
    //
    
    #include "stdafx.h"
    #include "Chart.h"
    #include "ChartDlg.h"
    #include ".\chartdlg.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    // CChartDlg Dialogfeld
    
    CChartDlg::CChartDlg(CWnd* pParent /*=NULL*/)
    	: CDialog(CChartDlg::IDD, pParent)
    {
    	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }
    
    void CChartDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    	DDX_Control(pDX, IDC_CHARTCTRL, m_wndChartCtrl);
    }
    
    BEGIN_MESSAGE_MAP(CChartDlg, CDialog)
    	ON_WM_SYSCOMMAND()
    	ON_WM_PAINT()
    	ON_WM_QUERYDRAGICON()
    	//}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    
    // CChartDlg Meldungshandler
    
    BOOL CChartDlg::OnInitDialog()
    {
    	CDialog::OnInitDialog();
    
    	CMenu* pSysMenu = GetSystemMenu(FALSE);
    	if (pSysMenu != NULL)
    	{
    		CString strAboutMenu;
    		strAboutMenu.LoadString(IDS_ABOUTBOX);
    		if (!strAboutMenu.IsEmpty())
    		{
    			pSysMenu->AppendMenu(MF_SEPARATOR);
    			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
    		}
    	}
    
    	SetIcon(m_hIcon, TRUE);
    	SetIcon(m_hIcon, FALSE);
    
    	// fülle array mit ein paar Daten in Prozent für Säulendiagramm
    	m_arrData.Add(30);
    	m_arrData.Add(40);
    	m_arrData.Add(60);
    	m_arrData.Add(80);
    	m_arrData.Add(90);
    
    	return TRUE;
    }
    
    void CChartDlg::OnSysCommand(UINT nID, LPARAM lParam)
    {
    	CDialog::OnSysCommand(nID, lParam);
    }
    
    void CChartDlg::OnPaint() 
    {
    	if (IsIconic())
    	{
    		CPaintDC dc(this);
    
    		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
    
    		int cxIcon = GetSystemMetrics(SM_CXICON);
    		int cyIcon = GetSystemMetrics(SM_CYICON);
    		CRect rect;
    		GetClientRect(&rect);
    		int x = (rect.Width() - cxIcon + 1) / 2;
    		int y = (rect.Height() - cyIcon + 1) / 2;
    
    		dc.DrawIcon(x, y, m_hIcon);
    	}
    	else
    	{
    		CDialog::OnPaint();
    	}
    }
    
    HCURSOR CChartDlg::OnQueryDragIcon()
    {
    	return static_cast<HCURSOR>(m_hIcon);
    }
    
    // CChartControl
    
    BEGIN_MESSAGE_MAP(CChartControl, CStatic)
    	ON_WM_PAINT()
    END_MESSAGE_MAP()
    
    void CChartControl::OnPaint()
    {
    	CPaintDC dc(this);
    
    	CRect rcClient;
    	GetClientRect(&rcClient);
    
    	// zeichne einen Rahmen
    	dc.Rectangle(&rcClient);
    	rcClient.DeflateRect(1, 1);
    
    	// zeichne Hintergrund weiss
    	dc.FillSolidRect(&rcClient, RGB(255, 255, 255));
    
    	rcClient.DeflateRect(1, 1);
    
    	// hole zeiger auf Dialogklasse
    	CChartDlg* pDialog = DYNAMIC_DOWNCAST(CChartDlg, GetParent());
    
    	if ( pDialog ) // zeiger erhalten?
    	{
    		// zeichne Säulendiagramm
    		int x = rcClient.Width() / pDialog->m_arrData.GetCount();
    		for ( int i = 0; i < pDialog->m_arrData.GetCount(); ++i )
    		{
    			int y = rcClient.Height() * pDialog->m_arrData.GetAt(i) / 100;
    			dc.FillSolidRect(rcClient.left + i * x, rcClient.bottom, x, -y, RGB(255, 0, 0));
    		}
    	}
    }
    

    Gruss
    EB



  • Super, 👍
    das hat schon mal funktioniert. Verstehe jetzt nur nicht, warum ich zwar die Charts sehe, aber wenn ich statt dessen

    for (int i = 0; i < rcClient.right; ++i)
    {
        dc.MoveTo(i,100);
        dc.LineTo(i,100);
    }
    

    an die Stelle unter

    // zeichne Säulendiagramm
    

    schreibe, sehe ich nix... 😕

    Stift wurde mit

    CPen penRed(PS_SOLID, 1, RGB(255,0,0));
    dc.SelectObject(&penRed);
    

    initialisiert...



  • Hi,

    du zeichnest ja auch nichts!

    for (int i = 0; i < rcClient.right; ++i)
    {
        dc.MoveTo(i,100);
        dc.LineTo(i,100);
    }
    

    setz mal Zahlen für i ein:
    MoveTo(0, 100) -> LineTo(0, 100) = NICHTS

    for (int i = 0; i < rcClient.right; ++i)
    {
        dc.MoveTo(i,100);
        dc.LineTo(i,150);
    }
    

    MoveTo(0, 100) -> LineTo(0, 150) = 50px Y-Linie

    Gruss
    EB



  • Ok, gegen dieses Argument hab ich keine Chance... Asche auf mein Haupt! 😃
    Danke, es geht. Vielen Dank!

    PS: Ich war immer der Meinung eine Linie von x,y bis x,y ist ein Pixel an dieser Stelle. Gibt es in der CDC-Klasse auch Pixelfunktionen? Muss nämlich Kurven zeichnen.


Anmelden zum Antworten