Anda di halaman 1dari 14

las preguntas ms frecuentes en los foros visual basic relacionadas a la dbgrid estndar generalmente se orientan a su configuracin y personalizacin.

en verdad dbgrid resulta un poco hostil a la hora de hacer lo que uno quiera, y a todos nos ha complicado alguna una vez. advierto que la intensin de este articulo no es ensear a manejar el control dbgrid, pues es hace parte de la documentacin de visual basic. la siguiente coleccin de trucos sirven en gran medida para que la dbgrid que suministra visual basic, tenga un aspecto ms profesional, al estilo de los formularios especializados de access : ttulos en negrilla y centrados !, registro " de # y formato personalizado. ". titulos en negrilla y centrados primero que todo, dbgrid no alinea celdas individuales, solo por columnas. es necesario ingeniarcelas para lograr hacer esto. mi truco se basa en adicionar espacios al lado izquierdo del te$to de la celda, claro que el asunto no es tan simple como una sencilla formula, dado que la presentacin sugiere fuentes escalables. el algoritmo se basa en una apro$imacin de ensayo y error y es bastante preciso: public sub centerheadcolumn%f as form, targetcolumn as column& dim te$t'idth, m as single, hole as string 'ith targetcolumn te$t'idth ( f.te$t'idth%.caption& if targetcolumn.'idth ) te$t'idth then m ( %.'idth * te$t'idth& + , do hole ( hole - sp loop until f.te$t'idth%hole& )( m if .alignment ( dbgleft then .caption ( hole - .caption .allo'sizing ( false elseif .alignment ( dbgright then .caption ( .caption - space%len%hole& * "& .allo'sizing ( false end if end if end 'ith end sub ntese el parmetro f como form, esto es requerido para aplicar la funcin te$t'idth, as, esto sugiere que la fuente del formulario que contiene la dbgrid y la fuente del encabezado de la dbgrid sean las mismas. las siguientes lneas %ejemplo& resuelven esto y fijan la fuente del encabezado de la dbgrid: sub dbgridheading%& dim f as ne' stdfont

dim i as integer 'ith f .name ( .ms sans serif. .size ( / .bold ( true end 'ith set me.font ( f set midbgrid.headfont ( f 'ith midbgrid for i ( 0 to .columns.count * " centerheadcolumn me, .columns%i& ne$t end 'ith end sub

,. registro tal de cuantos he visto pocos programas vb con la caracterstica registo tal de tantos, mientras que en access es un estndar. esto no es muy complicado de programar, aunque hacerlo bien %eficiente& es otra cosa. el truco es el siguiente: option e$plicit ... private countrecords as variant ... private sub midata1reposition%& if isempty%countrecords& then countrecords ( recordscountdc%midata& end if 'ith midata if .recordset.recordcount then .caption ( .alg2n te$to. registro : . 3 1 %.recordset.absoluteposition - "& 3 1 . de . 3 countrecords else .caption ( .no hay entrada de registros. end if end 'ith end sub lo que queramos 4cierto5, "006 eficiente. le damos soporte simplemente con la variable cuenta1midata: private sub midata1validate%action as integer, save as integer& select case action

case vbdataactionaddne' countrecords ( countrecords - " case vbdataactiondelete countrecords ( countrecords * " ... end select ... end sub para contabilizar el numero de registros yo he usado la siguiente funcin desde un modulo estndar: function recordscountdc%dc as data& as long dim cn as recordset, n as long if dc.recordset.recordcount then set cn ( dc.recordset.clone cn.movelast n ( cn.recordcount else n(0 end if recordscountdc ( n end function despu7s de cualquier midata.refresh, agregue la lnea countrecords ( recordscountdc%midata&, pero esto aplica solo para un formulario tipo form*subform %relaciones de uno a varios&, y en ambientes multiusuario, donde solo sabremos el numero de registros hasta dar un refresh.

8. formato personalizado esta es fcil, pero apuesto que pocos la saban. referente al siguiente bloque de cdogo, en su orden, despu7s del 'ith, %"& cambio la titulo de la columna, %,& cambio el ancho de la columna, %8& doy un formato num7rico %tipo ,,000.0&, %9& no quiero que se tecleen caracteres en la celda %esto es muy importante cuando es un query de tablas relacionadas y se usa la columna solo para gua&. 'ith midbgrid.columns%i& .caption ( .distribuidores minoristas. .'idth ( me.te$t'idth%string%,9, .s.&& .numberformat ( .::,::0.0. .loc;ed ( true end 'ith donde i es el ndice de la columna que se quiere personalizar %recuerde que las columnas

se enumeran empezando desde 0 hasta columns.count * "&.9. una lista desplegable en una celda confieso que el truco no me lo ingenie, ottmar figuero de nicaragua me puso en camino de un articulo de ape$ < %versin reciente& que orientaba como hacerlo. sin embargo, no me limite a fusilar el articulo, aqu le cuento como crear varias listas en diferentes celdas y todo en base a cdigo %el articulo lo hace en modo de tutor en tiempo de diseo&. tambien entrego una perspectiva para una programacin avanzada. sin mucho rodeo, se logra a trav7s de la propiedad button del objeto column del dbgrid y su evento clic. rpidamente, digamos que ya tiene su dbgrid enlazada a datos y trabaja bien, solo desea agregar un combobo$ a una celda para dar una lista de tems a sus usuarios. digamos que el field se llama .idioma. ".identifique el ndice de columna del campo que implementar una lista. sencillamente, las columnas van enumeradas de 0 , ", , , etc. digamos que el campo idioma se despliega en la columna 8, entonces defina la siguiente constante: defint a*z option e$plicit =++ indice de la columna que tiene un lista desplegable =++ recomiendo la sinta$is colinde$1nombredelista. p.e: const colinde$1list" ( 8 ,.agregue un control list al formulario. me imagino que sabe de sobra que un list o combobo$ se llena de datos al comenzar el programa. tambi7n especifique la propiedad button. esto se hara en el evento cargar del formulario, use de gua el ejemplo: private sub form1load%& =++ llena la lista de soporte al campo idioma =++ ejemplo sencillo 'ith list" .additem .espaol. .additem .ingles. .additem .ruso. .additem .aleman. .additem .frances. .additem .chino. end 'ith =++requerido antes de hacer referencia a campos de dbgrid data".refresh =++la celda de la columna .idioma. mostrara un botn dbgrid".columns%colinde$1list"&.button ( true =++opcional, la celda actual es negra al estilo access

dbgrid".marqueestyle ( dbghighlightcell end sub 8.eventos del dbgrid. el modelo es el siguiente %los comentarios documentan la accin&: private sub dbgrid"1buttonclic;%byval colinde$ as integer& dim c as column if colinde$ ( colinde$1list" then set c ( dbgrid".columns%colinde$& 'ith list" =++ despliegue de la lista al lado de la celda. =++ elimine los comentarios de las dos siguientes lneas =++ y coloque comentarios a las tres posteriores. a su gusto =.left ( dbgrid".left - c.left - c.'idth =.top ( dbgrid".top - dbgrid".ro'top%dbgrid".ro'& =++ lista debajo de la celda, al estilo combobo$ %8 lneas& .left ( dbgrid".left - c.left .top ( dbgrid".top - dbgrid".ro'top%dbgrid".ro'& - dbgrid".ro'height .'idth ( c.'idth - "> .listinde$ ( 0 .visible ( true .zorder 0 .setfocus end 'ith end if end sub private sub dbgrid"1beforecoledit%byval colinde$ as integer, byval ;eyascii as integer, cancel as integer& =++ use este evento para que cuando el usuario teclee un caracter sobre la celda =++ se despliegue la lista. es decir, se obliga al usuario a usar un tem de la lista. =++ en caso de dar al usuario libertad de escribir, elimine las siguientes lneas %if*end if&, =++ o precedales con un comentario if colinde$ ( colinde$1list" then =++ se obliga a seleccionar de la lista: cancel ( true dbgrid"1buttonclic; %colinde$& end if end sub private sub dbgrid"1scroll%cancel as integer& =++oculta la lista si hace scroll list".visible ( false end sub

".eventos de asignacin del te$to a la celda y la base de datos: private sub list"1;eypress%;eyascii as integer& =++habilita el uso de teclado para asignar a la celda o escape... select case ;eyascii case vb;eyreturn =++asigma el te$to seleccionado a la celda dbgrid".columns%colinde$1list"&.te$t ( list".te$t list".visible ( false case vb;eyescape list".visible ( false end select end sub private sub list"1lostfocus%& =++oculta la lista si pierde el enfoque list".visible ( false end sub private sub list"1dblclic;%& list"1;eypress vb;eyreturn end sub analisis implementacin avanzada la implementacin, tal y como la pinte, ciertamente es un cdigo poco robusto, aunque es ms slido que el descrito en el articulo de ape$, en referencia a facilidad de crear listas en los campos que desee, y cuando quiera, sin necesidad de hacer muchos cambios. este cdigo permite crear una lista fcilmente tan solo con cambiar el ndice de columna especificado en la constante colinde$1list". para multiples listas en la misma dbgrid, usara otras constante, digamos colinde$1list,, colinde$1list8, y as sucesivamente, y tendra que duplicar eventos. recomendara hacer al siguiente modificacin: =++********************************************************* =++ varias listas desplegables, ejemplo =++********************************************************* private sub dbgrid"1buttonclic;%byval colinde$ as integer& dim c as column dim l as listbo$ set c ( dbgrid".columns%colinde$& select case colinde$ case colinde$1list": set l ( list" case colinde$1list,: set l ( list,

end select 'ith l =abajo %8&: .left ( dbgrid".left - c.left .top ( dbgrid".top - dbgrid".ro'top%dbgrid".ro'& - dbgrid".ro'height .'idth ( c.'idth - "> .listinde$ ( 0 .visible ( true .zorder 0 .setfocus end 'ith end sub una implementacin ms slida, y profesional, seria crear un array de objetos list y no usar constantes para los ndices sino una variable type, digamos: private type displayliststruct fieldname as string columninde$ as integer querysource as string ;eyrelation as string end type const numberoflist ( 8 =ejemplo private displaylist%0 to numberoflist& as displayliststruct esto permitira realmente automatizar la implementacin, incluyo usando querys para llenar la lista. asignando claves de una tabla de referencia un estndar en access es dar la lista de soporte desde una consulta, y asignar el cdigo de dicha tabla a un campo que establece la relacin de soporte. usara la propiedad data".recordset%.clavedeenlace.&.value ( list".itemdata%list".listinde$&.>. configuracin de la fuente de datos en tiempo de ejecucin francamente este tema da para muchas pginas y el cdigo es bastante pesado para e$plicarlo con claridad en una sesin. as que lo omito por el momento. bsicamente se perfila como un componente de soft'are comercial. sin embargo, aqu les doy la mayora de pautas para que programadores avanzados hagan sus propias herramientas. el objetivo es desplegar cualquier fuente de datos totalmente configurada en una lnea, o de la manera ms simple. el ejemplo de la grfica es: set dbmain ( dbengine%0&.opendatabase%app.path - .?atlas.mdb., options:(false, readonly:(false& ... displaydatabro'ser .paises. el procedimiento displaydatabro'ser tiene un 2nico parmetro que es datasource el cual

ser una consulta o nombre de tabla. el soft'are que lo recibe analiza los datos %almacenados en la estructura y propiedades de los campos& y despliega la hoja de datos. la implementacin de todas las listas de soporte y generacin de la consulta compleja es tambi7n automtico. la contraparte de la vista dbgrid es la vista formulario. la automatizacin de los formularios de carga soporta cambios en la bases de datos %p.e. la inclusin de una nueva tabla, un nuevo campo, o la modificacin de un campo e$istente& sin modificacin de la aplicacin. esto se ve reflejado en una mejor relacin beneficio + costo, al reducir la inversin en mantenimiento de ingeniera de soft'are. de otra parte, en virtud de la automatizacin, se minimizan fallas de diseo. la parte de automatizacin del soporte a datos integrada con bases de datos e$ternas %de catlogos de datos&, permite la ampliacin o reutilizacin de datos corporativos. #. un campo calculado sobre columnas un campo calculado sobre una columna se debe hacer con cdigo, *as usted programe en access. sencillamente agregue un label y control para presentarlo e invoque un procedimiento@ me gusta hacerlo con un sspanel en relieve suave. este procedimiento es un ejemplo claro para calcular y presentar una sumatoria de un campo cualquiera: public sub sumcol% 1 dbg as dbgrid, 1 dat as data, 1 fieldname as string, 1 pnl as sspanel, 1 numberformat as string 1 & dim s as single dim rs as recordset on error goto sumcolerr set rs ( dat.recordset.clone do until rs.eof s ( s - val%rs%fieldname&& rs.movene$t loop pnl ( format%s, numberformat& e$it sub sumcolerr: =++su procedimiento de mensajes end sub desde el formulario que contiene el dbgrid se invoca desde dos eventos. primero para iniciarlo, y luego para actualizarlo despu7s de las modificaciones hechas por los usuarios. digamos que mi sspanel se llama pnl1calc"l y deseo presentar la suma total de produccin:

prvate sub datprimaryrs1reposition%& =++codigo... =++inicia el campo calulado sobre la columna: if pnl1calc".caption ( .. then sumcol grddatagrid, datprimaryrs, .produccin., pnl1calc", .0.0. end if end sub actualiza el total cuando se modifica o agrega un dato: prvate sub grddatagrid1afterupdate%& sumcol grddatagrid, datprimaryrs, .produccin., pnl1calc", .0.0. end sub el procedimiento sirve de modelo para hacer promedios, cculos estadsticos, etc. valga comentar que un calculo sobre una fila %registro& suele hacerse con el sql dentro de la consulta que es origen de los datos. sin embargo puede adaptar la t7cnica e$puesta para hacerlo en un control e$terior al dbgrid. A. implementado un zoom a las celdas supremamente deseable en campos memo.se trata que al dar BshiftC-Bf,C, se muestre una ventana ampliada con el te$to de la celda, *tal como en access. el evento que invoca el zoom es: prvate sub dbgrid"1;eydo'n%;eycode as integer, shift as integer& if %;eycode ( vb;eyf,& and %shift and vbshiftmas;& ) 0 then =++shift-f, openzoomte$t dbgrid", data" end if end sub el procedimiento openzoomte$t se encarga de analizar el campo y desplegar la ventana de zoom: public sub openzoomte$t%dbg as dbgrid, dat as data& dim f as field, n as integer =++verify field n(0 for each f in dat.recordset.fields if f.name ( dbg.columns%dbg.col&.datafield then select case f.type case dbte$t n ( f.size case dbmemo n ( , D "> * " end select e$it for

end if ne$t f =++display zoom form if n then 'ith frm1zoomte$t .title ( f.name .lette$t f.value, n, %f.type ( dbte$t& .sho' vbmodal if .returnpress then dbg.te$t ( .te$t doevents end if end 'ith unload frm1zoomte$t end if end sub por 2ltimo, publico el cdigo completo del formulario frm1zoomte$t %no se justifica un do'nload por tan reducido tamao&. abra notepad, pegue el cdigo a continuacin y archvelo como zoom cell.frm, luego agrege este formulario a su proyecto. version >.00 begin vb.form frm1zoomte$t borderstyle ( 9 =fi$ed tool'indo' clientheight ( ,890 clientleft ( "#E> clienttop ( ,,E> client'idth ( #,90 lin;topic ( .form". ma$button ( 0 =false minbutton ( 0 =false palettemode ( " =usezorder scaleheight ( ,890 scale'idth ( #,90 sho'intas;bar ( 0 =false tag ( .zoomte$t. begin vb.te$tbo$ t$t beginproperty font name ( .ms sans serif. size ( E.A> charset ( 0 'eight ( 900 underline ( 0 =false italic ( 0 =false stri;ethrough ( 0 =false endproperty height ( />> left ( ,90 multiline ( *" =true scrollbars ( , =vertical

tabinde$ ( 0 top ( E0 'idth ( 9E0> end end attribute vb1name ( .frm1zoomte$t. attribute vb1globalnamespace ( false attribute vb1creatable ( false attribute vb1predeclaredid ( true attribute vb1e$posed ( false defint a*z option e$plicit public returnpress as boolean private singleline as boolean private sub form1resize%& t$t.move 0, 0, scale'idth, scaleheight end sub private sub t$t1;eypress%;eypress& select case ;eypress case vb;eyreturn ;eypress ( 0 returnpress ( true hide case vb;eyescape returnpress ( false hide end select end sub private sub form1load%& left ( %screen.'idth * 'idth& ? , end sub public property get te$t%& as string dim lf if singleline then =++discards the te$t thereafter crlf lf ( instr%t$t, vbcrlf& if lf then te$t ( left%t$t, lf * "& else te$t ( t$t end if else te$t ( t$t end if end property

public sub lette$t%s as string, chars as integer, singleline$ as boolean& t$t.te$t ( s t$t.ma$length ( chars singleline ( singleline$ returnpress ( false end sub public property let title%byval ne'value as string& caption ( ne'value end property el te$to se traspasa a la celda con BenterC, puede cancelar con BescC. para introducir un cambio de lnea en un memo, use BctrlC-BenterC. /. el origen de los datos de varias tablas %relaciones complejas& francamente este tema es algo e$tenso y lo omitir7. esta e$trechamente relacionado con el punto > descrito en este documento. se trata de crear el sql con cdigo visual basic, basandose en la informacin de las propiedades predeterminadas y personalizadas de las tablas y campos. si desea databro'ser, me puede escribir por mail y solicitarmelo.. E. ordenar rpidamente un dbgrid el siguiente procedimiento ordena un dbgrid por la columna que tiene el enfoque. coloque un comando como desee para ordenar ascendente y otro para ordenar descendente, e invoque el procedimiento seg2n el caso. public sub sortdbgrid%dbg as dbgrid, dat as data, optional ascpmt as variant& =++ascpmt: true:ascendente %predeterminado&, false: descendente dim rs as recordset dim clause as string dim fieldname as string dim asc as boolean dim currcol as integer on error goto sorterr if ismissing%ascpmt& then asc ( true else asc ( cbool%ascpmt& end if

currcol ( dbg.col fieldname ( dbg.columns%currcol&.datafield if dat.recordset.fields%fieldname&.type ( dbmemo then bo$ .los campos memo no son ordenables. e$it sub end if screen.mousepointer ( vbhourglass set rs ( dat.recordset clause ( .B. - fieldname - .C. if not asc then clause ( clause - . desc. end if rs.sort ( clause set dat.recordset ( rs.openrecordset%rs.type& dbg.col ( currcol dbg.setfocus screen.mousepointer ( vbdefault e$it sub sorterr: =++su procedimiento de mensajes end sub el sort se puede hacer para varios campos al escribir la clusula campo", campo,, ..., campo n. tendra que escribir un cuadro de dialogo para este propsito y ajustar el procedimiento anterior. filtrar un dbdrid es muy similar al procedimiento anterior, solo tiene que especificar la clausula de filtro y asignarla en rd.filter ( clause@ es elegante programar cuadro de dialogo que permita al usuario crear la clausula de filtro de manera simple. no obligue a sus usuarios a estudiar sql. "0. cambiar el registro de un dbgrid en tiempo de ejecucin el siguiente procedimiento gen7rico permite asignar valores a una fila de un dbgrid con cdigo. 2til cuando el recordset tiene varias claves de relacin, que por supuesto no se muestran en columnas de la dbgrid pero estn presentes en el control data fuente de registros. public sub letdbgridrecord%dbg as dbgrid, dat as data& dim rs as recordset dim onne' as boolean on error goto letdbgridrecorderr set rs ( dat.recordset

if dbg1datos.addne'mode then onne' ( true rs.addne' else rs.edit end if =++asignacin de valores: rs%anyfield"& ( value" rs%anyfield,& ( value, =... rs.update if onne' then rs.movelast set rs ( nothing e$it sub letdbgridrecorderr: =++su procedimiento de mensajes end sub el procedimiento se puede generalizar al colocar un parametro variant de contenga una matriz bidimensional %nombredecampo, nuevovalor&. queda como ejercicio@ pista: dim $ as variant ... redim $%0 to n, 0 to n& ... como informacin, puede realizar cambios en el recordset del dbgrid sin usar los m7todos edit o addne', pero solo es posible en el evento beforeupdate de un registro recien editado en la dbgrid.

Anda mungkin juga menyukai