Вы находитесь на странице: 1из 44

Crear una base de datos con ADO, usando cdigo de

VB (29/Sep/2001)
Para poder crear una base de datos, desde Visual Basic,
usando ADO (ActiveX Data Objects), tenemos que crear en nuestro proyecto una
referencia a: Microsoft ADO Ext. 2.6 for DDL and Security (msadox.dll), y
crear un objeto del tipo Catalog.
Nota: Esta referencia es para la versin 2.6 de ADO, por tanto
puede ser que, si la versin que tienes instalada es otra, en lugar de
2.6 aparezca otra numeracin.
ADOX slo est disponible a partir de la versin 2.1 de ADO.

Veamos, de forma simple, cmo crear una base de datos:


Dim cat As ADOX.Catalog
Set cat = New ADOX.Catalog
'
' Crear la base de datos
cat.Create "Provider=" & sProvider & ";" & _
"Data Source=" & sNombreBase & ";"
En este ejemplo, tenemos que tener asignadas las variables sProvider (el
proveedor) y sNombreBase (el nombre y path de la base de datos).
Para una base de datos del tipo Access 97, sProvider =
"Microsoft.Jet.OLEDB.3.51"
Para una base de datos del tipo Access 2000, sProvider =
"Microsoft.Jet.OLEDB.4.0"
Nota: Si la base de datos ya existe, dar un error.
Para ms informacin: Defining and Retrieving a Databases Schema
(MDAC Technical Articles)

Abrir una base de datos ADO con contrasea (05/Sep/2001)


Para abrir una base de datos ADO con contrasea, podemos hacerlo al crear la
conexin.
He probado varias de las formas que se indican en la ayuda, pero la nica que me
ha funcionado es la que aqu te muestro... as que, si a ti te funciona de otra
forma, pues... eso, que uses la que mejor te parezca... je, je.
Este cdigo es para bases de datos del tipo Access 97, en caso de que quieras usar
una de Access 2000, hay que cambiar el provider
por: Provider=Microsoft.Jet.OLEDB.4.0;

Set Cnn = New ADODB.Connection


Cnn.Open "Provider=Microsoft.Jet.OLEDB.3.51; " & _
"Data Source=" & sBase & ";" & _
"Jet OLEDB:Database Password=laclave"

Crear una tabla en una base de datos usando ADO y


VB (29/Sep/2001)
Hay que crear una referencia a ADOX (ver Cmo crear una base de datos con
ADO).
El cdigo, casi simplificado, sera algo como esto:

Dim cat As ADOX.Catalog


Dim tbl As ADOX.Table
'
Set cat = New ADOX.Catalog
Set tbl = New ADOX.Table
'
' Abrir el catlogo
cat.ActiveConnection = _
"Provider=" & cboProvider.Text & ";" & _
"Data Source=" & txtNombreBase.Text & ";"
'
' Crear la nueva tabla
With tbl
.Name = txtNombreTabla.Text
' Crear los campos y aadirlos a la tabla.
' Esto hay que hacerlo antes de aadir la tabla a la coleccin
de tablas
.Columns.Append "ID", adInteger
' Dependiendo del tipo de proveedor, los datos de cadena sern
de un tipo u otro
If cboProvider.Text = "Microsoft.Jet.OLEDB.3.51" Then
' Para Access 97
.Columns.Append "Nombre", adVarChar, 50
de 50 caracteres

' Una cadena

.Columns.Append "email", adVarChar, 100


.Columns.Append "Telefono", adVarChar
.Columns.Append "Observaciones", adLongVarChar
larga, (Memo)

' Una cadena

Else
' Para Access 2000
.Columns.Append "Nombre", adVarWChar, 50
de 50 caracteres
.Columns.Append "email", adVarWChar, 100
.Columns.Append "Telefono", adVarWChar

' Una cadena

.Columns.Append "Observaciones", adLongVarWChar ' Una cadena


larga, (Memo)
End If
.Columns("Nombre").Attributes = adColNullable
contener nulos

' Permite

.Columns("email").Attributes = adColNullable
.Columns("Telefono").Attributes = adColNullable
.Columns("Observaciones").Attributes = adColNullable
End With
'
' Aadir la nueva tabla a la base de datos
cat.Tables.Append tbl
'
Set tbl = Nothing
Set cat = Nothing
En este ejemplo, tenemos que tener asignadas las variables sProvider (el
proveedor), sNombreBase (el nombre y path de la base de datos)
y sNombreTabla para el nombre de la tabla.
Para una base de datos del tipo Access 97, sProvider =
"Microsoft.Jet.OLEDB.3.51"
Para una base de datos del tipo Access 2000, sProvider =
"Microsoft.Jet.OLEDB.4.0"
Nota:
Los tipos de datos de cadena adVarChar y adLongVarChar son los que
aceptan las tablas para Access 97,
las tablas de Access 2000 se deben usar los del tipo adVarWChar y
adLongWChar.
Nota 2:
Los campos se aaden a la tabla por orden alfabtico,
independientemente del orden en el que se han aadido.
Nota del 27/Dic/02:
Esto slo ocurre si se usa el JET 3.51, con JET 4.0 los crea en el orden
indicado al crearlos.
Gracias Jose Angel Calvo.
Si alguien sabe cmo hacer que no se clasifiquen, (en JET 3.51), por favor que me
lo diga, gracias
Para ms informacin: Defining and Retrieving a Databases Schema (MDAC
Technical Articles)

El cdigo completo y una captura del


formulario en tiempo de diseo, para Crear
una base de datos, crear una tabla y
compactar la base de datos, usando ADO.
El formulario en tiempo de diseo:

El cdigo:

'----------------------------------------------------------------------------' Ejemplo de crear Bases de datos y tablas con ADOX


(28/Sep/01)
'
' Guillermo 'guille' Som, 2001
'
' Las referencias usadas son:
' Microsoft ADO Ext. 2.6 for DDL and Security
' Microsoft Jet and Replication Objects 2.6 Library
'
' Para ms informacin:
' Fuente:

Microsoft Data Access Components (MDAC) SDK

'

MDAC Technical Articles (MSDN Library)

' Artculo: Defining and Retrieving a Databases Schema

' Artculo: Miscellaneous / Compacting a Database


'----------------------------------------------------------------------------Option Explicit
Private Sub cmdCrearBase_Click()
' Crear una base de datos usando los datoos indicados en:
(28/Sep/01)
' txtNombreBase

El nombre (y path) de la base de datos

' cboProvider

El proveedor de la base de datos

'
Dim cat As ADOX.Catalog
'
' Si se produce un error: interceptarlo
On Error GoTo ErrCrearBase
'
Set cat = New ADOX.Catalog
'
' Si existe la base de datos, preguntar si queremos borrarla
If Len(Dir$(txtNombreBase.Text)) Then
If MsgBox("La base de datos ya existe." & vbCrLf & _
"Quieres Borrarla?", _
vbQuestion + vbYesNo + vbDefaultButton2 _
) = vbNo Then
Exit Sub
Else
Kill txtNombreBase.Text
End If
End If
'
' Crear la base de datos
cat.Create "Provider=" & cboProvider.Text & ";" & _
"Data Source=" & txtNombreBase.Text & ";"
'
MsgBox "Base de datos creada satisfactoriamente."
'
' Para no "colarnos" en la rutina de error
Exit Sub
'
ErrCrearBase:

' Mostrar el mensaje de error


MsgBox "Error al crear la base de datos:" & vbCrLf & _
Err.Number & " " & Err.Description, _
vbExclamation, "Error al crear la base de datos"
Err.Clear
End Sub
Private Sub cmdCrearTabla_Click()
' Crear una tabla en la base de datos indicada
(28/Sep/01)
Dim cat As ADOX.Catalog
Dim tbl As ADOX.Table
'
On Error GoTo ErrCrearTabla
'
Set cat = New ADOX.Catalog
Set tbl = New ADOX.Table
'
' Abrir el catlogo
cat.ActiveConnection = _
"Provider=" & cboProvider.Text & ";" & _
"Data Source=" & txtNombreBase.Text & ";"
'
' Crear la nueva tabla
With tbl
.Name = txtNombreTabla.Text
' Crear los campos y aadirlos a la tabla.
' Esto hay que hacerlo antes de aadir la tabla a la
coleccin de tablas
'
.Columns.Append "ID", adInteger
' Dependiendo del tipo de proveedor, los datos de cadena
sern de un tipo u otro
If cboProvider.Text = "Microsoft.Jet.OLEDB.3.51" Then
' Para Access 97
.Columns.Append "Nombre", adVarChar, 50
cadena de 50 caracteres

' Una

.Columns.Append "email", adVarChar, 100


.Columns.Append "Telefono", adVarChar
.Columns.Append "Observaciones", adLongVarChar
cadena larga, (Memo)

' Una

Else
' Para Access 2000
.Columns.Append "Nombre", adVarWChar, 50
cadena de 50 caracteres

' Una

.Columns.Append "email", adVarWChar, 100


.Columns.Append "Telefono", adVarWChar
.Columns.Append "Observaciones", adLongVarWChar ' Una
cadena larga, (Memo)
End If
.Columns("Nombre").Attributes = adColNullable
Permite contener nulos
.Columns("email").Attributes = adColNullable

'

