Dynamic Bitmap


Dynamic Bitmap

In some applications, it is necessary to draw pixel by pixel a section of a window. Trying to use the function gdi.SetPixel (::SetPixel) is very inefficient and it will result in a very slow program. To improve the performance of these programs a Dynamic Bitmap can be used to draw a set of pixels at a time. In the program of the next problem, first a graphics bitmap is created and the bits are set using the equation z =x +y, the color of each pixel is computed using the value of z. Finally, the graphics bitmap is drawn in the custom control. Note that it is possible to combine any GDI painting function to paint other objects in the control.
En algunas aplicaciones es necesario dibujar pixel por pixel una sección de una ventana. Tratar de usar la función gdi.SetPixel (::SetPixel) es muy ineficiente y resultará en un programa muy lento. Para mejorar el desempeño de estos programas se puede usar un mapa de bits dinámico para dibujar un conjunto de pixeles a la vez. En el programa del próximo problema, primero se crea un mapa de bits y los bits se fijan usando la ecuación z =x +y, el color se obtiene del valor de z. Finalmente, el mapa de bits se dibuja en el control personalizado. Observe que es posible combinar cualquier función de pintado de GDI para pintar otros objetos en el control.

Problem 1
Create a Dialog Application (using Wintempla) called TheZone to draw the equation shown. Once the application has been created add a custom control called Display: Tools > Add Wintempla Item... > Custom Control . Set the name to: Display (Wintempla will create two files: Display.h and Display.cpp)
Cree una aplicación de diálogo (usando Wintempla) llamada TheZone para dibujar la ecuación mostrada. Una vez que el proyecto ha sido creado agregue un control personalizado llamado Display: Tools > Add Wintempla Item... > Custom Control . Fije el nombre a: Display (Wintempla creará dos archivos: Display.h y Display.cpp)

EquationXY

Solution 1A
Open the TheZone.cpp file, and then open Wintempla. From the toolbar selectShow All Controls In ToolboxShow All Controls In Toolbox select the Custom Control tool and draw one Custom Control. Set the name to MyDisplay. In the class tab, set the class to Display.
Abra el archivo TheZone.cpp, entonces abra Wintempla. Desde la barra de herramientas seleccione Show All Controls In ToolboxShow All Controls In Toolbox seleccione la herramienta de Custom Control y dibuje un Custom Control. Fije el nombre en MyDisplay. En la pestaña de class, fije la class a Display.

AddMyDisplay

Solution 1B
Edit the TheZone.h file by including the Display.h file using the command: #include "Display.h". Run the program.
Edite el archivo TheZone.h incluyendo el archivo Display.h usando el comando: #include "Display.h". Ejecute el programa.

TheZone.h
#pragma once //______________________________________ TheZone.h
#include "resource.h"

#include "Display.h"
class TheZone: public Win::Dialog
{
public:
     TheZone()
     {
     }
     ~TheZone()
     {
     }
protected:
     ...
};

TheZoneFirstRun

Solution 1C
Edit the TheZone.cpp file as shown below.
Edite el archivo TheZone.cpp como se muestra debajo.

TheZone.cpp
#include "stdafx.h" //________________________________________ TheZone.cpp
#include "TheZone.h"

int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE , LPTSTR cmdLine, int cmdShow){
     TheZone app;
     return app.BeginDialog(IDI_THEZONE, hInstance);
}

void TheZone::Window_Open(Win::Event& e)
{
     this->customControlMyDisplay.ComputeBits();
     this->customControlMyDisplay.Repaint(NULL, true);
}

Solution 1D
Edit the Display.h file as shown below.
Edite el archivo Display.h como se muestra debajo.

Display.h
// Display.h
#pragma once
#include "resource.h"
#define BITMAP_WIDTH 400
#define BITMAP_HEIGHT 400

class Display: public Win::Window
{
public:
     Display();
     ~Display();
     void ComputeBits();
     bool IsEvent(Win::Event& e, int notification);
private:
     Sys::Graphics graphics;
     const wchar_t * GetClassName(void){return L"DISPLAY";}
     static bool isRegistered;
protected:
     //______ Wintempla GUI manager section begin: DO NOT EDIT AFTER THIS LINE
     void Window_Open(Win::Event& e);
     void Window_Paint(Win::Event& e);
     void Window_Size(Win::Event& e);
};


