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) // Constructorpublic:
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 // Implementationprotected:
~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 IDspublic:
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_FILEstatic 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_MAPEND_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]