.Columns("Telefono").Attributes = adColNullable
.Columns("Observaciones").Attributes = adColNullable
End With
'
' Aadir la nueva tabla a la base de datos
cat.Tables.Append tbl
'
SalirCrearTabla:
Set tbl = Nothing
Set cat = Nothing
'
Exit Sub
'
ErrCrearTabla:
' Mostrar el mensaje de error
MsgBox "Error al crear la tabla:" & vbCrLf & _
Err.Number & " " & Err.Description, _
vbExclamation, "Error al crear la tabla"
Err.Clear
Resume SalirCrearTabla
End Sub
Private Sub cmdCompactar_Click()
' Compactar una base de datos con ADO
Dim sDBTmp As String
Dim je As JRO.JetEngine
'
On Error GoTo ErrCompactar

'
Set je = New JRO.JetEngine
'
' Crear un nombre "medio" aleatorio
sDBTmp = "DBT_" & Format$(Minute(Now), "00") & Format$
(Second(Now), "00") & ".mdb"
' Asegurarnos de que no existe una base con el nombre temporal
If Len(Dir$(sDBTmp)) Then
Kill sDBTmp
End If
'
lblInfo.Caption = " Compactando la base de datos..."
lblInfo.Refresh
'
' Compactar la base de datos
je.CompactDatabase "Data Source=" & txtNombreBase.Text & ";", _
"Data Source=" & sDBTmp & ";"
'
' Eliminar la base de datos original
Kill txtNombreBase.Text
'
' Renombrar la base temporal con el original
Name sDBTmp As txtNombreBase.Text
'
lblInfo.Caption = " Base de datos compactada."
lblInfo.Refresh
'
Exit Sub
'
ErrCompactar:
' Mostrar el mensaje de error
MsgBox "Error al compactar la base de datos:" & vbCrLf & _
Err.Number & " " & Err.Description, _
vbExclamation, "Error al compactar la base de datos"
Err.Clear
lblInfo.Caption = " *** Error al compactar la base de datos ***"
lblInfo.Refresh
End Sub
Private Sub Form_Load()

With Me.cboProvider
.AddItem "Microsoft.Jet.OLEDB.4.0"

' (Access 2000)

.AddItem "Microsoft.Jet.OLEDB.3.51" ' (Access 97)


.ListIndex = 0
End With
txtNombreBase.Text = "PruebaADO.mdb"
txtNombreTabla.Text = "Tabla1"
lblInfo.Caption = "Guillermo 'guille' Som, 2001" &
IIf(Year(Now) > 2001, "-" & CStr(Year(Now)), "")
End Sub

8.- Seleccionar los registros que queremos en un Recordset


Para asignar a un Data (Recordset) los datos que quieras de una tabla, usa la
propiedad Recordsource.
Data1.RecordSource = "SELECT * FROM Tabla WHERE (condiciones de seleccin)
ORDER BY campo, [campo2]"
Data1.Refresh
El Refresh que no se te olvide, si no quieres que produzca error.
Condiciones de seleccin, sern las comparaciones (consulta) que quieres incluir
para la seleccin.
Por ejemplo, si quieres incluir todos los clientes de Mlaga que tengan coche,
clasificados por la poblacin:
Data1.RecordSource = "SELECT * FROM Clientes WHERE Provincia = 'Mlaga' AND
Coche = 'Si' ORDER BY [Poblacin]"
Fijate que Poblacin est entre corchetes, esto es necesario, porque la (o
acentuada) es un caracter "extrao" y se debe poner entre corchetes para que el
Jet lo entienda. Lo mismo hay que hacer si el nombre del campo incluye espacios.
Otra cosa a tener en cuenta es que si usas =, el contenido del campo "debe
coincidir exactamente", si en Provincia tienes algo como: Mlaga (Andaluca), no lo
"encontrar". Para que lo incluya tambin, cambia el signo igual por LIKE:
Data1.RecordSource = "SELECT * FROM Clientes WHERE Provincia LIKE '*Mlaga*'
AND Coche = 'Si' ORDER BY [Poblacin]"
Ms cosas, en la parte ORDER BY, se pueden incluir ms de un campo, separados
por comas.
El asterisco (*) que hay despus de SELECT, es para que incluya todos los campos
de la tabla.
Si slo quieres incluir algunos campos, especificalos en lugar del asterisco y
separalos con comas:
Data1.RecordSource = "SELECT Nombre,Apellidos, [Poblacin], Provincia, Coche
FROM Clientes WHERE Provincia LIKE 'Mlaga' AND Coche = 'Si' ORDER BY
[Poblacin]"

Tercera Entrega (7/Mar/97)


En la entrega anterior, (si lo s hoy no es el maana al que me refera... pero recuerda
que hubo quin dijo: ...como decamos ayer... y haban pasado 7 u 8 aos... as, que por cinco
das...), te comentaba que no se hacacomprobacin de que la

extensin fuese la adecuada. Vamos a trabajar con bases de Access,


as que la extensin debe ser MDB, por tanto, vamos a aadir las
siguientes lneas a la rutina cmdAceptar_Click() del formulario de
Entrada, y las pones despus del On Local Error... (Ms abajo est el cdigo
completo de cmdAceptar)
If InStr(sUserBase, ".mdb") = 0 Then
MsgBox "Atencin la base especificada no tiene extensin MDB",
vbInformation, cMsg
'Posicionarse en el Text1
Text1.SetFocus
Exit Sub
End If

Ahora ya podemos seguir con la rutina de crear la base.


Private Sub CrearBase(sBase As String)
'Crear la base de datos indicada
'
Dim Db As Database
Dim Fd As Field
Dim Tb As New TableDef
'Definir una Tabla
Dim Idx As New Index
'Para crear un ndice
Dim i As Integer
'Crear base de datos, idioma espaol y para la versin 2.0 del Jet
de Access
'=====================================================================
===========
'Si vas a adaptar este programa para VB3, usa dbVersion11 en lugar
de dbVersion20
'=====================================================================
===========
Set Db = CreateDatabase(sBase, dbLangSpanish, dbVersion20)
'
'La constante dbVersion20 no aparece en la ayuda, en su lugar lo
hace la dbVersion25
'pero sa no est creada!!!
'
'Primero la tabla de las tareas
Set Tb = Db.CreateTableDef("Tareas")
'Vamos a crear cada uno de los campos
Set Fd = Tb.CreateField("ID", dbLong)
'Ahora vamos a asignar las propiedades de contador, etc.
Fd.Attributes = dbAutoIncrField Or dbUpdatableField Or
dbFixedField
Tb.Fields.Append Fd
'El resto de los campos
Set Fd = Tb.CreateField("Fecha", dbDate)

Tb.Fields.Append Fd
Set Fd = Tb.CreateField("Asunto", dbText, 255)
Tb.Fields.Append Fd
Set Fd = Tb.CreateField("Descripcion", dbMemo)
Tb.Fields.Append Fd
Set Fd = Tb.CreateField("FechaInicio", dbDate)
Tb.Fields.Append Fd
Set Fd = Tb.CreateField("FechaTermino", dbDate)
Tb.Fields.Append Fd
Set Fd = Tb.CreateField("Terminada", dbInteger)
Tb.Fields.Append Fd
'Creamos un ndice con el ID
Idx.Name = "PrimaryKey"
Idx.Unique = True
Idx.Primary = True
Idx.Fields = "ID"
Tb.Indexes.Append Idx
'Aadimos la tabla a la base
Db.TableDefs.Append Tb
'
'Creamos la otra tabla: Anotaciones
Set Tb = Db.CreateTableDef("Anotaciones")
'El campo ID, es el contador, etc.
Set Fd = Tb.CreateField("ID", dbLong)
Fd.Attributes = dbAutoIncrField Or dbUpdatableField Or
dbFixedField
Tb.Fields.Append Fd
'El resto de los campos
Set Fd = Tb.CreateField("Fecha", dbDate)
Tb.Fields.Append Fd
Set Fd = Tb.CreateField("Tema", dbText, 50)
Tb.Fields.Append Fd
Set Fd = Tb.CreateField("Asunto", dbText, 255)
Tb.Fields.Append Fd
Set Fd = Tb.CreateField("Medio", dbText, 255)
Tb.Fields.Append Fd
Set Fd = Tb.CreateField("Localizacion", dbText, 255)
Tb.Fields.Append Fd
Set Fd = Tb.CreateField("Descripcion", dbMemo)
Tb.Fields.Append Fd
Set Fd = Tb.CreateField("Detalle", dbLongBinary)
Tb.Fields.Append Fd
'Creamos un ndice con el ID
Set Idx = Nothing
'Quitar la referencia anterior
Idx.Name = "PrimaryKey"
Idx.Unique = True
Idx.Primary = True
Idx.Fields = "ID"
Tb.Indexes.Append Idx
'Aadimos la segunda tabla a la base
Db.TableDefs.Append Tb
'Cerramos la base
Db.Close
MsgBox "Nueva base de datos " & sBase & " creada.", vbInformation
End Sub

Fijate en un detalle "sin importancia?". En la ayuda de VB, cuando


muestra las constantes que podemos usar para la versin de la base
de datos, aparece dbVersion25 y no est definida, en su lugar hay

que usardbVersion20, que si est definida como constante, pero no