Solution 1E
Edit the Display.cpp file as shown below.
Edite el archivo Display.cpp como se muestra debajo.

Display.cpp
// Display.cpp
#include "stdafx.h"
#include "Display.h"

bool Display::isRegistered= false;

Display::Display()
{     
     if (!this->isRegistered)
     {

          this->RegisterClassEx(
               LoadCursor(NULL, IDC_ARROW),
               (HBRUSH)(COLOR_BTNFACE+1));
          this->isRegistered = true;
     }
     graphics.Create(BITMAP_WIDTH, BITMAP_HEIGHT);
}

Display::~Display()
{
}

void Display::ComputeBits()
{
     //_______________________________ set x limits
     const double minX = -1.0;
     const double maxX = 1.0;
     const double deltaX = (maxX - minX)/(BITMAP_WIDTH-1.0);
     //_______________________________ set y limits
     const double minY = -1.0;
     const double maxY = 1.0;
     const double deltaY = (maxY - minY)/(BITMAP_HEIGHT-1.0);
     //_______________________________ set z limits
     const double minZ = -2.0;
     const double maxZ = 2.0;
     const double deltaZ = (maxZ - minZ);

     //_____________________________________________ Set the Bitmap bits: z = x + y
     int row, col;
     double x, y, z;
     double normalized_z = 0.0;
     COLORREF color;
     //
     for(row = 0; row < BITMAP_HEIGHT; row++)
     {
          y = maxY - row*deltaY;
          for(col = 0; col< BITMAP_WIDTH; col++)
          {
               x = minX + col*deltaX;
               z = x + y;
               //_____________________ Normalize z from 0.0 to 1.0
               normalized_z = (z-minZ)/deltaZ;
               color = Sys::Convert::DoubleToColorRef(normalized_z, false, 6);
               GRAPHICS_SETPIXEL(graphics, col, row, color);
               //graphics.SetPixel(col, row, color);
          }
     }
     graphics.CreateBitmap();
}

void Display::Window_Open(Win::Event& e)
{
}

void Display::Window_Paint(Win::Event& e)
{
     CG::Gdi gdi(e.hWnd, true, false);
     gdi.DrawGraphics(graphics, 10, 10);

     CG::Font font(L"Arial", 12);
     gdi.Select(font);
     gdi.SetBkMode(true);
     gdi.SetTextColor(RGB(40, 40, 40));
     CG::Pen pen(PS_SOLID, 1, RGB(170, 170, 255));
     gdi.Select(pen);
     //________________________________________ Draw X Axis
     gdi.DrawGraphScaleX(10, BITMAP_HEIGHT+10, BITMAP_WIDTH, -1.0, 1.0, 5, 10, L"x");
     //________________________________________ Draw Y Axis
     const int scaleWidth = gdi.DrawGraphScaleY(10+BITMAP_WIDTH, 10, BITMAP_HEIGHT, -1.0, 1.0, 5, 10, L"y");
     //________________________________________ Color Gradient Scale

     gdi.DrawGraphGradientScale(10+BITMAP_WIDTH+scaleWidth+10, 10, BITMAP_HEIGHT/2, -2.0, 2.0, 6, 5, 6, false);
}

void Display::Window_Size(Win::Event& e)
{
}

bool Display::IsEvent(Win::Event& e, int notification)
{
//     if (e.uMsg == WM_NOTIFY)
//     {
//          NMHDR* pNMHDR= (LPNMHDR)e.lParam;
//          if (pNMHDR->hwndFrom!=this->GetHWND()) return false;
//          if (notification == WIN_ALL_EVENTS)
//          {
//               // Your code here
//               return true;
//          }
//          if (pNMHDR->code!=notification) return false;
//          return true;
//     }
//
     if (e.uMsg!=WM_COMMAND) return false;
     const int id = LOWORD(e.wParam);
     const int notificationd = HIWORD(e.wParam);
     if (id != this->id) return false;
     if (notificationd!=notification) return false;
     return true;
}


TheZoneRun

Problem 2
Create a Dialog Application (using Wintempla) called EasyZone to draw the equation shown.
Cree una aplicación de diálogo (usando Wintempla) llamada EasyZone para dibujar la ecuación mostrada.

EquationXY

