banner



How To Draw Using Windows Api For C++

  • Download source - viii.3 KB
  • Download demo project - 32.8 KB

Sample Image

Introduction

In reading the forums and answering the questions, I have found that many beginners would like to learn the fundamental concepts of painting in WIN32 programs. Developing applications for windows can be challenging and frustrating. information technology can likewise exist rewarding if you know some of the basic techniques that are required to take advantage of the WIN32 operating system. This tutorial is for beginners, and will cover the basic techniques and cognition required to go started with painting in WIN32.

The code and the concepts are all at the SDK level, as most of the other techniques that are used to pigment to windows are based on the SDK. The WIN32 SDK is used within of the MFC and ATL/WTL objects that represent those frameworks. I believe the more you know almost the base technology, the SDK, the more you can take reward of the frameworks that are written to encapsulate the technology. In order to help developers that are developing in MFC and WTL, the corresponding classes from those frameworks will exist explained in the appropriate sections.

This tutorial is the beginning in a serial of five. This one is for beginners, the adjacent iii will cover more advanced topics at the intermediate level, and the final tutorial volition embrace WIN32 paint internals at the avant-garde level.

Device Context

At the simplest level, the device context (DC) is a surface that tin be painted on. However, the DC is as well the operating organization resources that coordinates the brushes, pens and fonts that are used to render the images on the display. Information technology is also the layer of abstraction that the Windows Graphics Device Interface (GDI) uses to abstruse the details of a brandish device from a developer. This means that it is possible to paint to the screen, a printer, or even a bitmap in memory with the same code, initialized with a dissimilar DC that is created for a item purpose. This makes coding very simple compared to the evolution that is required to plan direct to a particular video bill of fare, or printer commuter.

The key to creating solid and efficient graphics in Windows, is to know how to create and utilize the DC that y'all want for a detail purpose. There are many flavors of DCs, hither is a short description of each:

  • Customer DC

    A customer DC is associated with a particular window, and will give the developer access to the customer surface area of the target window. This is the type of DC that is used nearly oft by awarding programmers, and is the easiest to handle. This is the type of DC that should be used when the WM_PAINT message is handled. This is also the only DC that volition be explained with any amount of detail.

  • Window DC

    A window DC is associated with a particular window, and allows the developer to draw on any office of the target window, including the borders and the explanation. This is the type of DC that is sent with WM_NCPAINT message.

  • Memory DC

    A Memory DC is a DC that exists but in retention, and is not associated with any window. This is the only blazon of DC that can hold a user divers bitmap (HBITMAP). Memory DC's are very useful for caching images, and for use with backbuffers on complicated displays.

  • Full general Device DC

    For lack of a better name, this type of DC covers all of the other devices that it is possible to go a DC from. For instance, a printer or a plotter, the unabridged display monitor, or even custom device that a cutting-edge engineering company may invent that does non even exist notwithstanding. The fact is, a DC can be created for any device that supports the required API functions defined past Microsoft.

This guide will but demonstrate the Client DC in order to get the user started with bones Windows graphics evolution. The tutorials later in this series will embrace the other types of DC.

Obtaining a Client Device Context

While working with the WIN32 Paint API, you lot volition always obtain a handle to a device context (HDC). Any of the types of DCs that were described earlier can be stored in a HDC. This guide will merely describe how to obtain a client DC, equally the other DCs are used for more avant-garde purposes.

The frameworks stand for their DCs with a class. The base class for the DC is CDC. A CDC encapsulates the HDC itself. All of the functions that tin be called for a HDC are encapsulated as fellow member functions. There are also a few classes derived from the CDC that will permit special DCs to be created and maintained. The CPaintDC and the CClientDC will be explained later in this section.

BeginPaint

BeginPaint is the most common fashion to create a DC. Withal, this function should only be called in your WM_PAINT message handler of your window. This is considering BeginPaint validates the invalid region of your window. WM_PAINT messages are generated whenever an invalid region is created on your window. If BeginPaint is called exterior of the WM_PAINT handler, whatsoever region that was previously invalid will exist validated, and no WM_PAINT bulletin volition be generated for your window. This could crusade major side-effects in your control, peculiarly if someone else would like to bracket your control in the futurity.

It is only as important to use BeginPaint inside of the WM_PAINT handler equally it is to not use information technology outside of WM_PAINT. This is considering inside of the BeginPaint role call, Windows may generate a WM_ERASEBKGND bulletin and a WM_NCPAINT message if it is necessary. If you do not call BeginPaint within of your WM_PAINT handler, your windows borders may not be updated properly.