aparece en la lista de la ayuda.
Con esto ya est terminado el formulario de Entrada.
Aunque hay que realizar una serie de cambios en el cmdAceptar, aqu
pongo de nuevo el cdigo.
Adems del cambio para comprobar la extensin, he aadido un
nuevo chequeo, por si queremos crear una nueva base de datos a
nuestro nombre. Esto se hace siempre que no sea el mismo nombre
de la base y en el mismo directorio. (Te recomiendo que uses este nuevo cdigo)
Private Sub cmdAceptar_Click()
Dim sPath As String
especificada
Dim sUserPath As String
Dim sUserBase As String
usuario
Const cMsg = "Seleccionar la base"
MsgBox
Dim numBases As Integer
Dim sTmp As String
Dim i As Integer

'path de la base
'path del usuario
'nombre de la base del
'Constante para los
'Nmero de bases
'varios usos
'variable del bucle

'Comprobar si hay datos introducidos


sUsuario = Trim$(Text1)
If Len(sUsuario) = 0 Then
MsgBox "Debes especificar el nombre del usuario.",
vbInformation, cMsg
'Posicionarse en el Text1
Text1.SetFocus
Exit Sub
End If
sTmp = Trim$(Combo1.Text)
If Len(sTmp) = 0 Then
MsgBox "No hay ninguna base de datos seleccionada.",
vbInformation, cMsg
Combo1.SetFocus
Exit Sub
End If
'Separar los datos del path y nombre del archivo
SplitPath sTmp, sPath, sBase
'Comprobar si la base existe en el combo
'
Si no existe, aadirla al combo
i = ActualizarLista(sBase, Combo1)
If i = -1 Then
'Este caso seguramente nunca se dar, pero...
MsgBox "Se ha producido un error inesperado al aadir al
combo", vbCritical, cMsg
Unload Me
End
End If
'Esta base, hay que buscarla en las del usuario especificado
'el formato ser usuarioXX=path_de_la_base
sTmp = sUsuario & Format$(i + 1, "00")

'Comprobar si no se ha especificado el path


sUserPath = sPath
If sPath = "" Then
'para tomar el que hubiese de antes.
sUserPath = Trim$(LeerIni(ficIni, "General", sTmp, sPath))
End If
sUserBase = sUserPath & "\" & sBase
'Por si la ruta es errnea
On Local Error Resume Next
If InStr(sUserBase, ".mdb") = 0 Then
MsgBox "Atencin la base especificada no tiene extensin MDB",
vbInformation, cMsg
'Posicionarse en el Text1
Text1.SetFocus
Exit Sub
End If
'Comprobar si existe "fisicamente" la base
If Len(Dir$(sUserBase)) = 0 Then
'No existe, preguntar si se crea
If MsgBox("La base especificada no existe." & vbCrLf & "'" &
sUserBase & "'" & vbCrLf & "Quieres crearla?", vbQuestion + vbYesNo,
cMsg) = vbYes Then
On Local Error GoTo 0
'Si se produce un error, que
se pare!
'Crear la base
CrearBase sUserBase
Else
Combo1.SetFocus
Exit Sub
End If
End If
If Err Then
MsgBox "Seguramente la ruta especificada, es errnea:" &
vbCrLf & "'" & sUserBase & "'", vbInformation, cMsg
Combo1.SetFocus
Exit Sub
End If
On Local Error GoTo 0
pare!

'Si se produce un error, que se

'Guardar los datos de configuracin


GuardarIni ficIni, "General", sTmp, sUserPath
GuardarIni ficIni, "General", "Usuario", sUsuario
numBases = Combo1.ListCount
GuardarIni ficIni, "General", "NumeroBases", CStr(numBases)
'Guardar los nombres
For i = 1 To numBases
sTmp = "Base" & Format$(i, "00")
sBase = Combo1.List(i - 1)
GuardarIni ficIni, "General", sTmp, sBase
Next
'Asignar el nombre de la base a la variable global
sBase = sUserBase
gsNotas.Show

'Descargar este form


Unload Me
End Sub

Ahora tenemos que empezar con el form principal. Hay que crear una
serie de campos/apartados para manejar o seleccionar la tabla con la
que vamos a trabajar y todo eso.
Yo particularmente no uso el SSTab, (no me gusta el aspecto que tiene),
prefiero el control de Windows95, pero como s que hay algunos por
ah que usan todava el Windows 3.1, me lo pensar...
Eso ser ms adelante, ahora vamos "a complicarnos la vida".
Cmo? Pues creando dos forms uno para las Tareas y otro para las
Anotaciones.
Realmente no es para complicarnos la vida, es para no complicarmela
yo demasiado.
Me explico: El proyecto ir avanzando y teniendo ms cosillas, pero
poco a poco; si tienes que esperar a que est todo acabado... en fin.
Aunque lo estoy "diseando" todo lo "modular" que puedo, para
intentar que cada "mdulo" sea lo ms independiente posible... al final
se podran complicar demasiado las cosas y no quiero que eso ocurra.
Por tanto, slo voy a incluir el cdigo necesario para crear y usar la
tabla de Tareas. El resto del programa, vendr ms adelante y
usaremos las dos tablas en conjunto, a lo mejor hasta DbGrids y
DbList y todas esas cosas que empiezan por DBxxx que tanto os
gustan. (y que yo no uso nunca!)
Vamos al tajo, es decir a currar. (un momento que voy a comprobar cun largo es
este fichero..., vuelvo, ...es aceptable, as que seguiremos un poco ms en este... )
Pensemos que es lo que vamos a necesitar:
Un DataControl, 7 etiquetas y 7 TextBox (una para cada campo de la
tabla) y algn que otro botn, etc.
Dnde los colocamos? Por ahora usaremos el form principal es decir
gsNotas.frm
Vamos a ver el aspecto que tendr y un poco de explicacin de los
controles.

La lnea de
botones
desde Nuevo
a Pegar son
cmdAccion(x)
y los ndices
de 0-Nuevo
hasta 2Borrar
El botn Salir
sigue igual,
pero hay que
incluirlo en el
Picture1, que
tiene la
propiedad
Align Top, sin
bordes, Flat y
con fondo
gris claro.
Las
etiquetas:
Label1(x) y
los ndices
desde el 0Fecha a 5Fecha
Trmino.
Las cajas de
Texto:
Text1(x)
Asunto (2) y
Descripcin
(3) son
Multiline.
Terminado es:
Check1

Ahora hay que aadir lo siguiente, para poder empezar a usar la base
de datos que se supone habremos creado antes de entrar en el "form"
principal.
'--------------------------------------------------------------'Form para la entrada de datos de las Tareas
( 7/Mar/97)
'
'Primera tentativa: 7/Mar/97
'
'cdigo de ejemplo realizado por Guillermo Som
'--------------------------------------------------------------Option Explicit
Dim YaEstoyAqui As Boolean
'Para el Text2
'constantes para los botones de accin
Const CMD_NUEVO = 0
Const CMD_ACTUALIZAR = 1

Const CMD_BORRAR = 2
'Constantes para las acciones de actualizacin, etc del Data
Const EM_NOTHING = 0
Const EM_EDIT = 1
Const EM_ADDNEW = 2
'Constantes para el campo
Const cID = 0
Const cFecha = 1
Const cAsunto = 2
Const cDescripcion = 3
Const cFechaInicio = 4
Const cFechaTermino = 5
Const cTerminada = 6
Private Sub Check1_Click()
'Actualizar el Text asociado
Text1(cTerminada) = Check1.Value
End Sub
Private Sub cmdAccion_Click(Index As Integer)
If Index = CMD_NUEVO Then
'Nuevo registro
YaEstoyAqui = True
Data1.Recordset.AddNew
Data1.Enabled = False
YaEstoyAqui = False
Text1(1).SetFocus
ElseIf Index = CMD_ACTUALIZAR Then
'Guardar el contenido de cada uno de los campos
If Data1.EditMode = EM_ADDNEW Then
Data1.Recordset.Update
Else
Data1.Recordset.Edit
Data1.Recordset.Update
If Data1.EditMode = 0 Then
'
Else
Data1.UpdateControls
End If
End If
Data1.Enabled = True
Data1.Refresh
Data1.Recordset.MoveLast
Text1(1).SetFocus
ElseIf Index = CMD_BORRAR Then
'Borrar registro
If MsgBox("Seguro que quieres borrar este registro?", 4 + 32
+ 256) = 6 Then
Data1.Recordset.Delete
Data1.Refresh
If Not Data1.Recordset.EOF Then
Data1.Recordset.MoveLast
Else
Data1.Caption = "No hay registros"
End If
End If
End If
End Sub

Private Sub cmdSalir_Click()


Unload Me
End
End Sub
Private Sub Data1_Reposition()
Dim sTmp As String
On Local Error Resume Next
If Not Data1.Recordset.EOF Then
'Esta rutina se ejecuta cuando un registro es el
'registro actual, (cada vez que se actualiza)
If Not IsNull(Data1.Recordset!ID) Then _
sTmp = Data1.Recordset!ID
If Not IsNull(Data1.Recordset!Fecha) Then _
sTmp = sTmp & ", " & Data1.Recordset!Fecha
If Not IsNull(Data1.Recordset!Asunto) Then _
sTmp = sTmp & ", " & Data1.Recordset!Asunto
If Len(sTmp) Then
Data1.Caption = sTmp
Else
Data1.Caption = " Registro en blanco."
End If
If Not YaEstoyAqui Then
If Not IsNull(Data1.Recordset!ID) Then
Text2.Text = Data1.Recordset!ID
YaEstoyAqui = True
If Val(Data1.Recordset.Terminada) Then
Check1.Value = 1
Else
Check1.Value = 0
End If
YaEstoyAqui = False
End If
End If