Solution 2A
Open the EasyZone.cpp file, and then open Wintempla. From the toolbar selectShow All Controls In ToolboxShow All Controls In Toolbox select the Color MapColor Map tool and draw one ColorMap. Set the name to mapTemperature. This control requires an object that implements the interface Sys::IColorMapDataProvider.
Abra el archivo EasyZone.cpp, entonces abra Wintempla. Desde la barra de herramientas seleccione Show All Controls In ToolboxShow All Controls In Toolbox seleccione la herramienta Color MapColor Map y dibuje un Color Map. Fije el nombre en mapTemperature. Este control requiere un objeto que implementa la interface Sys::IColorMapDataProvider.

Solution 2B
Edit the EasyZone.h and EasyZone.cpp files to implement the interface Sys::IColorMapDataProvider. Do not forget to derive the EasyZone class from Sys::IColorMapDataProvider.
Edite los archivos EasyZone.h y EasyZone.cpp para implementar la interface Sys::IColorMapDataProvider. No se olvide derivar la clase EasyZone de Sys::IColorMapDataProvider.

EasyZone.h
#pragma once //______________________________________ EasyZone.h
#include "Resource.h"
class EasyZone: public Win::Dialog, public Sys::IColorMapDataProvider
{
public:
     EasyZone()
     {
     }
     ~EasyZone()
     {
     }
     //________________________________________________________ Sys::IColorMapDataProvider
     void GetDataRowZ(const int row, const int in_countX, const double* in_x, const double in_y, double* out_z);
protected:
     ...
};


EasyZone.cpp
...
void EasyZone::Window_Open(Win::Event& e)
{
     mapTemperature.MinX = -1.0;
     mapTemperature.MaxX = 1.0;
     //
     mapTemperature.MinY = -1.0;
     mapTemperature.MaxY = 1.0;
     //
     mapTemperature.MinZ = -2.0;
     mapTemperature.MaxZ = 2.0;
     //
     mapTemperature.SetDataProvider(this);
     mapTemperature.PixelsResolutionX = 400;
     mapTemperature.PixelsResolutionY = 500;
     mapTemperature.Refresh();
}

void EasyZone::GetDataRowZ(const int row, const int in_countX, const double* in_x, const double in_y, double* out_z)
{
     for (int i = 0; i < in_countX; i++)
     {
          out_z[i] = in_x[i] + in_y;
     }
}


EasyZoneRun

Problem 3
Create a Dialog Application (using Wintempla) called PolarDrawing to draw the polar equation shown. Once the application has been created add a custom control called Display: Tools > Add Wintempla Item... > Custom Control . Set the name to: Display (Wintempla will create two files: Display.h and Display.cpp)
Cree una aplicación de diálogo (usando Wintempla) llamada PolarDrawing para dibujar la ecuación polar mostrada. Una vez que el proyecto ha sido creado agregue un control personalizado llamado Display : Tools > Add Wintempla Item... > Custom Control . Fije el nombre a: Display (Wintempla creará dos archivos: Display.h y Display.cpp)

PolarEquation

Solution 3A
Open the PolarDrawing.cpp file, and then open Wintempla. From the toolbar selectShow All Controls In ToolboxShow All Controls In Toolbox select the Custom Control tool and draw one Custom Control. Set the name to MyDisplay. In the class tab, set the class to Display.
Abra el archivo PolarDrawing.cpp, entonces abra Wintempla. Desde la barra de herramientas seleccione Show All Controls In ToolboxShow All Controls In Toolbox seleccione la herramienta de Custom Control y dibuje un Custom Control. Fije el nombre en MyDisplay. En la pestaña de class, fije la class a Display.

AddPolarDisplay

Solution 3B
Edit the PolarDrawing.h file by including the Display.h file using the command: #include "Display.h". Run the program.
Edite el archivo PolarDrawing.h incluyendo el archivo Display.h usando el comando: #include "Display.h". Ejecute el programa.

PolarDrawing.h
#pragma once //______________________________________ PolarDrawing.h
#include "resource.h"

#include "Display.h"
class PolarDrawing: public Win::Dialog
{
public:
     PolarDrawing()
     {
     }
     ~PolarDrawing()
     {
     }
protected:
     ...
};

PolarDrawingFirstRun

Solution 3C
Edit the PolarDrawing.cpp file as shown below.
Edite el archivo PolarDrawing.cpp como se muestra debajo.

PolarDrawing.cpp
...

void PolarDrawing::Window_Open(Win::Event& e)
{
     //________________________________________________________ sldK
     sldK.SetRange(1, 25);
     sldK.Position = 1;
     //
     this->customControlMyDisplay.ComputeBits();
     this->customControlMyDisplay.Repaint(NULL, true);
}

void PolarDrawing::sldK_Hscroll(Win::Event& e)
{
     const int position = sldK.HasPositionChanged();
     if (position < 0) return;
     this->customControlMyDisplay.k = (position/20.0);
     this->customControlMyDisplay.ComputeBits();
     this->customControlMyDisplay.Repaint(NULL, true);
}

Solution 3D
Edit the Display.h file as shown below.
Edite el archivo Display.h como se muestra debajo.

Display.h
// Display.h
#pragma once
#include "resource.h"
#define BITMAP_WIDTH 400
#define BITMAP_HEIGHT 400

class Display: public Win::Window
{
public:
     Display();
     ~Display();
     double k;
     void ComputeBits();
     bool IsEvent(Win::Event& e, int notification);
private:
     Sys::Graphics graphics;
     const wchar_t * GetClassName(void){return L"DISPLAY";}
     static bool isRegistered;
protected:
     //______ Wintempla GUI manager section begin: DO NOT EDIT AFTER THIS LINE
     void Window_Open(Win::Event& e);
     void Window_Paint(Win::Event& e);
     void Window_Size(Win::Event& e);
};


Solution 3E
Edit the Display.cpp file as shown below.
Edite el archivo Display.cpp como se muestra debajo.

Display.cpp
// Display.cpp
#include "stdafx.h"
#include "Display.h"

bool Display::isRegistered= false;

Display::Display()
{     
     if (!this->isRegistered)
     {

          this->RegisterClassEx(
               LoadCursor(NULL, IDC_ARROW), // Cursor: IDC_IBEAM, IDC_WAIT, IDC_CROSS, ...
               (HBRUSH)(COLOR_BTNFACE+1)); //Background: (HBRUSH)(COLOR_WINDOW+1)), ::GetStockObject(BLACK_BRUSH)...
          this->isRegistered = true;
     }
     graphics.Create(BITMAP_WIDTH, BITMAP_HEIGHT);
     k = 1.0/20.0;
}

Display::~Display()
{
}

void Display::ComputeBits()
{
     //_______________________________ set x limits
     const double minX = -1.0;
     const double maxX = 1.0;
     const double deltaX = (maxX - minX)/(BITMAP_WIDTH-1.0);
     //_______________________________ set y limits
     const double minY = -1.0;
     const double maxY = 1.0;
     const double deltaY = (maxY - minY)/(BITMAP_HEIGHT-1.0);
     //_______________________________ set z limits
     const double minZ = 0.0;
     const double maxZ = 2.0*M_PI;
     const double deltaZ = (maxZ - minZ);

     //_____________________________________________ Set the Bitmap bits: z = r*theta
     int row, col;
     double x, y, z;
     double normalized_z = 0.0;
     COLORREF color;
     double r, theta;
     //
     for(row = 0; row < BITMAP_HEIGHT; row++)
     {
          y = maxY - row*deltaY;
          for(col = 0; col < BITMAP_WIDTH; col++)
          {
               x = minX + col*deltaX;
               r = sqrt(x*x + y*y);
               theta = atan2(-y, -x) + M_PI; // theta [0 2pi]. To make theta in [-pi pi] use theta = atan2(y, x);
               z = k*r*theta;
               //_____________________ Normalize z from 0.0 to 1.0
               normalized_z = (z-minZ)/deltaZ;
               color = Sys::Convert::DoubleToColorRef(normalized_z, false, 7);
               GRAPHICS_SETPIXEL(graphics, col, row, color);
               //graphics.SetPixel(col, row, color);
          }
     }
     graphics.CreateBitmap();
}

void Display::Window_Open(Win::Event& e)
{
}

void Display::Window_Paint(Win::Event& e)
{
     CG::Gdi gdi(e.hWnd, true, false);
     gdi.DrawGraphics(graphics, 10, 10);
}

void Display::Window_Size(Win::Event& e)
{
}

bool Display::IsEvent(Win::Event& e, int notification)
{
//     if (e.uMsg == WM_NOTIFY)
//     {
//          NMHDR* pNMHDR= (LPNMHDR)e.lParam;
//          if (pNMHDR->hwndFrom!=this->GetHWND()) return false;
//          if (notification == WIN_ALL_EVENTS)
//          {
//               // Your code here
//               return true;
//          }
//          if (pNMHDR->code!=notification) return false;
//          return true;
//     }
//
     if (e.uMsg!=WM_COMMAND) return false;
     const int id = LOWORD(e.wParam);
     const int notificationd = HIWORD(e.wParam);
     if (id != this->id) return false;
     if (notificationd!=notification) return false;
     return true;
}


