17 de mayo de 2009

Ampliar la vista de un formulario

Después de activar la casilla correspondiente, la parte del formulario bajo el cursor del mouse, se re dibuja en la ventana principal de foxpro como visto con una lupa.


*-- Aquí el código:
LOCAL oForm
oForm = CREATEOBJECT("Tform")
oForm.SHOW(1)

DEFINE CLASS Tform AS FORM
  WIDTH = 350
  HEIGHT = 160
  BORDERSTYLE = 2
  MAXBUTTON = .F.
  MINBUTTON = .F.
  AUTOCENTER = .T.
  CAPTION = "Ampliar vista"
  hForm = 0
  hDC = 0

  ADD OBJECT chMagnify AS CHECKBOX WITH VALUE=.F.,;
    LEFT=20, TOP=20, AUTOSIZE=.T., CAPTION="Activar"

  ADD OBJECT chInvert AS CHECKBOX WITH VALUE=.F.,;
    LEFT=20, TOP=56, AUTOSIZE=.T., CAPTION="Invertir colores"

  ADD OBJECT lbl1 AS LABEL WITH;
    LEFT=190, TOP=20, AUTOSIZE=.T., CAPTION="Escala:"

  ADD OBJECT cmbScale AS COMBOBOX WITH STYLE=2,;
    LEFT=240, TOP=20, WIDTH=70, HEIGHT=21

  ADD OBJECT cmdClose AS COMMANDBUTTON WITH CANCEL=.T.,;
    LEFT=140, TOP=112, WIDTH=70, HEIGHT=27, CAPTION="Cerrar"

  PROCEDURE INIT
    THIS.DECLARE

  PROCEDURE ACTIVATE
    IF THIS.hForm = 0
      THIS.hForm = GetFocus()
      THIS.hDC = GetDC(THIS.hForm)
    ENDIF

  PROCEDURE DESTROY
    IF THIS.hDC <> 0
      = ReleaseDC(THIS.hForm, THIS.hDC)
    ENDIF

  PROCEDURE cmdClose.CLICK
    THISFORM.RELEASE

  PROCEDURE cmbScale.INIT
    WITH THIS
      .ADDITEM("Normal")
      .ADDITEM("x 2")
      .ADDITEM("x 3")
      .ADDITEM("x 4")
      .LISTINDEX=3
    ENDWITH

  PROCEDURE MOUSEMOVE
    LPARAMETERS nButton, nShift, nXCoord, nYCoord
    THIS.Magnify

  PROCEDURE chMagnify.MOUSEMOVE
    LPARAMETERS nButton, nShift, nXCoord, nYCoord
    THISFORM.Magnify

  PROCEDURE chInvert.MOUSEMOVE
    LPARAMETERS nButton, nShift, nXCoord, nYCoord
    THISFORM.Magnify

  PROCEDURE lbl1.MOUSEMOVE
    LPARAMETERS nButton, nShift, nXCoord, nYCoord
    THISFORM.Magnify

  PROCEDURE cmbScale.MOUSEMOVE
    LPARAMETERS nButton, nShift, nXCoord, nYCoord
    THISFORM.Magnify

  PROCEDURE cmdClose.MOUSEMOVE
    LPARAMETERS nButton, nShift, nXCoord, nYCoord
    THISFORM.Magnify

  PROCEDURE Magnify
    #DEFINE SRCCOPY 0xCC0020
    #DEFINE NOTSRCCOPY 0x00330008
    #DEFINE cnDstWidth 600
    #DEFINE cnDstHeight 300

    IF THIS.chMagnify.VALUE
      LOCAL cBuffer, nX, nY, hDstWin, hDstDC,;
        nMode, nSrcWidth, nSrcHeight, nScale

      hDstWin = GetActiveWindow()
      hDstDC = GetWindowDC(hDstWin)

      cBuffer = REPLICATE(CHR(0), 8)
      = GetCursorPos(@cBuffer)
      = ScreenToClient(THIS.hForm, @cBuffer)

      nX = buf2dword(SUBSTR(cBuffer, 1,4))
      nY = buf2dword(SUBSTR(cBuffer, 5,4))

      nScale = THIS.cmbScale.LISTINDEX
      nSrcWidth = INT(cnDstWidth/nScale)
      nSrcHeight = INT(cnDstHeight/nScale)

      nMode = IIF(THIS.chInvert.VALUE,;
        NOTSRCCOPY, SRCCOPY)

      = StretchBlt(hDstDC, 10, 100,;
        cnDstWidth, cnDstHeight, THIS.hDC,;
        nX-nSrcWidth/2, nY-nSrcHeight/2,;
        nSrcWidth, nSrcHeight, nMode)

      = ReleaseDC(hDstWin, hDstDC)
    ENDIF

  PROCEDURE DECLARE
    DECLARE INTEGER GetActiveWindow IN user32
    DECLARE INTEGER GetCursorPos IN user32 STRING @lpPoint
    DECLARE INTEGER GetWindowDC IN user32 INTEGER HWND
    DECLARE INTEGER GetDC IN user32 INTEGER HWND
    DECLARE INTEGER GetFocus IN user32

    DECLARE INTEGER ReleaseDC IN user32;
      INTEGER hWindow, INTEGER hdc

    DECLARE INTEGER ScreenToClient IN user32;
      INTEGER hWindow, STRING @lpPoint

    DECLARE INTEGER StretchBlt IN gdi32;
      INTEGER hdcDest, INTEGER nXOriginDest,;
      INTEGER nYOriginDest, INTEGER nWidthDest,;
      INTEGER nHeightDest, INTEGER hdcSrc,;
      INTEGER nXOriginSrc, INTEGER nYOriginSrc,;
      INTEGER nWidthSrc, INTEGER nHeightSrc,;
      INTEGER dwRop