Else

Data1.Caption = "No hay registros."


Text2.Text = Null
End If
Err = 0
On Local Error GoTo 0
End Sub
Private Sub Form_Load()
Show
'Cargar la tabla
CargarTabla
End Sub
Private Sub Form_Unload(Cancel As Integer)
Set gsNotas = Nothing
End Sub

Private Sub Text2_GotFocus()


Text2.SelStart = 0
Text2.SelLength = Len(Text2.Text)
End Sub
Private Sub Text2_KeyPress(KeyAscii As Integer)
Dim TxtID As Long
On Local Error Resume Next
If KeyAscii = 13 Then
KeyAscii = 0
If Not IsNull(Text2.Text) Then
'Buscar ese ID.
If Not YaEstoyAqui Then
'Para poder modificar este campo...
TxtID = Val(Text2.Text)
Data1.Recordset.FindFirst "ID = " & CStr(TxtID)
Text2.Text = Data1.Recordset!ID
End If
End If
End If
End Sub

Con esto ya se pueden empezar a crear registros y todas esas cosas,


en las siguientes entregas veremos ms cosas... el qu? Algo se me
ocurrir... Es que, aunque se recomiende lo contrario, no suelo
"planificar" apriori lo que har, as que tendrs que ir "actualizando" el
archivo ZIP con los listados, porque seguro que en lo que ya he
codificado antes, habrn cambios...
Por ejemplo tendrs que aadir lo siguiente a las declaraciones del
form de Entrada:
Option Compare Text

Porque si no lo haces, al hacer la comparacin de la extensin, si se


escribe distinto de minsculas, no "lo encontrar".
Que los disfrutes.
Esto es todo por ahora.
Maana ms, (bueno... el prximo da ms).

Cuarta Entrega (3/Abr/97)


Bueno, ya estn llegando las sugerencias sobre el rumbo que debe seguir este proyecto, por
ahora van ganando los seguidores de que sea en 32 bits. Pero no te asustes si an ests
programando en 16 bits, incluso si usas VB3, porque todo es compatible hasta el momento.
Si usas VB3/VB2 te recomiendo que veas las recomendaciones para convertir los listados de
VB4-16bits a cdigo usable por VB3 y espero que pronto cambies a un sistema de 32 bits
(incluido el Visual Basic)

Vamos al tajo. Hoy la cosa va de preparar una consulta (query o bsqueda, como prefieras
llamarla).

La bsqueda se realizar en un campo determinado y nos servir para ir mostrando en la


pantalla de edicin los datos que coinciden con los que queremos buscar.

La consulta ya es una tarea ms "trabajada" y nos permite buscar en distintos campos,


sincronizando los datos que queremos comprobar. Por ejemplo, queremos mostrar todos los
datos que estn entre dos fechas y que en el campo Asunto tenga una palabra determinada,
etc.
Por tanto la bsqueda es ms simple. Slo se comprueba un campo y sin ningn tipo de rango.
La consulta puede tener en cuenta un mismo campo con varios valores y/o estar dentro de un
rango. Incluso pondremos opciones que sean "excluyentes" y/o "incluyentes" (no s si se dice
as, pero ahora explico de que van estas "palabrejas")
Es decir que podemos buscar datos en el campo Asunto (por ejemplo), que tengan un valor
determinado y unos datos en el campo Descripcin; (ahora viene lo de "incluyente y
excluyente"), podemos hacer un AND es decir que deben estar los valores en los dos campos o
podemos hacer un OR para que estando cualquiera de los dos valores, nos sirva.

Empecemos entonces por la rutina de bsqueda, para lo cual slo necesitamos


incluir un botn de comandos en nuestra barra de tareas, ms adelante convertiremos estos
CommandButton en una barra de herramientas con grficos y todo eso.
Abre el form gsNotas y aade uno nuevo, para ello, selecciona uno de los que estn y pulsa en
Edicin/Copiar, pulsa en el Picture de la barra de tareas y ahora pegalo (pulsa en
Edicin/Pegar).
Cambiale el caption a Buscar... y aade la siguiente declaracin en las declaraciones del Form:
Const CMD_BUSCAR = 3
Ahora vamos a escribir el cdigo necesario para realizar la bsqueda. Para esta tarea tan
simple necesitamos una forma de pedir el dato que queremos buscar, bien usando el InputBox
del Visual Basic (descartado por su "simpleza") o bien crearnos un dilogo nosotros mismos,
(eso es lo que vamos a hacer). Para crear el dilogo vamos a usar unas rutinas que ya tengo
creadas y un form genrico de dilogo, (s ese), el que ya puse en Utilidades (gsInput), que lo
vuelvo a incluir, (adaptado y modificado en un par de aspectos, con respecto a lo que ya estaba
publicado), para que veas cmo se hacen las cosas. 8-)
Aade al proyecto los siguientes archivos: gsInput.bas y gsInput.frm
En el mdulo bas se incluyen las declaraciones de las variables, constantes, funciones y
procedimientos a usar.
Veamos una imagen del Form y los listados del mdulo y el cdigo del form.

La utilidad gsInput, para crear dilogos al estilo del MsgBox e InputBox, pero con iconos
programables.

'gsInput.Bas
'-------------------------------------------------'Mdulo para funcin de confirmacin
(26/Jul/96)
'
' Guillermo Som Cerezo, 1996-97
'
'Revisado: ( 5/Mar/97)
'Nueva versin: Simulacin de InputBox (22/Mar/97)
'
'Funcin para "simular" una caja de dilogo... ms o menos
'Necesita el form gsInput.frm
'-------------------------------------------------Option Explicit
Global BotonPulsado As Integer
'Constantes para el tipo
Global Const cSi = vbOK
Global Const cSiNo = vbYesNo
Global Const cSiNoCancelar = vbYesNoCancel
Global Const cSiCancelar = vbOKCancel
Global Const cSiATodo = 8
'Constantes para el botn pulsado
Global Const cBotonSi = vbYes
'6
Global Const cBotonNo = vbNo
'7
Global Const cBotonCancelar = vbCancel '2
Global Const cBotonSiATodo = 8
'8
Private Sub PosicionarControles(sEntrada As String, iTipo As Integer,
sCaption As String, Optional vMostrarText)
'---------------------------------------------' Ajusta los controles a mostrar
'---------------------------------------------Dim i As Integer
Dim j As Integer
Dim iQueBoton As Integer
Dim fHeight As Integer
Dim mIzq As Integer
'La posicin ms a la
izquierda
Dim bMostrarText As Boolean
If IsMissing(vMostrarText) Then
bMostrarText = False
Else
bMostrarText = CBool(vMostrarText)
End If

iQueBoton = 0
If iTipo >= 512 Then
iQueBoton = 3
iTipo = iTipo Mod 512
ElseIf iTipo >= 256 Then
iQueBoton = 2
iTipo = iTipo Mod 256
End If
With frmConfirm
If bMostrarText Then
.Text1.Enabled = True
.Text1.Visible = True
Else
.Text1.Enabled = False
.Text1.Visible = False
End If
If iTipo And vbCritical Then
.Image1(0).Picture = .Image1(1).Picture
iTipo = iTipo - vbCritical
ElseIf iTipo And vbQuestion Then
.Image1(0).Picture = .Image1(2).Picture
iTipo = iTipo - vbQuestion
ElseIf iTipo And vbExclamation Then
.Image1(0).Picture = .Image1(3).Picture
iTipo = iTipo - vbExclamation
ElseIf iTipo And vbInformation Then
.Image1(0).Picture = .Image1(4).Picture
iTipo = iTipo - vbInformation
Else
'Exclamacin por defecto
.Image1(0).Picture = .Image1(3).Picture
End If
.Label1(0).Visible = True
.Label1(0) = sEntrada
fHeight = .Label1(0).Top + .Label1(0).Height + 1040
If .Text1.Enabled Then
fHeight = fHeight + 420
End If
If fHeight < 2500 Then
fHeight = 2500
End If
.Height = fHeight
If .Text1.Enabled Then
.Text1.Top = fHeight - 1220
End If
.Command1(0).Top = fHeight - 800
'Usar enabled en lugar de visible, ya que hasta que se haga el
show

'no sern realmente visibles


For i = 1 To 3
.Command1(i).Enabled = False
Next
.Command1(0).Visible = True
'Seleccionar los botones a mostrar
If iTipo = vbYesNo Then
.Command1(2).Enabled = True
ElseIf iTipo = vbYesNoCancel Then
.Command1(2).Enabled = True
.Command1(3).Enabled = True
ElseIf iTipo = 8 Then
.Command1(1).Enabled = True

.Command1(2).Enabled = True
.Command1(3).Enabled = True
ElseIf iTipo = vbOKCancel Then
.Command1(3).Enabled = True
.Command1(0).Caption = "Aceptar"
Else
'Si slo se muestra un botn...
.Command1(0).Caption = "Aceptar"
End If
'Ajustar la localizacin, segn los botones mostrados
mIzq = 0
For i = 3 To 0 Step -1
.Command1(i).Top = .Command1(0).Top
If .Command1(i).Enabled Then
If mIzq = 0 Then
mIzq = .ScaleWidth - 1215
Else
mIzq = mIzq - 1170
End If
.Command1(i).Left = mIzq
.Command1(i).Visible = True
Else
.Command1(i).Visible = False
End If
Next
'Centrar el form
.Move (Screen.Width - .Width) \ 2, (Screen.Height - .Height) \
2

.Caption = sCaption
End With
End Sub
Public Function InputConfirm(sEntrada As String, sTexto As String,
Optional vTipo, Optional vCaption, Optional vPrograma, Optional
vIcono) As Integer
'---------------------------------------------' Muestra la ventana de confirmacin
'---------------------------------------------'Segn el valor de iTipo, se mostrar:
'
Si es > de 256, seleccionar No
'
Si es => de 512, seleccionar Cancelar
'
Aceptar
vbOk
'
Si, No
vbYesNo
'
Si, No, Cancelar
vbYesNoCancel
'
Si, SiATodo, No, Cancelar
8
'Tipo de icono a mostrar:
'
Stop
vbCritical
16
'
Interrogacin
vbQuestion
32
'
Exclamacin
vbExclamation
48
'
Informacin
vbInformation
64
'---------------------------------------------'El valor devuelto ser:
'
Si
vbYes
'
SiATodo
8
'
No
vbNo
'
Cancelar
vbCancel
'---------------------------------------------Dim i As Integer
Dim j As Integer
Dim iTipo As Integer

Dim sCaption As String


Dim sPrograma As String
Dim lIcono As Integer
If IsMissing(vTipo) Then
iTipo = vbOK
Else
iTipo = vTipo
End If
If IsMissing(vCaption) Then
sCaption = ""
Else
sCaption = vCaption
End If
If IsMissing(vPrograma) Then
sPrograma = ""
Else
sPrograma = vPrograma
End If
If IsMissing(vIcono) Then
lIcono = 0&
Else
lIcono = vIcono
End If
If Len(sPrograma) = 0 Then
frmConfirm!Picture1.Visible = False
Else
frmConfirm.ExtraerIcono sPrograma, lIcono
End If
frmConfirm!Text1 = sTexto
PosicionarControles sEntrada, iTipo, sCaption, True
'=====================================================================
=====
'Nota si falla el .Show vbModal usa ste cdigo
'
'Do
'
frmConfirm.Show
'
DoEvents
'Loop Until BotonPulsado
'
frmConfirm.Show vbModal
'=====================================================================
=====
sTexto = frmConfirm.Text1
InputConfirm = BotonPulsado
Unload frmConfirm
DoEvents
End Function
Public Function MsgConfirm(sEntrada As String, Optional vTipo,
Optional vCaption, Optional vPrograma, Optional vIcono) As Integer
'---------------------------------------------' Muestra la ventana de confirmacin
'----------------------------------------------

'Segn el valor de iTipo, se mostrar:


'
Si es > de 256, seleccionar No
'
Si es => de 512, seleccionar Cancelar
'
Aceptar
vbOk
'
Si, No
vbYesNo
'
Si, No, Cancelar
vbYesNoCancel
'
Si, SiATodo, No, Cancelar
8
'Tipo de icono a mostrar:
'
Stop
vbCritical
16
'
Interrogacin
vbQuestion
32
'
Exclamacin
vbExclamation
48
'
Informacin
vbInformation
64
'---------------------------------------------'El valor devuelto ser:
'
Si
vbYes
'
SiATodo
8
'
No
vbNo
'
Cancelar
vbCancel
'---------------------------------------------Dim i As Integer
Dim j As Integer
Dim iTipo As Integer
Dim sCaption As String
Dim sPrograma As String
Dim lIcono As Integer
If IsMissing(vTipo) Then
iTipo = vbOK
Else
iTipo = vTipo
End If
If IsMissing(vCaption) Then
sCaption = ""
Else
sCaption = vCaption
End If
If IsMissing(vPrograma) Then
sPrograma = ""
Else
sPrograma = vPrograma
End If
If IsMissing(vIcono) Then
lIcono = 0&
Else
lIcono = vIcono
End If
If Len(sPrograma) = 0 Then
frmConfirm!Picture1.Visible = False
Else
frmConfirm.ExtraerIcono sPrograma, lIcono
End If
PosicionarControles sEntrada, iTipo, sCaption
'=====================================================================
=====
'Nota si falla el .Show vbModal usa ste cdigo
'
'Do
'
frmConfirm.Show