PolarDrawingRun

Tip
You may eliminate flickering by using Wintempla to check the "Clip Child Windows" property in the main dialog. You may additionally use the Null brush to paint the background of the Display custom control as shown in the code below.
Usted puede eliminar el parpadeo usando Wintempla para la propiedad "Clip Child Windows" en el diálogo principal. Usted puede adicionalmente usar la brocha Nula para pintar la parte de fondo del control personalizado Display como se muestra en el código de abajo.

ClipChildWindows

Display.cpp

Display.cpp
// Display.cpp
#include "stdafx.h"
#include "Display.h"

bool Display::isRegistered= false;

Display::Display()
{     
     if (!this->isRegistered)
     {

          this->RegisterClassEx(
               LoadCursor(NULL, IDC_ARROW),
               (HBRUSH)::GetStockObject(NULL_BRUSH));
          this->isRegistered = true;
     }
     graphics.Create(BITMAP_WIDTH, BITMAP_HEIGHT);
}
...


Problem 4
Create a Dialog Application (using Wintempla) called EasyPolar to draw the equation shown.
Cree una aplicación de diálogo (usando Wintempla) llamada EasyPolar para dibujar la ecuación mostrada.

PolarEquation

Solution 4A
Open the EasyPolar.cpp file, and then open Wintempla. From the toolbar selectShow All Controls In ToolboxShow All Controls In Toolbox select the Color MapColor Map tool and draw one ColorMap. Set the name to mapTemperature. This control requires an object that implements the interface Sys::IColorMapDataProvider.
Abra el archivo EasyPolar.cpp, entonces abra Wintempla. Desde la barra de herramientas seleccione Show All Controls In ToolboxShow All Controls In Toolbox seleccione la herramienta Color MapColor Map y dibuje un Color Map. Fije el nombre en mapTemperature. Este control requiere un objeto que implementa la interface Sys::IColorMapDataProvider.

Solution 4B
Edit the EasyPolar.h and EasyPolar.cpp files to implement the interface Sys::IColorMapDataProvider. Do not forget to derive the EasyPolar class from Sys::IColorMapDataProvider.
Edite los archivos EasyPolar.h y EasyPolar.cpp para implementar la interface Sys::IColorMapDataProvider. No se olvide de deriva la clase EasyPolar de la clase Sys::IColorMapDataProvider.

EasyPolar.h
#pragma once //______________________________________ EasyPolar.h
#include "Resource.h"
class EasyPolar: public Win::Dialog, public Sys::IColorMapDataProvider
{
public:
     EasyPolar()
     {
     }
     ~EasyPolar()
     {
     }
     //_____________________________________________________________________ Sys::IColorMapDataProvider
     void GetDataRowZ(const int row, const int in_countX, const double* in_x, const double in_y, double* out_z);
protected:
     ...
};

EasyPolar.cpp
...
void EasyPolar::Window_Open(Win::Event& e)
{
     mapTemperature.MinX = -1.0;
     mapTemperature.MaxX = 1.0;
     //
     mapTemperature.MinY = -1.0;
     mapTemperature.MaxY = 1.0;
     //
     mapTemperature.MinZ = 0.0;
     mapTemperature.MaxZ = 2.0*M_PI;
     //
     mapTemperature.SetDataProvider(this);
     mapTemperature.PixelsResolutionX = 500;
     mapTemperature.PixelsResolutionY = 500;
     mapTemperature.Refresh();
}

void EasyPolar::GetDataRowZ(const int row, const int in_countX, const double* in_x, const double in_y, double* out_z)
{
     double r, theta;
     for (int i = 0; i < in_countX; i++)
     {
          r = sqrt(in_x[i]*in_x[i] + in_y*in_y);
          theta = atan2(-in_y, -in_x[i]) + M_PI; // theta [0 2pi]. To make theta in [-pi pi] use theta = atan2(y, x);
          out_z[i] = r*theta;
     }
}


EasyPolarRun

© Copyright 2000-2019 Wintempla selo. All Rights Reserved. Sep 05 2019. Home