In society to get a handle to a DC with BeginPaint, y'all will need a handle to the target window, and a PAINTSTRUCT structure. PAINTSTRUCT holds data nigh the current painting session when you phone call BeginPaint, that is unimportant at this level. BeginPaint besides returns a handle to the DC that it creates, and this is the value that we are interested in. Hither is an example of how to call BeginPaint.

            PAINTSTRUCT ps; HDC            hdc; hdc = ::BeginPaint(hWnd, &ps);

The part that needs to exist used in guild to free a HDC created with BeginPaint is EndPaint. It is important to call EndPaint rather than i of the other DC destroyers, because BeginPaint calls HideCursor in order to prevent the cursor from being painted on during your paint operations, and EndPaint calls ShowCursor to make it visible once more. If EndPaint is non called, afterward a BeginPaint then y'all may feel some weird anomalies with the cursor.

Here is an example of EndPaint:

::EndPaint(hWnd, &ps);

The call to BeginPaint and EndPaint are encapsulated in the class CPaintDC in MFC and WTL. By simply creating an instance of this DC on the stack, the DC will automatically exist created and destroyed for the developer. Here is the code for the constructor and destructor in the MFC version of this class:

CPaintDC::CPaintDC(CWnd* pWnd) {     ...          if          (!Attach(::BeginPaint(m_hWnd = pWnd->m_hWnd, &m_ps)))         AfxThrowResourceException(); }  CPaintDC::~CPaintDC() {     ...      ::EndPaint(m_hWnd, &m_ps);     Detach(); }

GetDC / GetDCEx

GetDC is the next about mutual manner to create a DC. GetDC will obtain a device context to the target windows client area. GetDCEx will do the same thing, withal it will allow you to specify a default clipping region. GetDCEx will be ignored until the adjacent guide.

GetDC has many uses exterior of the WM_PAINT handler. Utilise GetDC when a graphical effect needs to be created, that may non be part of the permanent data of the target window. For instance, use GetDC to create the DC for the prophylactic-banding outcome on drawing tools, and when selecting multiple objects in a window.

Here is an example of how to create and destroy a DC with a call to GetDC.

HDC hdc; hdc = GetDC(hWnd);  ...  ::ReleaseDC(hWnd, hdc);

The telephone call to GetDC and ReleaseDC are encapsulated in the class CClientDC in MFC and WTL. Past simply creating an instance of this DC on the stack, the DC will automatically exist created and destroyed for the developer. Here is the lawmaking for the constructor and destructor in the MFC version of this course:

CClientDC::CClientDC(CWnd* pWnd) {     ...          if          (!Attach(::GetDC(m_hWnd = pWnd->GetSafeHwnd())))         AfxThrowResourceException(); }  CClientDC::~CClientDC() {     ...     ::ReleaseDC(m_hWnd, Detach()); }

Using a Device Context

Using a DC is very unproblematic, and it can be quite complicated, it all depends on what painting issue is to be accomplished. This guide volition only stay with the default pen and brush that are selected in the DC when it is first created. Here is an example of how to phone call a number of different GDI functions with the DC that we have created.

Rectangle(hdc,          100,          100,          200,          300);  Ellipse(hdc,          100,          100,          200,          300);  TCHAR szMessage[] =          "          Paint Beginner"; UINT  nLen = _tcslen(szMessage); TextOut(hdc,          100,          325, szMessage, nLen);        

Here is a short example demonstrating how to employ the CPaintDC:

CPaintDC dc; dc.Rectangle(ten,          x,          150,          200); ...        

Here is a short instance demonstrating how to employ the CClientDC:

CClientDC dc; dc.Rectangle(ten,          10,          150,          200); ...        

Getting Started

The brusk demo plan that is provided will display an array of shapes that has been created by the user. The user tin create a shape by clicking and dragging the mouse, the aforementioned manner that objects are selected in windows explorer. The ii methods for creating a customer DC are demonstrated.

  • BeginPaint: This function is used to paint the shapes that the user has created.
  • GetDC: This function is used to create the rubberbanding effect that allows the user to elevate and create the shapes.

The demo program is very simple in construction. It forsakes coding style and elegance for simplicity and clarity. All of the state that is required for this program is stored in global variables. There is a maximum of 5 shapes that tin be created because they are stored in a statically allocated assortment. If more than five shapes are created, then the oldest existing shape will be replaced with the new shape.