'
DoEvents
'Loop Until BotonPulsado
'
frmConfirm.Show vbModal
'=====================================================================
=====
MsgConfirm = BotonPulsado
Unload frmConfirm
DoEvents
End Function
El cdigo de gsInput.frm
'-------------------------------------------------' gsInput.frm
(22/Mar/97)
'
' Guillermo Som Cerezo, 1996-97
'
'Basado en gsConfirm
(26/Jul/96)
'Revisado:
( 5/Mar/97)
'Nueva versin: Simulacin de InputBox (22/Mar/97)
'Si se hacen las modificiones mnimas, se puede usar en VB3 (3/Abr/97)
'
'Funcin para "simular" una caja de dilogo... ms o menos
'Necesita el mdulo gsInput.bas
'-------------------------------------------------Option Explicit
'Declaraciones del API
#If Win32 Then
Private Declare Function GetClassWord Lib "user32" _
(ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function ExtractIcon Lib "shell32.dll" Alias
"ExtractIconA" _
(ByVal hInst As Long, ByVal lpszExeFileName As String,
ByVal nIconIndex As Long) As Long
Private Declare Function DrawIcon Lib "user32" _
(ByVal hDC As Long, ByVal X As Long, ByVal Y As Long,
ByVal hIcon As Long) As Long
#Else
Private Declare Function GetClassWord Lib "User" _
(ByVal hWnd As Integer, ByVal nIndex As Integer) As
Integer
Private Declare Function ExtractIcon Lib "shell.dll" _
(ByVal hInst As Integer, ByVal lpszExeFileName As String,
ByVal nIconIndex As Integer) As Integer
Private Declare Function DrawIcon Lib "User" _
(ByVal hDC As Integer, ByVal X As Integer, ByVal Y As
Integer, ByVal hIcon As Integer) As Integer
#End If
Public Sub ExtraerIcono(sPrograma As String, queIcon As Integer)
'Cargar el icono indicado del programa
#If Win32 Then
Dim myhInst As Long
Dim hIcon As Long
Dim i As Long

Const GCW_HMODULE = (-16&)


Dim miIcon As Long
#Else
Dim myhInst As Integer
Dim hIcon As Integer
Dim i As Integer
Const GCW_HMODULE = (-16)
Dim miIcon As Integer
#End If
'necesario para que sea Integer o Long, segn sea 16 o 32 bits
miIcon = queIcon
myhInst = GetClassWord(hWnd, GCW_HMODULE)
hIcon = ExtractIcon(myhInst, sPrograma, miIcon)
If hIcon Then
Picture1.Picture = LoadPicture("")
Picture1.AutoRedraw = -1
i = DrawIcon(Picture1.hDC, 0, 0, hIcon)
Picture1.Refresh
Else
Picture1.Visible = False
End If
End Sub
Private Sub Command1_Click(Index As Integer)
Select Case Index
Case 0
BotonPulsado = vbYes
Case 1
BotonPulsado = cSiATodo '8
Case 2
BotonPulsado = vbNo
Case Else
BotonPulsado = vbCancel
End Select
Hide
End Sub
Private Sub Form_Load()
'
BotonPulsado = 0
End Sub
Private Sub Form_Unload(Cancel As Integer)
'Si se cierra sin pulsar botn, es como si se cancelara
If BotonPulsado = 0 Then
BotonPulsado = vbCancel
End If
Set frmConfirm = Nothing
End Sub
Bueno, esto es con respecto a estas utilidades, para ver la explicacin de cmo usarlo, echale
una visual a la explicacin que en su da puse, o bien sigue el cdigo usado, (no es muy
complicado).

Veamos ahora el cdigo que hay que aadir para realizar la bsqueda.
(He cambiado la estructura IF...THEN por una SELECT...CASE)
Case CMD_BUSCAR
'Buscar registros
'Si no estamos en un Text de bsqueda, salir
If ControlActual = 0 Then Exit Sub
Static sBuscar As String
Dim sTmp As String
Dim i As Integer
If InputConfirm("Escribe el dato a buscar", sBuscar,
vbOKCancel + vbQuestion, _
"Buscar datos") <> vbCancel Then
sBuscar = Trim$(sBuscar)
If Len(sBuscar) Then
YaEstoyAqui = True
Data1.Recordset.FindFirst
Text1(ControlActual).DataField & _
" LIKE '" &
sBuscar & "*'"
If Data1.Recordset.NoMatch Then
Beep
MsgBox "No se ha hallado el dato buscado en el
campo: " & Text1(ControlActual).DataField, vbOK + vbInformation,
"Buscar"
Text1(ControlActual).SetFocus

Else

sTmp = sBuscar
If Left(sTmp, 1) = "*" Then
sTmp = Mid$(sTmp, 2)
End If
'Seleccionar el texto hallado
With Text1(ControlActual)
i = InStr(.Text, sTmp)
.SelStart = i - 1
.SelLength = Len(sTmp)
'posicionarse en ese control
.SetFocus
End With
End If
YaEstoyAqui = False
End If
End If
Bien, es simple no?
Si te das cuenta uso la variable ControlActual para saber el control que est seleccionado. Esta
variable est declarada en el Form, para que sea accesible a todo el Formulario. En el evento
Text1_GotFocus se le asigna el valor del ndice:

Private Sub Text1_GotFocus(Index As Integer)


'Esta variable se asignar cada vez que el control
reciba el foco
ControlActual = Index
End Sub
En este mismo evento del Check1 y el Text2 se asigna a CERO, para que la rutina de
bsqueda no se efecte. Fijate en la comparacin que se hace:

If ControlActual = 0

Then Exit Sub


La variable sBuscar la he declarado STATIC para que conserve el valor, as al pulsar de nuevo

en Busca, se muestra el ltimo valor buscado.


Cuando se encuentra el registro, se resalta la palabra, de esta forma "vemos" rpidamente
dnde est.
Pero tiene un pequeo fallo: Slo encuentra el primer registro y no nos permite seguir
buscando, para mostrar los siguientes en los que se cumpla. Esto se soluciona aadiendo una
opcin BuscarSiguiente, que quedara as:
Case CMD_BuscarSiguiente
If Len(sBuscar) = 0 Then
'Si no se ha buscado anteriormente
cmdAccion_Click CMD_BUSCAR
Else

YaEstoyAqui = True
Data1.Recordset.FindNext Text1(ControlActual).DataField & " LIKE '" & sBuscar &
"*'"
If Data1.Recordset.NoMatch Then
Beep
MsgBox "No se han hallado ms coincidencias del dato buscado en el campo: " &
Text1(ControlActual).DataField, vbOK + vbInformation, "Buscar Siguiente"
Text1(ControlActual).SetFocus
Else
sTmp = sBuscar
If Left(sTmp, 1) = "*" Then
sTmp = Mid$(sTmp, 2)
End If
'Seleccionar el texto hallado
With Text1(ControlActual)
i = InStr(.Text, sTmp)
.SelStart = i - 1
.SelLength = Len(sTmp)
'posicionarse en ese control
.SetFocus
End With
End If

YaEstoyAqui = False
End If

Se declarar la constante CMD_BuscarSiguiente y tendremos que aadir un botn a nuestra


barra, para este menester.
Fijate en la comparacin que se hace del contenido de sBuscar, si est vaca se pregunta por lo
que se debe buscar y si no, se pasa a la accin de buscar el siguiente registro que coincida con
lo buscado.

Nota: Si cambias de campo, buscar el contenido de sBuscar dentro de los registros de ese
campo.

El tema de la bsqueda queda "finalizado". En otra ocasin sustituiremos el form


gsInput por otro ms elaborado y almacenaremos las cadenas buscadas para que se pueda
seleccionar entre las ltimas bsquedas.
Antes de pasar al tema de la Consulta, deberamos hacer un par de arreglos "sofisticados".
Por ejemplo, si no hay datos anteriores que buscar, deshabilitar el botn de Siguiente; (esto
ser para ms adelante)
Si se ha pulsado en Nuevo, no permitir ninguna otra accin excepto la de Guardar.
Para ello hay que hacer estos cambios en el Sub de cmdAccion_Click:
Static esNuevo As Boolean
'...
Case CMD_NUEVO
'Nuevo registro
If Not esNuevo Then
YaEstoyAqui = True
'Quitar la "posible" marca del Check
Check1.Value = 0
Data1.Recordset.AddNew
esNuevo = True
'Deshabilitar los botones, excepto el de guardar
For i = CMD_NUEVO To CMD_BuscarSiguiente

cmdAccion(i).Enabled = False
Next
cmdAccion(CMD_ACTUALIZAR).Enabled = True
Data1.Enabled = False
YaEstoyAqui = False
Text1(1).SetFocus
End If
Case CMD_ACTUALIZAR
'Volver a habilitar los botones y poner la variable a False
For i = CMD_NUEVO To CMD_BuscarSiguiente
cmdAccion(i).Enabled = True
Next
esNuevo = False
'...

Bueno, ya es hora del tema de la consulta... y de acostarse.


Lo siento, no ha sido intencionado, pero se me ha ido la cosa un poco de "varilla" y me he
enrollado ms de la cuenta.
Como aperitivo de lo que hay que hacer, te mostrar el Form en el que se mostrarn los datos,
bastante simple, por cierto, ya que slo tiene un ListBox y dos botones.

Este form se podr redimensionar y permitir editar el registro seleccionado, pero eso ser en
la prxima ocasin (que prometo ser muy pronto, intentar que sea en esta misma noche)

Quinta Entrega (7/Abr/97)


Hoy no voy a abordar todava el tema de las consultas, lo siento. Ese ser el tema de la
prxima entrega.
No es que quiera ponerme "intrigante", pero es que en ese apartado se van a tener que hecer
una serie de "replanteamientos" del programa y habr que aadir algunas estructuras de datos
y eso voy a dejarlo despus de los pequeos cambios que hoy tengo pensado. A estas alturas
sabrs que no tengo este "cursillo" planeado ni planificado, va saliendo poco a poco y como no
soy una persona de ideas fijas, pues me permito "cambiar" de parecer y espero que no sea a
costa de tu aburrimiento.
Ah!, por cierto, en cuanto a la gente que "apuesta" por que sea un proyecto de 16 bits, decirte
que an no hay NI UNA.
Espero que esto siga as, la verdad es que no me hace mucha ilusin tener que hacer el
planteamiento para los 16 bits, no sera bueno, creo. S que an hay gente que "tiene" que
trabajar con Win 3.x, pero ya va siendo hora de que cambien...
De todas formas, si hubiese alguna persona interesada en convertirlo a VB3, me podra tomar
la molestia de hacer una versin "paralela", aunque eso s, con menos "actualizaciones". (el
plazo termina el prximo Mircoles dia 9 de Abril)
Una vez hecha estas aclaraciones, vamos al tema que nos interesa. Hoy tengo pensado estas
cosas:
(Antes de pasar a estos puntos, debemos hacer unos cambios al form gsNotas)
Los cambios a realizar en el form gsNotas, son los siguientes:
---Al Picture1, cambiale el Nombre para que se llame ToolBar
---Aadir un pictureBox y asignarle las siguientes propiedades:
Name = StatusBar (hay que ir preparndose para los 32 bits!)
Height = 270
Align = 2-Align Botton
BorderStile = 0-None
---Aadir un Label dentro del Picture que acabas de insertar y asigna las siguientes
propiedades:
Name = LblStatus
BorderStile = 0-None
Ahora aade el siguiente cdigo:
En las declaraciones, despus del Option Explicit, debers poner esto otro, para que la rutina
de bsqueda "no falle"

Option Compare Text


De esta forma, al comparar cadenas (incluso con el Instr), no se tendrn en cuenta las
maysculas/minsculas.
Estas declaraciones, tambin en la parte general del form, para "recordar" el tamao inicial de
la ventana, despus se usar cuando cambiemos el tamao.

Dim iH As Integer
ventana
Dim iW As Integer
Ahora si, estas son las cosillas para hoy:

1.

Aadir unos mens

2.

Ajustar los controles al redimensionar la ventana

'Tamao mnimo de la

3.

Nuevo Form para Buscar/Reemplazar

4.

Una rutina para Reemplazar datos

5.

Informar en que posicin dentro del TextBox estamos

1.- Aadir unos mens.


Los vamos a necesitar, ya que se aadirn ms opciones de las que en principio van a "coger"
en la barra de herramientas.
Para ello, muestra el form gsNotas. Pulsa en Tools/Menu Editor...
Aade los siguientes "mens"
&Archivo
--&Nuevo
--G&uardar
--&Borrar
-- --&Salir
&Edicin
--C&ortar
--&Copiar
--&Pegar
-- --S&eleccionar Todo
-- --&Buscar...
--Buscar Si&guiente
--&Reemplazar

mnuArc
mnuNuevo
mnuGuardar
mnuBorrar
mnuArcSep1
mnuSalir
mnuEd
mnuCortar
mnuCopiar
mnuPegar
mnuEdSep1
mnuSelecTodo
mnuEdSep2
mnuBuscar
mnuBuscSig
mnuReemplazar

Shortcut
Shortcut
Shortcut

=
=
=

^X
^C
^V

Shortcut

^E

Shortcut
Shortcut
Shortcut

=
=
=

^B
{F3}
^R

Ya tenemos unos cuantos mens creados, ahora vamos a asignarles los comandos a realizar.
El tema de la Edicin (cortar, copiar, etc., lo dejaremos para otra ocasin)
Aade la siguiente declaracin en la parte general del Form:

Const CMD_Reemplazar = 5
Y este es el cdigo para los mens que ahora estan operativos: (fijate que la opcin de
Reemplazar, se efectuar en el interior del procedimiento del cmdAccion, aunque ese botn no
exista, el VB slo procesa la orden que le digamos y no comprueba si el valor Index recibido en
el procedimiento est dentro del rango de botones creados)
Private Sub mnuBorrar_Click()
cmdAccion_Click CMD_BORRAR
End Sub
Private Sub mnuBuscar_Click()
cmdAccion_Click CMD_BUSCAR
End Sub
Private Sub mnuBuscSig_Click()
cmdAccion_Click CMD_BuscarSiguiente
End Sub
Private Sub mnuGuardar_Click()

cmdAccion_Click CMD_ACTUALIZAR
End Sub
Private Sub mnuNuevo_Click()
cmdAccion_Click CMD_NUEVO
End Sub
Private Sub mnuReemplazar_Click()
cmdAccion_Click CMD_Reemplazar
End Sub
Private Sub mnuSalir_Click()
cmdSalir_Click
End Sub

2.- Ajustar los controles al redimensionar la ventana


Para ajustar el tamao de los controles, usaremos el procedimiento Form_Resize. En esta
rutina, se comprueba de que no se haga ningn cambio, si est minimizada y que no se pueda
hacer el form ms pequeo del tamao inicial.
Veamos el cdigo: (el Form_Load tambin se ha modificado)
Private Sub Form_Load()
'El tamao por defecto
iH = Height
iW = Width
'El archivo de configuracin
sFFIni = ficIni
Show
DoEvents
'Cargar la tabla
CargarTabla
End Sub
Private Sub Form_Resize()
Dim i As Integer
'No hacer nada si se minimiza
If WindowState = vbMinimized Then Exit Sub
'No permitir un tamao menor que el inicial
If Width < iW Then
Width = iW
Exit Sub
End If
If Height < iH Then
Height = iH
Exit Sub
End If
Data1.Width = ScaleWidth - 180
Text2.Left = ScaleWidth - Text2.Width - 90
Label1(0).Left = Text2.Left - 450
'Los textBox de Asunto y descripcin
For i = 2 To 3
With Text1(i)
.Width = ScaleWidth - .Left - 90
End With
Next
'Los texts y labels del final
For i = 4 To 5
With Text1(i)
.Top = ScaleHeight - 750
Label1(i).Top = .Top + 30
End With
Next
Check1.Top = Label1(4).Top

'El alto del text de la descripcin


With Text1(3)
.Height = Text1(4).Top - .Top - 75
End With
'Move es ms rpido que efectuar los 3 cambios
LblStatus.Move 60, 30, ScaleWidth - 120
End Sub

3.- Nuevo Form para Buscar/Reemplazar


Para la tarea de Reemplazar, vamos a necesitar otro form, el cual nos va a servir tanto para
pedir los datos a Reemplazar como para la rutina de Buscar, con lo cual no necesitaremos, al
menos por ahora, el mdulo y el form gsInput, as que puedes "quitarlos" del proyecto y aadir
los siguientes:
gsDBR.Frm y gsDBR.Bas

Esta es una "foto" del form gsDBR


El cdigo de estos dos nuevos mdulos es el siguiente:
'---------------------------------------------------'Form genrico para dilogo Buscar/Reemplazar
'
'Guillermo Som Cerezo, 1996-97
'---------------------------------------------------Option Explicit
Const NumeroMaximoDeItems = 100
Dim bBuscandoEnCombo As Boolean
Private Sub cmdCancel_Click()
ActualizarCombo
iFFAccion = cFFAc_Cancelar
Unload Me
End Sub
Private Sub cmdFindNext_Click()
ActualizarCombo
sFFBuscar = txtFind.Text
sFFPoner = ""
iFFAccion = cFFAc_BuscarSiguiente
Unload Me
End Sub
Private Sub cmdReplace_Click()
ActualizarCombo

sFFBuscar = txtFind.Text
sFFPoner = txtReplace.Text
If Len(sFFPoner) = 0 Then
iFFAccion = cFFAc_Buscar
Else
iFFAccion = cFFAc_Reemplazar
End If
Unload Me
End Sub
Private Sub cmdReplaceAll_Click()
ActualizarCombo
sFFBuscar = txtFind.Text
sFFPoner = txtReplace.Text
If Len(sFFPoner) = 0 Then
iFFAccion = cFFAc_Buscar
Else
iFFAccion = cFFAc_ReemplazarTodo
End If
Unload Me
End Sub
Private Sub Combo1_Change(Index As Integer)
If bBuscandoEnCombo Then Exit Sub
If Index = 0 Then
txtFind = Combo1(0).Text
Else
txtReplace = Combo1(1).Text
End If
End Sub
Private Sub Combo1_Click(Index As Integer)
If bBuscandoEnCombo Then Exit Sub
If Combo1(Index).ListIndex Then
Combo1(Index).Text =
Combo1(Index).List(Combo1(Index).ListIndex)
End If
If Index = 0 Then
txtFind = Combo1(Index).Text
Else
txtReplace = Combo1(Index).Text
End If
End Sub
Private
Dim
Dim
Dim
Dim
Dim
Dim

Sub Form_Load()
j As Integer
i As Integer
n As Integer
vTmp As String
sTmp As String
sTag As String

If sFFIni = "" Then

sFFIni = "BuscReemp.ini"
End If
'Posicionar en el centro de la ventana principal
Move (Screen.Width - Width) \ 2, (Screen.Height - Height) \ 2
'asignar los valores anteriores del combo
For i = 0 To 1
sTag = Trim$(Combo1(i).Tag)
n = 0
n = LeerIni(sFFIni, sTag, "NumEntradas", n)
If n > NumeroMaximoDeItems Then n = NumeroMaximoDeItems
'For j = n - 1 To 0 Step -1
For j = 0 To n - 1
vTmp = "Entrada" & CStr(j)
sTmp = LeerIni(sFFIni, sTag, vTmp, "")
If Len(sTmp) Then
Combo1(i).AddItem sTmp
End If
Next
Next
Combo1(0).Text = ""
Combo1(1).Text = ""
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
'Si se cierra por el controlbox, o cualquier forma distinta del
propio cdigo,
'asumir que se ha cancelado.
If UnloadMode <> vbFormCode Then
iFFAccion = cFFAc_Cancelar
End If
End Sub
Private
Dim
Dim
Dim
Dim
Dim
Dim

Sub Form_Unload(Cancel As Integer)


n As Integer
vTmp As String
sTmp As String
i As Integer
j As Integer
sTag As String

If iFFAccion <> cFFAc_Cancelar Then


ActualizarCombo
For i = 0 To 1
n = Combo1(i).ListCount
sTag = Trim$(Combo1(i).Tag)
If n > NumeroMaximoDeItems Then n = NumeroMaximoDeItems
GuardarIni sFFIni, sTag, "NumEntradas", CStr(n)
For j = 0 To n - 1
vTmp = "Entrada" & CStr(j)
sTmp = Combo1(i).List(j)
GuardarIni sFFIni, sTag, vTmp, sTmp
Next
Next
End If
Set gsDBR = Nothing
End Sub
Private Sub ActualizarCombo()

'----------------------------------------------------'Esta rutina actualiza el contenido de los dos combos,


'si la entrada en el Combo.Text no est, la incluye.
'Se podra usar la llamada al API de Windows.
'----------------------------------------------------'Actualizar el contenido del Combo
Dim sTmp As String
'Para ms rapidez...
Static i As Integer
Static j As Integer
Static hallado As Boolean
Static k As Integer
'
bBuscandoEnCombo = True
For k = 0 To 1
hallado = False
sTmp = Combo1(k).Text
If Len(Trim$(sTmp)) Then
j = Combo1(k).ListCount - 1
For i = 0 To j
If StrComp(Trim$(sTmp), Trim$(Combo1(k).List(i))) = 0
Then

hallado = True
Exit For
End If
Next
If Not hallado Then
Combo1(k).AddItem sTmp, 0
End If
End If

Next
bBuscandoEnCombo = False
End Sub

Este es el listado del mdulo con las rutinas de peticin de los datos
'--------------------------------------------------------------'gsDBR.bas Mdulo para el dilogo de Buscar y Reemplazar
'
'(c)Guillermo Som, 1996-97
'--------------------------------------------------------------Option Explicit
'Variables y constantes para buscar/reemplazar
Global sFFBuscar As String
Global sFFPoner As String
Global iFFAccion As Integer
'Constantes para la accin a realizar
Global Const cFFAc_Cancelar = True
Global Const cFFAc_IDLE = 0
Global Const cFFAc_Buscar = 1
Global Const cFFAc_BuscarSiguiente = 2
Global Const cFFAc_Reemplazar = 3
Global Const cFFAc_ReemplazarTodo = 4
Global Const cFFAc_Aceptar = 5
'
Global sFFIni As String

'Archivo de configuracin

Public Function gsReemplazar(sBuscar As String, sPoner As String,


Optional vModo, Optional vCaption) As Integer
'Prepara el dilogo de Reemplazar
Dim iModo As Integer
Dim sCaption As String
If IsMissing(vModo) Then
iModo = cFFAc_Reemplazar
Else
iModo = vModo
End If
If IsMissing(vCaption) Then
sCaption = "Reemplazar"
Else
sCaption = CStr(vCaption)
End If
iFFAccion = cFFAc_IDLE
With gsDBR
.Caption = sCaption
.cmdFindNext.Default = False
.cmdFindNext.Visible = False
.cmdReplaceAll.Default = True
.Combo1(0).Text = sBuscar
.Combo1(1).Text = sPoner
'Mostrar el form y esperar a que se tome una accin
.Show vbModal
'Do
'
.Show
'
DoEvents
'Loop Until iFFAccion
End With
'Devolver la cadena a reemplazar y buscar
sBuscar = sFFBuscar
sPoner = sFFPoner
'Si tanto buscar como poner estn en blanco, devolver cancelar
If Len(Trim$(sBuscar)) = 0 Then
If Len(Trim$(sPoner)) = 0 Then
iFFAccion = cFFAc_Cancelar
End If
End If
'Devolver la accin
gsReemplazar = iFFAccion
End Function
Public Function gsBuscar(sBuscar As String, Optional vModo, Optional
vCaption) As Integer
'Prepara el dilogo para buscar
Dim iModo As Integer
Dim sCaption As String
If IsMissing(vModo) Then
iModo = cFFAc_Buscar
Else
iModo = vModo
End If
'Slo permitir buscar y buscar-siguiente
Select Case iModo
Case cFFAc_Buscar, cFFAc_BuscarSiguiente

'est bien, no hay nada que hacer


Case Else
iModo = cFFAc_Buscar
End Select
If IsMissing(vCaption) Then
sCaption = "Buscar"
Else
sCaption = CStr(vCaption)
End If
iFFAccion = cFFAc_IDLE
With gsDBR
.Caption = sCaption
.cmdReplace.Visible = False
.lblReplace.Visible = False
.cmdReplaceAll.Visible = False
.Combo1(1).Visible = False
.cmdFindNext.Left = .cmdReplaceAll.Left
If iModo = cFFAc_BuscarSiguiente Then
.cmdFindNext.Caption = "Siguiente"
DoEvents
End If
.Combo1(0).Text = sBuscar
'Mostrar el form y esperar a que se tome una accin
.Show vbModal
'Do
'
.Show
'
DoEvents
'Loop Until iFFAccion
End With
'Devolver la cadena seleccionada/introducida
sBuscar = sFFBuscar
'Devolver la accin
gsBuscar = iFFAccion
End Function
Public Sub gsPedirUnValor(spuvTitulo As String, spuvMensaje As String,
spuvPregunta As String, spuvValor As String, spuvBoton As String)
'Rutina de propsito general para pedir un valor (00.22 23/May/96)
With gsDBR
.Caption = spuvTitulo
.Combo1(0).Visible = False
.lblBuscar.Width = .ScaleWidth - 120
.lblBuscar = spuvMensaje
.Combo1(0).Visible = False
.cmdReplace.Visible = False
.cmdFindNext.Default = False
.cmdFindNext.Visible = False
.lblReplace = spuvPregunta
.cmdReplaceAll.Default = True
.cmdReplaceAll.Caption = spuvBoton
If Len(Trim$(spuvValor)) Then
.Combo1(1).Text = spuvValor
Else
If .Combo1(1).ListCount Then
.Combo1(1).ListIndex = 0
End If
End If

.Show vbModal
End With
spuvValor = sFFPoner
End Sub
Ahora la rutina de bsqueda quedara as, (he puesto tambin que si hay texto seleccionado, se
ponga ese para buscar)
Case CMD_BUSCAR
'Buscar registros
'Si no estamos en un Text de bsqueda, salir
If ControlActual = 0 Then Exit Sub
'Si hay texto seleccionado...
With Text1(ControlActual)
If .SelLength > 0 Then
sBuscar = "*" & Trim$(.SelText)
End If
End With
If gsBuscar(sBuscar, , "Buscar datos") > cFFAc_IDLE Then
sBuscar = Trim$(sBuscar)
If Len(sBuscar) Then
YaEstoyAqui = True
Data1.Recordset.FindFirst Text1(ControlActual).DataField & " LIKE '" & sBuscar
& "*'"
If Data1.Recordset.NoMatch Then
Beep
MsgBox "No se ha hallado el dato buscado en el campo: " &
Text1(ControlActual).DataField, vbOK + vbInformation, "Buscar"
Text1(ControlActual).SetFocus
Else
sTmp = sBuscar
If Left(sTmp, 1) = "*" Then
sTmp = Mid$(sTmp, 2)
End If
'Seleccionar el texto hallado
With Text1(ControlActual)
i = InStr(.Text, sTmp)
.SelStart = i - 1
.SelLength = Len(sTmp)
'posicionarse en ese control
.SetFocus
End With
End If
YaEstoyAqui = False
End If
End If

Ahora el tema de Reemplazar, (ya era hora to!)

4.- Una rutina para Reemplazar datos


Debers tener estas declaraciones de variables al principio del procedimiento (no es necesario
que estn al principio, pero queda como ms "mono"):
Dim BusquedaNoHallada As Boolean
Dim j As Integer
Este es el cdigo de la rutina de "Reemplazo"
Case CMD_Reemplazar
'Si no estamos en un Text de bsqueda, salir
If ControlActual = 0 Then Exit Sub
'Si hay texto seleccionado...
With Text1(ControlActual)
If .SelLength > 0 Then
sBuscar = "*" & Trim$(.SelText)

End If
End With
sFFBuscar = sBuscar
sFFPoner = ""
iFFAccion = gsReemplazar(sFFBuscar, sFFPoner)
If iFFAccion <> cFFAc_Cancelar Then
MousePointer = vbHourglass
DoEvents
sBuscar = Trim$(sFFBuscar)
'Quitar de los caracteres de asterscos
Do While InStr(sFFBuscar, "*")
i = InStr(sFFBuscar, "*")
sFFBuscar = Left$(sFFBuscar, i - 1) & Mid$(sFFBuscar, i + 1)
Loop
If Len(sFFBuscar) <> 0 And Len(sFFPoner) <> 0 Then
If iFFAccion = cFFAc_Reemplazar Or iFFAccion = cFFAc_ReemplazarTodo Then
LblStatus = "Buscando " & sBuscar & "..."
DoEvents
YaEstoyAqui = True
Data1.Recordset.FindFirst Text1(ControlActual).DataField & " LIKE '" &
sBuscar & "*'"
If Data1.Recordset.NoMatch Then
Beep
MsgBox "No se ha hallado el dato buscado en el campo: " &
Text1(ControlActual).DataField, vbOK + vbInformation, "Reemplazar"
Text1(ControlActual).SetFocus
BusquedaNoHallada = True
End If
YaEstoyAqui = False
Do Until BusquedaNoHallada
sTmp = Text1(ControlActual).Text
'cambiar... (comprobar si es palabra completa)
If Left$(sBuscar, 1) = "*" Then
i = InStr(sTmp, sFFBuscar)
Else
If Left$(sTmp, Len(sFFBuscar)) = sFFBuscar Then
i = 1
Else
i = 0
End If
End If
If i Then
sTmp = Left$(sTmp, i - 1) & sFFPoner & Mid$(sTmp, i +
Len(sFFBuscar))
Text1(ControlActual).Text = sTmp
End If
If iFFAccion = cFFAc_Reemplazar Then Exit Do
'Cambiar todas las coincidencias en el msmo text
j = 1
Do
If Left$(sBuscar, 1) = "*" Then
i = InStr(j, sTmp, sFFBuscar)
Else
If Left$(sTmp, Len(sFFBuscar)) = sFFBuscar Then
i = 1
Else
i = 0
End If
End If
If i Then
j = i + 1
sTmp = Left$(sTmp, i - 1) & sFFPoner & Mid$(sTmp, i +
Len(sFFBuscar))
Text1(ControlActual).Text = sTmp
End If
Loop While i
DoEvents
YaEstoyAqui = True
Data1.Recordset.FindNext Text1(ControlActual).DataField & " LIKE '" &
sBuscar & "*'"
If Data1.Recordset.NoMatch Then
BusquedaNoHallada = True
Else
BusquedaNoHallada = False
End If
YaEstoyAqui = False
Loop
End If
End If
MousePointer = vbDefault

DoEvents
End If

5.- Informar en que posicin del TextBox estamos.


Esto es para "rematar" el tema por hoy. Ya que tenemos el LblStatus, vamos a darle una
utilidad.
A mi particularmente me gusta saber en que posicin se encuentra el cursor cuando estoy
editando un campo, sobre todo cuantos caracteres me quedan an. ? Suponte que ests en el
campo de Asunto y quieres saber cuantos caracteres puedes utilizar, ya sabes que son 255 el
mximo, as que lo que viene a continuacin, es para indicarnos eso precisamente, la posicin
dentro del Text y cuantos caracteres son en total.
Mejor ver el cdigo, que ya no controlo demasiado...
Private Sub Text1_Click(Index As Integer)
LblStatus = "Pos: " & Text1(Index).SelStart + 1 & "/" &
Text1(Index).MaxLength
End Sub
Private Sub Text1_KeyUp(Index As Integer, KeyCode As Integer, Shift As
Integer)
LblStatus = "Pos: " & Text1(Index).SelStart + 1 & "/" &
Text1(Index).MaxLength
End Sub
Ahora si que hemos terminado. Espero que saques algunas cosillas de provecho de todo lo de
hoy.
Hasta la prxima entrega, esta vez no digo para cuando que despus me dices que no
cumplo mi palabra...