ENDDEFINE

FUNCTION buf2dword(lcBuffer)
  RETURN ASC(SUBSTR(lcBuffer, 1,1)) + ;
    BITLSHIFT(ASC(SUBSTR(lcBuffer, 2,1)), 8) +;
    BITLSHIFT(ASC(SUBSTR(lcBuffer, 3,1)), 16) +;
    BITLSHIFT(ASC(SUBSTR(lcBuffer, 4,1)), 24)

Saludos.

Jesus Caro V

2 de mayo de 2009

Como acelerar las consultas en MySQL

Aunque MySQL lleva su propio sistema de optimización cuando lanzamos un "Query SQL", nos es posible mediante programación elegir el índice que utilizará el MySQL en cada una de las tablas para optimizar nuestra consulta.

Como es mejor un ejemplo que mil palabras, vamos a ilustrar un pequeño ejemplo desde nuestro querido Fox.

Creamos en nuestra BBDD de MySQL una pequeña tabla de apuntes contables. Con varios índices (No.Apunte,SubCuenta,Fecha etc).
DROP TABLE IF EXISTS apuntes;

CREATE TABLE apuntes (
  apunte decimal(8,0) default '0.00',
  fecha date default '2009-01-01',
  texto varchar(40) collate utf8_spanish_ci default '',
  cuenta varchar(10) collate utf8_spanish_ci default '0000000000',
  debe decimal(12,2) default '0.00',
  haber decimal(12,2) default '0.00',
  PRIMARY key  (apunte),
  key K01 (fecha),
  key K02 (cscta))
ENGINE = InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci ROW_FORMAT=DYNAMIC ;

Una vez visto el ejemplo de tabla, vamos a crear nuestra consulta en nuestro querido Fox. Y dependiendo de los datos que queramos extraer de la tabla, elegiremos que la consulta sea optimizada por un índice determinado.
*******************************************************************
*  Ejemplo de Consulta Optimizada para MySQL
*******************************************************************

KNDX = 'K01'
DO FORM FCONSULTA    && (FORMULARIO DE CAPTURA DE VARIABLES)
IF T1APTS = T2APTS
  KNDX = 'PRIMARY'
ENDIF

IF T1FECHA = T2FECHA
  KNDX = 'K01'
ENDIF

IF T1CUENTA = T2CUENTA
  KNDX = 'K02'
ENDIF

TEXT TO XSQL TEXTMERGE NOSHOW
  SELECT  *
    FROM  apuntes FORCE INDEX(<<KNDX>>)
    WHERE apunte >= ?T1APTS AND apunte <= ?T2APTS AND
    fecha >= ?T1FECHA AND fecha <= ?T2FECHA AND
    cuenta >= ?T1CUENTA AND cuenta <= ?T2CUENTA
    ORDER BY apunte,fecha 
ENDTEXT

SQLPREPARE(NH, '' + XSQL, 'TCURSOR')

DO WHILE SQLEXEC(NH) = 0
ENDDO

BROWSE

*******************************************************************

Espero que el código anterior sea descriptivo de lo que os quiero transmitir.
En el ejemplo anterior utilizamos la variable KNDX que es la que almacena el índice que queremos utilizar para optimizar nuestra consulta. Por defecto en este ejemplo concreto ponemos el valor del indice fecha 'K01'. Y utilizamos la orden FORCE INDEX para forzar al MySQL que utilice el índice que le indicamos en cada consulta dependiendo de los valores que queramos extraer en cada momento.

En tablas relativamente pequeñas es posible que no se aprecie rendimiento alguno. Pero en consulta a tablas con mas de 2 Millones de registros, como es mi caso. Os aseguro que el rendimiento es exponencial.

Un cordial saludo a la comunidad Fox.

Antonio L. Montagut
www.ontarioxb.es