Here is the OnPaint handler that was created to handle the WM_PAINT message:

LRESULT OnPaint       (HWND hWnd) {     PAINTSTRUCT ps;     HDC            hdc;     hdc = ::BeginPaint(hWnd, &ps);      UINT index;          for          (index =          0; alphabetize          <          SHAPE_COUNT; index++)     {          if          (ID_SHAPE_RECTANGLE == Shapes[index].shapeID)         {             ::Rectangle    (                             hdc,                          Shapes[index].rect.left,                          Shapes[index].rect.meridian,                          Shapes[index].rect.right,                         Shapes[index].rect.bottom                         );         }          else          {             ::Ellipse    (                             hdc,                          Shapes[alphabetize].rect.left,                          Shapes[index].rect.superlative,                          Shapes[index].rect.right,                         Shapes[index].rect.lesser                         );         }     }      ::EndPaint(hWnd, &ps);          return          0;     }

Notice the very simple pigment structure encapsulated between the calls to BeginPaint and EndPaint. More calls could exist made between the BeginPaint subclass. The same principle would all the same apply, all painting for the primary window should be done here.

The rubber banding effect is a little bit more complicated. This outcome is created by modifying ii of the state variables in the DC. The first state that is inverse is that the electric current drawing mode is changed from a plain copy to a destination NOT pen, or R2_NOT. This pen volition permit the first drawing example of the pen to change all of the bits from brandish, making a line visible. By simply Drawing the exact same line a 2nd time, the line will disappear.

The second change in DC state, is to select an empty brush color into the DC, and then that when the shape is dragged, it does not paint the center of the shape. These 2 tricks are not the important point that should be noticed from this code. The important point to notice is that the DC was received from a call to GetDC and ended with a call to ReleaseDC. Same as the drawing code, any operations are contained in this DC creation bracket, and the window painting proceeds in between.

Hither is the role that draws the rubberbanding result:

          void          DrawRubberBand(HWND hWnd) {     HDC hdc;                 hdc = ::GetDC(hWnd);                                         ::SetROP2(hdc, R2_NOT);                 ::SelectObject(hdc, ::GetStockObject(NULL_BRUSH));                 HMENU hMenu            = ::GetMenu(hWnd);     HMENU hShapeMenu    = ::GetSubMenu(hMenu,          ane);          if          (::GetMenuState(hShapeMenu, ID_SHAPE_RECTANGLE, MF_BYCOMMAND) & MF_CHECKED)     {         ::Rectangle(                         hdc,                      ptStart.x,                      ptStart.y,                      ptCurrent.x,                     ptCurrent.y                     );     }          else          {         ::Ellipse(                         hdc,                      ptStart.x,                      ptStart.y,                      ptCurrent.x,                     ptCurrent.y                     );     }                 ::ReleaseDC(hWnd, hdc); }

One final point that should exist explained most the demo plan is the call that makes the rubber band work. This lawmaking is within of the WM_MOUSEMOVE message handler. The handler will commencement cheque if rubberbanding is currently activated. If so it volition kickoff draw the current rectangle, finer erasing information technology from the screen, it will update the current coordinates, and then it volition draw the new coordinates effectively updating the position of the rectangle. Hither is the lawmaking:

LRESULT OnMouseMove   (HWND hWnd, UINT nCtrl, UINT ten, UINT y) {                       if          (!isRubberBand)     {          render          0;     }                 DrawRubberBand(hWnd);                 ptCurrent.x = x;     ptCurrent.y = y;                 DrawRubberBand(hWnd);                       return          0;         }

Conclusion

Once again, this guide is to get people started down the path of painting in WIN32. This article was written completely for the WIN32 SDK. I fully believe that MFC and ATL are cleaner ways to develop code for Windows, merely I besides believe that if a developer can go a firm grasp of the bones concepts at the SDK level, they volition be able to flourish equally a framework developer, considering yous volition be able to determine what is happening behind the scenes, especially when problems arise.

The next commodity I mail will exist at an intermediate level with more data. The next article will describe the other means to create DCs. There will likewise be information on the different fields of the PAINTSTRUCT construction. Finally, the update region will be explained with a great amount of detail.

Source: https://www.codeproject.com/Articles/1988/Guide-to-WIN32-Paint-for-Beginners

Posted by: borbarusten.blogspot.com

0 Response to "How To Draw Using Windows Api For C++"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel