Ar zuikių mokyklėlėje piešia morkas?

Praeituose 'Vartiklio' Nr.5 ir  Nr.6  numeriuose susipažinę su MFC pagrindais iškart panorome ką nors nupiešti - juk "Windows" yra grafinė terpė, kurioje šią sritį globoja GDI ("Graphics Device Interface").

"Windows" terpės programa tiesiogiai nedirba nė su vienu išvedimo įrenginiu - ji terašo į įrenginio kontekstą (DC), kurio valdiklio reikšmės ir turi, visų pirma, paprašyti sistemos (Tik reikia niekada neužmiršti kuo greičiau jį grąžinti sistemai, nes DC tėra tik PENKI - ir juos dalijasi visos "Windows" programos). Programuojant naudojant MFC, CDC objektas apima visas išvedimo funkcijas (jos taip pat įeina ne tik į anksčiau minėtą "CPaintDC", bet ir kitas konteksto klases). Pvz., štai kaip nubrėžiama atkarpa:

CDC *pDC = GetDC();    // gauti kontekstą
pDC -> MoveTo (startX, startY); // nueiti į pradžią
pDC -> LineTo (endX, endY);   // brėžti liniją
ReleaseDC ();

Tačiau dar paprasčiau yra naudojant "CClientDC" poklasį, nes sukūrus šios klasės objektą nereikia rūpintis DC išlaisvinimu - tai automatiškai padarys objekto destrukcijos funkcija. Ankstesnis pavyzdėlis yra perrašomas taip (laikoma, kad tai nedidelės funkcijos, atliekančios tik piešimo veiksmus, dalis):

CClientDC dc (this);    // gauti lango kliento dalies kontekstą
dc.MoveTo (startX, startY);   // nueiti į pradžią
dc.LineTo (endX, endY);    // brėžti liniją

Kartais norisi piešti ne tik kliento srityje, bet ir bet kurioje lango vietoje (pvz., antraštėje). Tada galima naudoti (labai panašią į "CClientDC") klasę "CWindowsDC". O labai retais atvejais, kai reikia ką nors nupiešti bet kurioje ekrano vietoje, "CClientDC" arba "CWindowsDC" objektui perduodame NULL reikšmę, t.y.
CClientDC dc (NULL);    // gauti viso ekrano kontekstą
Be atkarpos brėžimo galima naudoti ir tokias funkcijas:
ArcTo - brėžti elipsės lanką;
Ellipse - brėžti elipsę;
FillRect - uždažyti stačiakampį naudojant veiksnų teptuką;
FloodFill - uždažyti bet kokios formos sritį;
Pie - brėžti ir uždažyti skritulinės diagramos elementą;
Polygon - brėžti ir uždažyti daugiakampį;
RoundRect - brėžti ir uždažyti stačiakampį apvaliais kampais.

Apie plunksnas ir teptukus daugiau pakalbėsime kitą kartą, o dabar nupiešime morką. Ankstesniuose pavyzdžiuose užtenka pakeisti tik "OnPaint" funkciją.

// Failas MORKA.H: Apra÷ai ir klasił antra÷tós
class CManoPrograma : public CWinApp
{
   public: BOOL InitInstance ( );
};
class CPagrLangas : public CFrameWnd
{ public: CPagrLangas ( );
   protected:
     afx_msg void OnPaint ();
     DECLARE_MESSAGE_MAP ()
};

// Failas MORKA.RC: Resursai
manoIkona ICON morka.ico

// Failas MORKA.CPP: Programos tekstas
#include <afxwin.h>
#include "morka.h"


CManoPrograma manoPrograma; // Apra÷omas objektas
// Klasós narił realizacija
BOOL CManoPrograma :: InitInstance ( )
{ m_pMainWnd = new CPagrLangas ( ); // sukuriamas pagrindinis langas
   m_pMainWnd -> ShowWindow (m_nCmdShow); // prane÷ama, kad reikia i÷vesti
   m_pMainWnd -> UpdateWindow (); // fizi÷kai i÷vedamas
   return TRUE;
} // end CManoPrograma : InitInstance
// Pagr. lango prane÷imł dispetßeris
BEGIN_MESSAGE_MAP (CPagrLangas, CFrameWnd)
   ON_WM_PAINT ( )
END_MESSAGE_MAP ( )

// Žia kitos klasós narił realizacija
CPagrLangas :: CPagrLangas ( )
{ CString wndClass = AfxRegisterWndClass ( // registruoti lango klasń
     CS_HREDRAW | CS_VREDRAW,
     LoadCursor(manoPrograma.m_hInstance, IDC_CROSS),
     (HBRUSH)::GetStockObject(LTGRAY_BRUSH),
   LoadIcon(manoPrograma.m_hInstance, "manoIkona"));
   Create (wndClass, manoPrograma.m_pszExeName); // Sukurti langŻ su antra÷te 'Labas'
} // end CPagrLangas :: CPagrLangas
// Perklojama standartine funkcija
#include
void CPagrLangas :: OnPaint ( )
{ CPaintDC dc (this); // Ekrano kontekstas
   CPen plunksna (PS_SOLID,2, RGB(255,0,127));
   CPen *senaPlunksna = dc.SelectObject (&plunksna);
   CBrush teptukas(RGB(255,0, 127));
   CBrush *senasTeptukas = dc.SelectObject (&teptukas);
   FLOAT R= 250, PI = 3.1415926535;
   int pirmaX= R*cos(PI/6), antraX= R*cos(PI/8);
   int pirmaY= R*sin(PI/6), antraY= R*sin(PI/8);

   dc.MoveTo(60, 220);
   dc.LineTo(60+pirmaX, 220-pirmaY);
   dc.MoveTo(60, 220);
   dc.LineTo(60+antraX, 220-antraY);
   dc.Arc (60-R,220+R, 60+R, 220-R,
    60+antraX,220-antraY,60+pirmaX, 220-pirmaY);
   dc.FloodFill(60+R/2*cos(PI/7), 220-R/2*sin(PI/7),
    RGB(255,0,127));
   dc.SelectObject(senaPlunksna);
   dc.SelectObject(senasTeptukas);

// Beliko nupiešti žalius lapelius
{ int iLap, xPos; FLOAT nextR=112;
   int startX, startY, DX, DY;
   int iPosl[7] = {0, 6, 9, 11, 9, 6, 0};
   POINT pp[14];
   FLOAT kampas;
   CPen zPlunksna (PS_SOLID,2, RGB(64,195,64));
   CBrush zTeptukas(RGB(64,195, 64));
   dc.SelectObject (&zPlunksna);
   dc.SelectObject (&zTeptukas);

   for (iLap = 0; iLap < 3; iLap++)
   { kampas = PI / (6.0+(iLap+1)/2.0);
     startX = 60 + R*cos(kampas);
     startY = 220 - R*sin(kampas);
     DX = nextR/7*cos(kampas); DY = nextR/7*sin(kampas);
     for (xPos = 0; xPos < 7; xPos++)
     { pp[xPos].x = pp[xPos+7].x = startX + DX * xPos;
       pp[xPos].y = pp[xPos+7].y = startY - DY * xPos;
       pp[xPos].y -= iPosl[xPos];
       pp[xPos+7].y += iPosl[xPos];
     }
     dc.Polygon(pp, 13);
     dc.FloodFill(60+(R+nextR/3)*cos(kampas),
     220-(R+nextR/3)*sin(kampas),
     RGB(64,195,64));
   }
}
dc.SelectObject (senaPlunksna);
dc.SelectObject (senasTeptukas);
} // end CPagrLangas :: OnPaint