Infografía Resumen 6
FABRICACIÓN
DE CONTROLES ACTIVEX
Los controles ActiveX,
pueden ser implementados por cualquier lenguaje que los soporte, como Visual
C++, Visual Basic, Visual J++, etc. Los controles utilizados en el proyecto han
sido implementados con Visual C++.
Para
implementar un control ActiveX, el proyecto en Visual
C++ consta de tres archivos de código fuente: *App, *PropPag y *Ctrl. El módulo *App
permite realizar tareas de mantenimiento elementales, como inicialización del
control y reposición de variables. *PropPage, por su
parte, suministra una plantilla o modo de cuadro de diálogo que permite a los
usuarios del control ActiveX, personalizar sus
opciones. El último módulo, *Ctrl, contiene lo
sustancial del control ActiveX: código para diseñar
el control, mensajes de envío y recepción en Windows, y otros elementos.
El
módulo Ctrl, es una clase derivada de ColeControl. Esta clase MFC encapsula la función de un
control ActiveX y sirve de protección ante las
interfaces de distribución OLE.
En
el módulo Ctrl, se implementan las propiedades y los
métodos, que una vez compilado el control, pueden ser accesibles desde
cualquier contenedor que use el control.
Propiedades
de un control ActiveX
Además
de los tipos básicos, las propiedades pueden utilizar datos especiales, como
fechas, monedas y colores. ActiveX se encarga de
definir estos tipos, que no pueden ser creados por el usuario.
Existen
tres grandes categorias de propiedades:
·
Propiedades
integradas. Algunas
propiedades, como el color de fondo, la fuente principal y el estado activado,
son tan universales que se requieren incluso en los controles más simples.
Microsoft, las ha incluido directamente en la arquitectura ActiveX.
La propiedades integradas son fáciles de implantar, y
se accede a ellas a través de la clase básica ColeControl.
·
Propiedades
de ambiente. Las de ambiente
no son propiedades propiamente dichas, sino más bien valores que se reciben
directamente de un contenedor de control. En cualquier lugar del código puede
consultarse el valor actual de un contenedor relativo a una propiedad de
ambiente.
·
Propiedades
personalizadas. Las
propiedades integradas resultan cómodas, pero serán insuficientes. Antes o
después se precisará añadir a los procedimientos nuevas propiedades
personalizadas. Estos atributos especiales no son sino propiedades con un
nombre definido por el usuario.
Normalmente,
los controles ActiveX permiten un acceso completo a
sus propiedades. Los contenedores pueden leer directamente estas propiedades y
modificar cualquiera de sus valores; sin embargo, los controles no pueden
intervenir sobre ellas.
Pero
sí están autorizados a crear funciones de notificación especiales que se
invocan siempre que cambia un valor de propiedad. Por ejemplo puede asociarse
una función de notificación a la propiedad fecha de un calendario. Esta función
tendría por defecto volver a presentar el calendario cuando cambiara la fecha.
Aunque
las funciones de notificación pueden recibir cualquier nombre, deberían rotularse con arreglo a una etiqueta ActiveX. La convención de nombres obliga a escribir el
nombre de la propiedad entre las palabras "On"
y "Changed".
Aún
con la posibilidad de incluir funciones de notificación, las propiedades siguen
mostrándose completamente indefensas. El control y su contenedor tienen
completa libertad para manipularlas. La arquitectura ActiveX
ofrece una solución: proteger la propiedad con métodos Get/Set. El método Get muestra el
valor actual de la propiedad, y el método Set lo
cambia por otro nuevo. Esta técnica es útil particularmente cuando ha de
calcularse una propiedad antes de leerla, o si se precisa validarla antes de
escribirla.
Funciones
de intercambio de propiedades
Después de añadir una propiedad con el asistente de
clases, se debe inicializar manualmente. No se deberá fijar su valor dentro del
constructor de clases, como se haría en programas C++ normales. En vez de ello,
se inicializará la propiedad en DoPopExchange(), una función miembro de ColeControl
que el asistente de controles OLE añade automaticamente.
DoPropExchange() tiene un doble propósito. En primer lugar, asigna a cada
propiedad un valor por defecto sea cual sea la ocurrencia del control que se
esté creando. Además, permite que el contenedor serialice
las propiedades. Esta propiedad permite restaurar el estado de un control
incluso después de que se haya interrumpido por avería le funcionamiento del
sistema.
Métodos
Los métodos de los controles ActiveX
son similares a las funciones de miembros C++. Leen parámetros y les asignan un
valor. Dado que los métodos obedecen a un estándar binario, cualquier programa
compatible con ActiveX puede invocarlos sin necesidad
de un código fuente específico.
Sucesos
Aplicar métodos es una solución sencilla para que un
contenedor se comunique con un control ActiveX. Pero,
además, esta conversación también puede establecerse en sentido contrario. Al
enviar un suceso, el control transmitirá información "de retorno" al
contenedor. Los sucesos pueden informar al contenedor de cualquier contingencia
producida: la pulsación de una tecla, la terminación de un proceso largo, un
mensaje de sincronización, etc. Si fuera necesario, los sucesos pueden manejar
información suplementaria en forma de parámetros. Los parámetros de los sucesos
son, en gran medida, comparables a los de los métodos; pueden ser números
enteros, cadenas de caracteres o cualquier otro tipo de datos ActiveX estándar.
Implementación
de los controles del proyecto. EASYGA.OCX Y CONTROLGA.OCX
Los
dos controles implementados, EasyGA.ocx y ControlGA.ocx, ejecutan un algoritmo genético usando las librerias de algoritmos genéticos EO, implementa-das por el
tutor del proyecto Juan Julián Merelo Guervós.
La implementación del control se ha hecho en Visual C++, por dos motivos
básicos, en primer lugar, por que las librerías de algoritmos genéticos con las
que hemos trabajado, se encuentran implementadas en C++, y por tanto su
integración es inmediata, y en segundo lugar, por que Visual C++ es la
herramienta más desarrollada para la implementación de controles ActiveX.
El
control genera aleatoriamente una población de
cromosomas, en un rango fijado por el usuario del control. El control usa un algorimo genético implementado en las librerías EO, para
maximizar una función de evaluación, en este caso la sumatoria de todos los
genes del cromosoma.
Con
el objeto de que el usuario del control sea quién determine los paráme-tros del algoritmo genético, se crean las
propiedades Get/Set
siguientes:
·
Size: indica la longitud del cromosoma
·
Range: indica el intervalo [-rango/2, rango/2], para los valores de cada gen
en el cromosoma
·
PopSize: número de individuos de la población
·
NumGenerations: indica cuántas generaciones se ejecutará el
algoritmo genético.
·
Calculo: es una propiedad booleana
que se utiliza para indicar que las propiedades ya ha sido inicializadas y ya
se puede ejecutar el algoritmo genético.
Se
ha implementado el método GetFitness, que
tiene como parámetros individuo y generación, y te devuelve el fitness que el algoritmo genético ha conseguido para ese
individuo en esa generación.
El
control ControlGA.ocx es similar al control EasyGA.ocx. Las diferencias estriban, en que con ControlGA se puede ejecutar dos funciones de evaluación
distintas, la sumatoria y la suma potencia. Las propiedades de este control ActiveX son las siguientes
Como métodos tiene implementados los
métodos:
·
Sumatoria. Cuando se invoca este método, la función de
evaluación que va ha utilizar el control es la sumatoria de todos los genes del
cromosoma.
·
SumaPotencia. La función de evaluación, es la sumatoria de los
genes, multiplicados por el indice del gen. El
resultado se divide por el número total de genes.
·
GetFitness. Esta función devuelve el fitness
de cada individuo antes de la ejecución del algoritmo genético, y el fitness que se obtiene tras la evaluación de éste.
Como ejemplo de implementación de uu control ActiveX en Visual C++,
se muestran a continuación los ficheros ControlGACtl.h
y ControlGACtl.cpp, que contienen el código esencial
de un control ActiveX.
El fichero ControlGACtl.h
tiene el siguiemte código:
#if
!defined(AFX_CONTROLGACTL_H__0E12C874_2E36_11D3_B0EA_EE4C2C44F238__INCLUDED_)
#define AFX_CONTROLGACTL_H__0E12C874_2E36_11D3_B0EA_EE4C2C44F238__INCLUDED_
#if _MSC_VER = 1000
#pragma once
#endif // _MSC_VER = 1000
// ControlGACtl.h : Declaration of the CControlGACtrl ActiveX Control class.
/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl : See ControlGACtl.cpp for implementation.
class CControlGACtrl : public COleControl
{
DECLARE_DYNCREATE(CControlGACtrl)
// Constructor
public:
CControlGACtrl();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CControlGACtrl)
public:
virtual void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid);
virtual void DoPropExchange(CPropExchange* pPX);
virtual void OnResetState();
//}}AFX_VIRTUAL
// Implementation
protected:
~CControlGACtrl();
DECLARE_OLECREATE_EX(CControlGACtrl) // Class factory and guid
DECLARE_OLETYPELIB(CControlGACtrl) // GetTypeInfo
DECLARE_PROPPAGEIDS(CControlGACtrl) // Property page IDs
DECLARE_OLECTLTYPE(CControlGACtrl) // Type name and misc status
// Message maps
//{{AFX_MSG(CControlGACtrl)
// NOTE - ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
// Dispatch maps
//{{AFX_DISPATCH(CControlGACtrl)
afx_msg short GetSize();
afx_msg void SetSize(short nNewValue);
afx_msg short GetPopSize();
afx_msg void SetPopSize(short nNewValue);
afx_msg short GetRange();
afx_msg void SetRange(short nNewValue);
afx_msg short GetGenerations();
afx_msg void SetGenerations(short nNewValue);
afx_msg void sumatoria();
afx_msg void sumaPotencia();
afx_msg float GetFitness(short generacion, short individuo);
//}}AFX_DISPATCH
DECLARE_DISPATCH_MAP()
afx_msg void AboutBox();
// Event maps
//{{AFX_EVENT(CControlGACtrl)
//}}AFX_EVENT
DECLARE_EVENT_MAP()
// Dispatch and event IDs
public:
short popsize;
short size;
short generations;
short range;
enum {
//{{AFX_DISP_ID(CControlGACtrl)
dispidSize = 1L,
dispidPopSzie = 2L,
dispidRange = 3L,
dispidGenerations = 4L,
dispidFitness = 7L,
dispidSumatoria = 5L,
dispidSumaPotencia = 6L,
//}}AFX_DISP_ID
};
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_CONTROLGACTL_H__0E12C874_2E36_11D3_B0EA_EE4C2C44F238__INCLUDED)
El código del fichero ControlGACtl.cpp es el
siguiente:
// ControlGACtl.cpp : Implementation of the CControlGACtrl ActiveX Control class.
#include "stdafx.h"
#include "ControlGA.h"
#include "ControlGACtl.h"
#include "ControlGAPpg.h"
#include
#include
#include
#include
#include
#include
using namespace std;
#include <stdlib.h
#include <stdio.h
#include <time.h
#include <generic/EOVector.h
#include <generic/EOGOps.h
#include <generic/EOEvalAll.h
#include <generic/EOselect/EOSteadyState.h
#include <specific/EOSIntOps.h
#include <generic/EOGenTerm.h
#include <generic/EOselect/EOReplacers.h
#include <generic/EOEasyGA.h
#include <ADT/EOAlgo.h
#include <ADT/EOFitness.h
#include <ADT/EOSelector.h
#include <ADT/EOTerm.h
#include <ADT/EOEvalFunc.h
#include "evaluacion.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
float fitness_inicial[200];
float fitness_final[200];
IMPLEMENT_DYNCREATE(CControlGACtrl, COleControl)
/////////////////////////////////////////////////////////////////////////////
// Message map
BEGIN_MESSAGE_MAP(CControlGACtrl, COleControl)
//{{AFX_MSG_MAP(CControlGACtrl)
// NOTE - ClassWizard will add and remove message map entries
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG_MAP
ON_OLEVERB(AFX_IDS_VERB_EDIT, OnEdit)
ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// Dispatch map
BEGIN_DISPATCH_MAP(CControlGACtrl, COleControl)
//{{AFX_DISPATCH_MAP(CControlGACtrl)
DISP_PROPERTY_EX(CControlGACtrl, "size", GetSize, SetSize, VT_I2)
DISP_PROPERTY_EX(CControlGACtrl, "popSzie", GetPopSize, SetPopSize, VT_I2)
DISP_PROPERTY_EX(CControlGACtrl, "range", GetRange, SetRange, VT_I2)
DISP_PROPERTY_EX(CControlGACtrl, "generations", GetGenerations, SetGenerations, VT_I2)
DISP_FUNCTION(CControlGACtrl, "sumatoria", sumatoria, VT_EMPTY, VTS_NONE)
DISP_FUNCTION(CControlGACtrl, "sumaPotencia", sumaPotencia, VT_EMPTY, VTS_NONE)
DISP_PROPERTY_PARAM(CControlGACtrl, "fitness", GetFitness, SetNotSupported, VT_R4, VTS_I2 VTS_I2)
//}}AFX_DISPATCH_MAP
DISP_FUNCTION_ID(CControlGACtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
END_DISPATCH_MAP()
/////////////////////////////////////////////////////////////////////////////
// Event map
BEGIN_EVENT_MAP(CControlGACtrl, COleControl)
//{{AFX_EVENT_MAP(CControlGACtrl)
// NOTE - ClassWizard will add and remove event map entries
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_EVENT_MAP
END_EVENT_MAP()
/////////////////////////////////////////////////////////////////////////////
// Property pages
// TODO: Add more property pages as needed. Remember to increase the count!
BEGIN_PROPPAGEIDS(CControlGACtrl, 1)
PROPPAGEID(CControlGAPropPage::guid)
END_PROPPAGEIDS(CControlGACtrl)
/////////////////////////////////////////////////////////////////////////////
// Initialize class factory and guid
IMPLEMENT_OLECREATE_EX(CControlGACtrl, "CONTROLGA.ControlGACtrl.1",
0xe12c866, 0x2e36, 0x11d3, 0xb0, 0xea, 0xee, 0x4c, 0x2c, 0x44, 0xf2, 0x38)
/////////////////////////////////////////////////////////////////////////////
// Type library ID and version
IMPLEMENT_OLETYPELIB(CControlGACtrl, _tlid, _wVerMajor, _wVerMinor)
/////////////////////////////////////////////////////////////////////////////
// Interface IDs
const IID BASED_CODE IID_DControlGA =
{ 0xe12c864, 0x2e36, 0x11d3, { 0xb0, 0xea, 0xee, 0x4c, 0x2c, 0x44, 0xf2, 0x38 } };
const IID BASED_CODE IID_DControlGAEvents =
{ 0xe12c865, 0x2e36, 0x11d3, { 0xb0, 0xea, 0xee, 0x4c, 0x2c, 0x44, 0xf2, 0x38 } };
/////////////////////////////////////////////////////////////////////////////
// Control type information
static const DWORD BASED_CODE _dwControlGAOleMisc =
OLEMISC_INVISIBLEATRUNTIME |
OLEMISC_ACTIVATEWHENVISIBLE |
OLEMISC_SETCLIENTSITEFIRST |
OLEMISC_INSIDEOUT |
OLEMISC_CANTLINKINSIDE |
OLEMISC_RECOMPOSEONRESIZE;
IMPLEMENT_OLECTLTYPE(CControlGACtrl, IDS_CONTROLGA, _dwControlGAOleMisc)
/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl::CControlGACtrlFactory::UpdateRegistry -
// Adds or removes system registry entries for CControlGACtrl
BOOL CControlGACtrl::CControlGACtrlFactory::UpdateRegistry(BOOL bRegister)
{
// TODO: Verify that your control follows apartment-model threading rules.
// Refer to MFC TechNote 64 for more information.
// If your control does not conform to the apartment-model rules, then
// you must modify the code below, changing the 6th parameter from
// afxRegInsertable | afxRegApartmentThreading to afxRegInsertable.
if (bRegister)
return AfxOleRegisterControlClass(
AfxGetInstanceHandle(),
m_clsid,
m_lpszProgID,
IDS_CONTROLGA,
IDB_CONTROLGA,
afxRegInsertable | afxRegApartmentThreading,
_dwControlGAOleMisc,
_tlid,
_wVerMajor,
_wVerMinor);
else
return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}
/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl::CControlGACtrl - Constructor
CControlGACtrl::CControlGACtrl()
{
InitializeIIDs(&IID_DControlGA, &IID_DControlGAEvents);
// TODO: Initialize your control's instance data here.
}
/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl::~CControlGACtrl - Destructor
CControlGACtrl::~CControlGACtrl()
{
// TODO: Cleanup your control's instance data here.
}
/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl::OnDraw - Drawing function
void CControlGACtrl::OnDraw(
CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
// TODO: Replace the following code with your own drawing code.
pdc-FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
pdc-Ellipse(rcBounds);
}
/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl::DoPropExchange - Persistence support
void CControlGACtrl::DoPropExchange(CPropExchange* pPX)
{
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
COleControl::DoPropExchange(pPX);
// TODO: Call PX_ functions for each persistent custom property.
}
/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl::OnResetState - Reset control to default state
void CControlGACtrl::OnResetState()
{
COleControl::OnResetState(); // Resets defaults found in DoPropExchange
SetGenerations(10);
SetPopSize(100);
SetRange(100);
SetSize(10);
}
/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl::AboutBox - Display an "About" box to the user
void CControlGACtrl::AboutBox()
{
CDialog dlgAbout(IDD_ABOUTBOX_CONTROLGA);
dlgAbout.DoModal();
}
/////////////////////////////////////////////////////////////////////////////
// CControlGACtrl message handlers
short CControlGACtrl::GetSize()
{
return size;
}
void CControlGACtrl::SetSize(short nNewValue)
{
size = nNewValue;
SetModifiedFlag();
}
short CControlGACtrl::GetPopSize()
{
return popsize;
}
void CControlGACtrl::SetPopSize(short nNewValue)
{
popsize = nNewValue;
SetModifiedFlag();
}
short CControlGACtrl::GetRange()
{
return range;
}
void CControlGACtrl::SetRange(short nNewValue)
{
range = nNewValue;
SetModifiedFlag();
}
short CControlGACtrl::GetGenerations()
{
return generations;
}
void CControlGACtrl::SetGenerations(short nNewValue)
{
generations = nNewValue;
SetModifiedFlag();
}
float CControlGACtrl::GetFitness(short generacion, short individuo)
{
if (generacion == 1)
{
return fitness_inicial[individuo-1];
}
else
return fitness_final[individuo-1];
}
void CControlGACtrl::sumatoria()
{
unsigned size = GetSize();
unsigned popSize = GetPopSize();
unsigned range = GetRange();
unsigned numGenerations = GetGenerations();
unsigned i, j;
srand( (unsigned)time( NULL ) );
typedef EOVector<int,int eoInt;
typedef eoInt* ptEoInt;
EOPop initPop;
for ( j = 0; j < popSize; j ++ )
{
ptEoInt EOIA = new eoInt;
for ( i = 0; i < size; i ++ )
{
EOIA-push_back( rand() % range - range/2 );
}
initPop.push_back( *EOIA );
delete EOIA;
}
Sumatoria thisEvalFunc;
EvalAll thisEval( thisEvalFunc );
// Go ahead to next generation
float select = (float)0.3;
EOSteadyState coach( select );
// Eliminate the worst
unsigned subPop = (unsigned) floor( select*popSize );
EOElimWorst popKiller( subPop );
// And now breed
EORank chaperon( subPop );
//Add operators
EOXOver2 xOver( 1 );
chaperon.addOp( &xOver );
//More operators
EODup dupper( 1 );
chaperon.addOp( &dupper );
//More operators
EOKill killer( 1 );
chaperon.addOp( &killer );
EOIntArrayMutate mutator( 1 );
chaperon.addOp( &mutator);
EOGenTerm ngenerations( numGenerations );
EOEasyGA
thisAlgorithm( thisEval, coach, chaperon, ngenerations, popKiller, true);
thisEval( initPop );
for (i=0;i<popSize;i++)
fitness_inicial[i] = initPop[i].fitness();
thisAlgorithm( initPop );
for (i=0;i<popSize;i++)
fitness_final[i] = initPop[i].fitness();
}
void CControlGACtrl::sumaPotencia()
{
unsigned size = GetSize();
unsigned popSize = GetPopSize();
unsigned range = GetRange();
unsigned numGenerations = GetGenerations();
unsigned i, j;
// start the algorithm
srand( (unsigned)time( NULL ) );
// useful typedefs
typedef EOVector<int,int eoInt;
typedef eoInt* ptEoInt;
EOPop initPop;
for ( j = 0; j < popSize; j ++ )
{
ptEoInt EOIA = new eoInt;
for ( i = 0; i < size; i ++ )
{
EOIA-push_back( rand() % range - range/2 );
}
initPop.push_back( *EOIA );
delete EOIA;
}
SumaPotencia thisEvalFunc;
EvalAll thisEval( thisEvalFunc );
// Go ahead to next generation
float select = (float)0.3;
EOSteadyState coach( select );
// Eliminate the worst
unsigned subPop = (unsigned) floor( select*popSize );
EOElimWorst popKiller( subPop );
// And now breed
EORank chaperon( subPop );
//Add operators
EOXOver2 xOver( 1 );
chaperon.addOp( &xOver );
//More operators
EODup dupper( 1 );
chaperon.addOp( &dupper );
//More operators
EOKill killer( 1 );
chaperon.addOp( &killer );
//Add mutation
EOIntArrayMutate mutator( 1 );
chaperon.addOp( &mutator);
//Termination condition
EOGenTerm ngenerations( numGenerations );
//And now the population itself
EOEasyGA
thisAlgorithm( thisEval, coach, chaperon, ngenerations, popKiller, true);
// Evaluate the initial population
thisEval( initPop );
for (i=0;i<popSize;i++)
{
fitness_inicial[i] = initPop[i].fitness();
}
// Apply the genetic algorithm, and generate evolvedPop
thisAlgorithm( initPop );
for (i=0;i<popSize;i++)
{
fitness_final[i] = initPop[i].fitness();
}
}
[Portada] [Resumen] [Infografia]