tutorials.de Buch-Aktion 05/2012
ERLEDIGT
JA
ANTWORTEN
9
ZUGRIFFE
394
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    Cappaja Cappaja ist offline Mitglied Silber
    Registriert seit
    May 2009
    Ort
    Konstanz
    Beiträge
    85
    Hallo,

    ich sitze wahrscheinlich schon zu lange davor und verstehe nicht mehr den Zusammenhang. Ich habe eine dialogbasierende Anwendung CWiwoDlg als Main-Klasse. Nebenbei habe ich in einer Klasse CGraph für eine Zeichenroutine eines Cursors, welcher bei LBUTTONDOWN über den jeweilige CPOINT point.x in X-Richtung gesetzt wird. Beim Aufruf aus der Main-Klasse findet er an rotmarkierter Stelle nicht mehr das Handle vom Typ CWnd *m_pWnd und springt beim debuggen genau an dieser Stelle heraus. Weiß jemand woran das liegen könnte?

    Codeausschnitt aus CWiwoDlg.cpp
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    
    void CWiwoDlg::OnLButtonDown(UINT nFlags, CPoint point) 
    {
        CGraph pGraph;
        CRect rect = pGraph.CalcDataArea();
        BOOL bFlag = CheckRect(point, rect);
     
        if(bFlag == TRUE)
        {
            int nCX, nCY;
            nCX = point.x;
            nCY = point.y;
            CString sCX, sCY;
            sCX.Format("%d", nCX);
            sCY.Format("%d", nCY);
            m_ctrlCX.SetWindowText(sCX);
            m_ctrlCY.SetWindowText(sCY);
            pGraph.DrawCursor(nCX);
        }
        else
            TRACE("\nCX und CY liegen ausserhalb!\n");
        
        CDialog::OnLButtonDown(nFlags, point);
    }
     
    BOOL CWiwoDlg::CheckRect(CPoint point, CRect rect)
    {
        if(point.x < rect.left)   return FALSE;
        if(point.x > rect.right)  return FALSE;
        if(point.y > rect.bottom) return FALSE;
        if(point.y < rect.top)    return FALSE;
        return TRUE;
    }

    Codeausschnitt aus CGraph.cpp
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    
    void CGraph::DrawCursor(int nCX)
    {
        try
        {
            if(!m_pWnd)
                [COLOR="Red"]return;[/COLOR]
     
            CPen *pStandardPen;
            CPen MyPen;
            CRect DataArea = CalcDataArea();
     
            // DC zum Zeichnen anlegen
            CDC *pDC = m_pWnd->GetDC();
            MyPen.CreatePen(PS_SOLID, 1, RGB(255,255,255));
            // MyPen als Standard Pen an pDC übergeben
            pStandardPen = pDC->SelectObject(&MyPen);
     
            // ### TODO Zeichenroutine für Cursor ###
            pDC->MoveTo(/*m_iGraphWidth / 2*/nCX, DataArea.top);
            pDC->LineTo(/*m_iGraphWidth / 2*/nCX, DataArea.bottom);
     
            // CleanUp
            m_pWnd->ReleaseDC(pDC);
        }
        catch(CResourceException &CEx)
        {
            char msg[128];
            CEx.GetErrorMessage(msg, sizeof(msg));
            MessageBox(NULL, msg, "Fehler", MB_ICONERROR);
        }
    }
     

  2. #2
    Avatar von vfl_freak
    vfl_freak vfl_freak ist offline Mitglied Diamant
    Registriert seit
    Aug 2007
    Ort
    Niedersachsen
    Beiträge
    2.161
    Moin,

    wo ist denn "m_pWnd" deklariert ? ? ?

    Zeig uns mal mehr Code ......

    Vermutlich solltest Du den Zeiger darauf irgendwie über die aufrufende Funktion "OnLButtonDown" durchreichen (ggf. per this).

    Gruß
    Klaus
     
    Es ist noch kein Meister vom Himmel gefallen - sonst hätte man schon längst seine Leiche gefunden !!

    Falls ich helfen konnte, wäre eine Bewertung oder ein Danke nett ;-)
    -------------------------------------------------------------------------------------------------
    Ich beantworte keine Fragen per PN !!
    Stellt Eure Fragen im Forum - dann haben alle etwas davon !!

  3. #3
    MCoder MCoder ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jul 2005
    Ort
    München
    Beiträge
    2.448
    Abgesehen davon was Klaus schon geschrieben hat: Zeichenoperation sollten immer im OnPaint-Handler ausgeführt werden, weil sie sonst schnell wieder überbügelt werden.
    Bei OnLButtonDown() legst du nur fest was gezeichnet werden soll (etwa mit Hilfe von Member-Variablen) und rufst dann lediglich Invalidate() auf. Dadurch wird automatisch OnPaint() aufgerufen. Dort bekommst du einen Gerätekontext, den du als Parameter an die DrawCursor()-Methode übergeben kannst. Das Fensterhandle brauchst du dann eigentlich nicht mehr.

    Gruß
    MCoder
     
    "The three chief virtues of a programmer are: Laziness, Impatience and Hubris."
    --- Larry Wall

  4. #4
    Cappaja Cappaja ist offline Mitglied Silber
    Registriert seit
    May 2009
    Ort
    Konstanz
    Beiträge
    85
    also erstmal danke.
    m_pWnd ist in CGraph.h deklariert.
    Das ganze ist eine fertige Klasse CGraph welche ich von Codeguru übernommen und eingebunden habe. In dieser Klasse exisitert die Methode PaintGraph() welche ich in der OnPaint() der Mainklasse über eine Membervariable auch ausführe. Innerhalb der PaintGraph() habe ich zuerst auch meine Methode DrawCursor ausgeführt was funktionierte. Jetzt wollte ich es aber noch nachrichtenorientiert gestalten und weiß nicht wie ich mit den MFC da am besten vorgehe.

    Ich muss der Methode DrawCursor eben unbedingt die CPoint Koordinate nCX mitgeben damit er innerhalb des gültigen DataAreas in X-Richtung verschoben werden kann. dazu brauche ich doch die mausnachricht. ich wüsste momentan nicht wie ich das anders gestalten könnte. an der rotmarkierten Stelle im unteren Code müsste anstelle eines statischen Werts nCX des linken Mausklicks übergeben, aber wie?

    ich habe ja bereits einen Zeiger auf die Klasse CGraph, andernfalls müsste ich auf die Klassen gegenseitig verweisen, was man doch tunlichst vermeiden sollte und zu compilerfehlern führt. sonst könnte ich ja einfach das Ergebnis von nCX in eine Membervariable schreiben und diese dem Übergabeparameter von DrawCursor() in PaintGraph() zuweisen.

    hier der code von PaintGraph()
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    
    //////////////////////// PaintGraph //////////////////////////////////////
    /*
        This paints the entire graph on to the holding window's
        client area;
        It does it in steps starting from the background and working forward.
        As the graph is NOT a window object in it's own right, it uses the
        display context of the holding window. If it has not been given a 
        pointer to the holding window, it will not paint.
        Any CGraph routine that paints to the screen, checks the window pointer
        first.
        The last thing to be painted is the plotting of the function data (if any)
    */
    ///////////////////////////////////////////////////////////////////////////
    void CGraph::PaintGraph()
    {
        //here we draw the graph
        //step 1: Draw the surrounding rectangle
        //for the whole graph
        if (m_pWnd==NULL)
        {
            return;
        }
        CRect rect;
        CPen pen, *oldpen;
        CDC *dc=m_pWnd->GetDC();
        //some useful calculations
        UINT lmargin=CalcLeftMargin();
        UINT rmargin=CalcRightMargin();
        UINT bmargin=CalcBottomMargin();
        UINT tmargin=CalcTopMargin();
        UINT Graphbottom=m_iGraphY+m_iGraphHeight;
        UINT Graphright=m_iGraphX+m_iGraphWidth;
     
        //step 2: color the background
        CBrush brush,*poldbrush;
        brush.CreateSolidBrush(m_crGraphBkColor);
        pen.CreatePen(PS_SOLID,1,m_crGraphBkColor);
        rect.left=m_iGraphX;
        rect.right =rect.left+m_iGraphWidth;
        rect.top=m_iGraphY;
        rect.bottom=rect.top+m_iGraphHeight;
        oldpen=dc->SelectObject(&pen);
        poldbrush=dc->SelectObject(&brush);
        dc->Rectangle(&rect);
        dc->SelectObject(oldpen);
        dc->SelectObject(poldbrush);
        pen.Detach();
        
        //step 3: Draw Grid if required
        DrawGrid();
        
        //step 4: Draw Axies
        //draw x-axis
        dc->MoveTo(m_iGraphX+lmargin,Graphbottom-m_iOriginY);
        pen.CreatePen(PS_SOLID,1,m_crXTickColor);
        oldpen=dc->SelectObject(&pen);
        dc->LineTo(Graphright-rmargin,Graphbottom-m_iOriginY);
        dc->SelectObject(oldpen);
        pen.Detach();
     
        //draw the Y Axis
        pen.CreatePen(PS_SOLID,1,m_crXTickColor);
        oldpen=dc->SelectObject(&pen);
        if (!m_bYLineAtLeft)
        {
            //draw the Y Line so that it intercepts
            //the x-line like crosshairs
            dc->MoveTo(m_iGraphX+m_iOriginX,m_iGraphY+tmargin);
            dc->LineTo(m_iGraphX+m_iOriginX,Graphbottom-bmargin);
        }
        else
        {
            //draw the Y Line at the LHS
            dc->MoveTo(m_iGraphX+lmargin,m_iGraphY+tmargin);
            dc->LineTo(m_iGraphX+lmargin,Graphbottom-bmargin);
        }
        dc->SelectObject(oldpen);
        pen.Detach();
     
        //step 5: draw ticks if required
        DrawTicks();
     
    [COLOR="Red"]   //step 5.1: draw cursor
        //DrawCursor(0);[/COLOR]
     
        //step 6: Write Graph title
        DrawGraphTitle();
     
        //step 7: Write Function name
        DrawFunctionName();
     
        //step 8: Write x-legend
        DrawXLegend();
     
        //step 9: Write y legend
        //doing this is very similar to doing the graph title or the
        //x-legend but the Y axis is either at the LHS or set to match the
        //x-origin
        DrawYLegend();
     
        //step 10: write the x & y axes values
        DrawXAxisNumbers();
        DrawYAxisNumbers();
     
        //Step 11
        //draw Function
        DrawFunction();
     
        //Cleanup
        m_pWnd->ReleaseDC(dc);
    }
    Geändert von Cappaja (07.07.09 um 13:23 Uhr)
     

  5. #5
    MCoder MCoder ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jul 2005
    Ort
    München
    Beiträge
    2.448
    Hallo,

    wie gesagt, ich halte es für keine gute Lösung, einen DeviceKontext zum Zeichnen auf einer Fensteroberfläche extra zu generieren, statt den in OnPaint erzeugten zu verwenden.
    Zunächst würde ich der Methode "PaintGraph" einen Parameter für den DeviceKontext geben:
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    void CGraph::PaintGraph(CDC *dc)
    {
        // ...
    }
     
    ...
     
    void CWiwoDlg::OnPaint() 
    {
        CPaintDC dc(this);
        pGraph.PaintGraph(&dc);
    }
    Falls die anderen Zeichenmethoden (DrawTicks usw.) den CDC auf ähnliche Weise erzeugen, sollte der Parameter dort auch ergänzt werden. Die Membervariable "m_pWnd" kann dann entfallen.
    Statt dessen könntest du innerhalb von CGraph eine Member-Variable für die Koordinate deklarieren und beim Button-Klick entsprechend belegen. Ebenso sollte das CGraph-Objekt als Member von CWiwoDlg deklariert werden:
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    
    // im CGraph Header
    public:
        int m_nCX;
     
    // im CWiwoDlg Header
    public:
        CGraph m_Graph;
     
    // in PaintGraph
    DrawCursor(m_nCX);
     
    void CWiwoDlg::OnLButtonDown(UINT nFlags, CPoint point) 
    {
        CRect rect = m_Graph.CalcDataArea();
        BOOL bFlag = CheckRect(point, rect);
     
        if(bFlag == TRUE)
        {
            int nCX, nCY;
            nCX = point.x;
            nCY = point.y;
            CString sCX, sCY;
            sCX.Format("%d", nCX);
            sCY.Format("%d", nCY);
            m_ctrlCX.SetWindowText(sCX);
            m_ctrlCY.SetWindowText(sCY);
            
            m_Graph.m_nCX = nCX; // Koordinate belegen
            Invalidate(); // Aufruf von OnPaint auslösen
        }
        
        CDialog::OnLButtonDown(nFlags, point);
    }
    Gruß
    MCoder
     
    "The three chief virtues of a programmer are: Laziness, Impatience and Hubris."
    --- Larry Wall

  6. #6
    Cappaja Cappaja ist offline Mitglied Silber
    Registriert seit
    May 2009
    Ort
    Konstanz
    Beiträge
    85
    Hallo MCoder

    danke für deinen ratschlag. nachdem ich alles so hatte war mein graph komplett verschwunden. es sind 10 methoden die ebenfalls ein CDC objekt anlegen und in wiederum vielen weiteren methoden aufgerufen werden, es wurde ein durcheinander wobei am ende das fenster auf der strecke blieb.

    ich habe jetzt mal mein backup gestartet und deinen befehl in zeile 28 übernommen. das war es was ich ursprünglich gesucht hatte. so rufe ich die methode DrawCursor() nicht explizit auf sondern übergebe sie mit der PaintGraph() in der OnPaint(). Jetzt bekomme ich zwar keine Fehlermeldungen mehr, allerdings sehe ich auch nirgends meinen Cursor. Oder liegt der Fehler in der Paint-Methode? allerdings hab ich hier nur an einer zeile selbst hand angelegt:

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    void CWiwoDlg::OnPaint() 
    {
        if(IsIconic())
        {
            CPaintDC dc(this); // Gerätekontext für Zeichnen
     
            SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
     
            // Symbol in Client-Rechteck zentrieren
            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;
     
            // Symbol zeichnen
            dc.DrawIcon(x, y, m_hIcon);
        }
        else
        {
            CDialog::OnPaint();
            m_pGraph->PaintGraph();
        }
    }
    Geändert von Cappaja (07.07.09 um 17:34 Uhr)
     

  7. #7
    MCoder MCoder ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jul 2005
    Ort
    München
    Beiträge
    2.448
    Zitat Zitat von Cappaja Beitrag anzeigen
    und deinen befehl in zeile 28 übernommen
    Verwendest du dann auch den Member m_nCX? Schaue doch mit dem Debugger nach, welcher Wert überhaupt an DrawCursor() übergeben wird.

    Gruß
    MCoder
     
    "The three chief virtues of a programmer are: Laziness, Impatience and Hubris."
    --- Larry Wall

  8. #8
    Cappaja Cappaja ist offline Mitglied Silber
    Registriert seit
    May 2009
    Ort
    Konstanz
    Beiträge
    85
    hi mcoder,

    habe das problem gelöst: in zeile 28 sollte der Inhalt mittels m_pGraph->m_nCX = nCX; übergeben werden. so stand zwar kurzzeitig der richtige wert drin, wurde aber nicht in die klasse CGraph übernommen sodass immer der grenzwert von int übergeben wurde.

    nebenbei noch ne kleine frage: wäre es nicht effizienter anstelle von invalidate() nur m_pGraph->PaintGraph() aufzurufen? so wird lediglich der Graph anstelle des kompletten Fensters neu gezeichnet oder täusche ich mich da? zumindest erhalte ich auf diese weise kein flackern bei mehrmaligem aktualisieren.
    Geändert von Cappaja (08.07.09 um 15:24 Uhr)
     

  9. #9
    MCoder MCoder ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jul 2005
    Ort
    München
    Beiträge
    2.448
    Zitat Zitat von Cappaja Beitrag anzeigen
    nebenbei noch ne kleine frage: wäre es nicht effizienter anstelle von invalidate() nur m_pGraph->PaintGraph() aufzurufen? so wird lediglich der Graph anstelle des kompletten Fensters neu gezeichnet oder täusche ich mich da? zumindest erhalte ich auf diese weise kein flackern bei mehrmaligem aktualisieren.
    Wenn es besser funktioniert, mache es so. Ich habe mir die Funktionsweise der CGraph-Klasse nicht genauer angeschaut, so dass ich auch nicht viel zur optimalen Verwendung sagen kann. Meine Tipps beruhten auf meinen bisherigen Erfahrung mit der GDI-Programmierung, die aber im konkreten Fall nicht unbedingt passen müssen.

    Gruß
    MCoder
     
    "The three chief virtues of a programmer are: Laziness, Impatience and Hubris."
    --- Larry Wall

  10. #10
    Cappaja Cappaja ist offline Mitglied Silber
    Registriert seit
    May 2009
    Ort
    Konstanz
    Beiträge
    85
    hauptsache alles passt soweit, vielen dank mal bis dahin
     

Ähnliche Themen

  1. Window-Handle in DLL
    Von Billie im Forum C/C++
    Antworten: 3
    Letzter Beitrag: 17.03.09, 14:20
  2. window handle
    Von martinpriebe im Forum .NET Application und Service Design
    Antworten: 3
    Letzter Beitrag: 06.08.07, 09:39
  3. Child Handle -> Parent Handle
    Von dobermant im Forum Visual Basic 6.0
    Antworten: 0
    Letzter Beitrag: 01.12.06, 02:08
  4. Handle auf aktives Office Window
    Von ThAigner im Forum Visual Basic 6.0
    Antworten: 0
    Letzter Beitrag: 02.06.05, 21:09
  5. Get Window Handle From Location
    Von kahuna im Forum C/C++
    Antworten: 2
    Letzter Beitrag: 04.12.04, 13:55