Códigos de ejemplo para aprender distintas tecnologías, o lo que sucede cuando a una cuarentona se la deja sola con una computadora
Acerca de:
Este blog contiene los códigos, ejemplos y bases de datos que he usado cuando aprendía acerca de algún tema específico. En lugar de borrarlos (una vez dominado ya el tema), he decidido publicarlos :)
miércoles, 21 de diciembre de 2011
Mi Repositorio de Códigos Fuente
Son códigos que ya he publicado anteriormente, pero ahora en un sólo lugar, en mi cuenta en mygnet para que todo el mundo los descargue, los copie, los modifique, los analice, los traduzca a otros lenguajes, y haga todo lo que les plazca con ellos :D
jueves, 17 de noviembre de 2011
La Api ShellExecute devuelve código de error 42
El error 42 se produce cuando se intenta abrir un ejecutable con la api ShellExecute, la cual sirve para abrir archivos o carpetas. En el caso de VB6, si se desea ejecutar otra aplicación se deberá usar la función Shell.
En VB6 la api ShellExecute se declara como:
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal HWnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
Si deseo abrir un archivo con el programa que lo abre por defecto, deberé escribir (Me es el formulario):
Esto abrirá el archivo de texto con el block de notas.
Si deseo abrir un archivo con otro programa, escribiré:
Lo cual abrirá el archivo de texto con el Wordpad de Windows.
La función Shell es propia de VB6. Si quiero ejecutar una aplicación deberé escribir:
Shell "C:\MiApp.exe", vbNormalFocus
Update Abril 2013:
Sí se pueden ejecutar archivos ejecutables con la api ShellExecute, sólo hay que pasarle los parámetros correctos:
Dim ret As Long
ret = ShellExecute(Me.hwnd, vbNullString, _
"D:\unaCarpeta\Otra Carpeta\mIEjecutable.exe", vbNullString, vbNullString, 1)
Si no se va a evaluar el valor devuelto por ShellExecute no es necesario declarar la variable ret. Por ejemplo esto ejecuta el block de notas:
ShellExecute Me.hwnd, vbNullString, "notepad.exe", vbNullString, vbNullString, 1
Y esto ejecuta la calculadora de windows:
ShellExecute Me.hwnd, vbNullString, "calc.exe", vbNullString, vbNullString, 1
En VB6 la api ShellExecute se declara como:
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal HWnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
Si deseo abrir un archivo con el programa que lo abre por defecto, deberé escribir (Me es el formulario):
Dim ret As Long
ret = ShellExecute(Me.HWnd, "Open", "C:\text.txt", "", "", 1)
ret = ShellExecute(Me.HWnd, "Open", "C:\text.txt", "", "", 1)
Esto abrirá el archivo de texto con el block de notas.
Si deseo abrir un archivo con otro programa, escribiré:
Dim ret As Long
ret = ShellExecute(Me.HWnd, "Open", "Wordpad.exe", "C:\text.txt", "", 1)
ret = ShellExecute(Me.HWnd, "Open", "Wordpad.exe", "C:\text.txt", "", 1)
Lo cual abrirá el archivo de texto con el Wordpad de Windows.
La función Shell es propia de VB6. Si quiero ejecutar una aplicación deberé escribir:
Shell "C:\MiApp.exe", vbNormalFocus
Update Abril 2013:
Sí se pueden ejecutar archivos ejecutables con la api ShellExecute, sólo hay que pasarle los parámetros correctos:
Dim ret As Long
ret = ShellExecute(Me.hwnd, vbNullString, _
"D:\unaCarpeta\Otra Carpeta\mIEjecutable.exe", vbNullString, vbNullString, 1)
Si no se va a evaluar el valor devuelto por ShellExecute no es necesario declarar la variable ret. Por ejemplo esto ejecuta el block de notas:
ShellExecute Me.hwnd, vbNullString, "notepad.exe", vbNullString, vbNullString, 1
Y esto ejecuta la calculadora de windows:
ShellExecute Me.hwnd, vbNullString, "calc.exe", vbNullString, vbNullString, 1
lunes, 24 de octubre de 2011
Error al actualizar un Recordset: "El Campo no es Actualizable"
Intentaba modificar un registro de una base de datos en Access desde VB6, cuando, al hacer miRecordset.Update, me saltaba el siguiente error:
Aunque los permisos de la base de datos permitan hacer modificaciones a sus datos, un campo del recordset no permite cambiar su contenido si es auto incrementable. Antes de actualizar mi recordset, necesitaba saber qué campos son autoincrementables para no tocarlos cuando quiera modificar su contenido.
Son rescatables estos posts:
for i = 0 to rs.Fields(x).Properties.co unt - 1
debug.print rs.Fields(x).Properties(i) .name
next i
Thanks that helped a bit, the properties listed are
BASECATALOGNAME
BASECOLUMNNAME
BASESCHEMANAME
BASETABLENAME
COLLATINGSEQUENCE
COMPUTEMODE
DATETIMEPRECISION
ISAUTOINCREMENT
ISCASESENSITIVE
ISSEARCHABLE
OCTETLENGTH
KEYCOLUMN
COMPFLAGS
SORTID
BASETABLEINSTANCE
TDSCOLLATION
Para saber, por ejemplo, si un campo con índice x es auto incrementable, se hace:
If miRecordset(x).Properties("IsAutoIncrement").Value Then _
Debug.Print "Es Auto Incrementable"
En mi caso, al modificar mi recordset, hago:
For i = 0 To miRecordset.Fields.count - 1
If Not miRecordset(i).Properties("IsAutoIncrement").Value Then
miRecordset(i) = nuevoValor
End If
Next
Con esto elimino el error de Campo no Actualizable.
En general, el mensaje de error es: "No se puede actualizar 'nombre del campo'; el campo no es actualizable".
Esto se debe a que ese campo específico tiene alguna característica que hace que no se puede reescribir. En mi base d edatos, el campo "Id" es llave primaria y es auto incrementable.
Aunque los permisos de la base de datos permitan hacer modificaciones a sus datos, un campo del recordset no permite cambiar su contenido si es auto incrementable. Antes de actualizar mi recordset, necesitaba saber qué campos son autoincrementables para no tocarlos cuando quiera modificar su contenido.
Después de mucho buscar por internet, di con este foro:
http://www.experts-exchange.com/Programming/Languages/Visual_Basic/Q_20248270.htmlSon rescatables estos posts:
Expert Comment
Posted by rspahitz on 21/12/01 at 8:20 AM
I don't know the answer, but since (I think) Properties is a collection, you should be able to cycle through and find the valid choices:for i = 0 to rs.Fields(x).Properties.co
debug.print rs.Fields(x).Properties(i)
next i
Author Comment
Posted by andyknott on 21/12/01 at 8:28 AM
Hi rspahitz,Thanks that helped a bit, the properties listed are
BASECATALOGNAME
BASECOLUMNNAME
BASESCHEMANAME
BASETABLENAME
COLLATINGSEQUENCE
COMPUTEMODE
DATETIMEPRECISION
ISAUTOINCREMENT
ISCASESENSITIVE
ISSEARCHABLE
OCTETLENGTH
KEYCOLUMN
COMPFLAGS
SORTID
BASETABLEINSTANCE
TDSCOLLATION
Para saber, por ejemplo, si un campo con índice x es auto incrementable, se hace:
If miRecordset(x).Properties("IsAutoIncrement").Value Then _
Debug.Print "Es Auto Incrementable"
En mi caso, al modificar mi recordset, hago:
For i = 0 To miRecordset.Fields.count - 1
If Not miRecordset(i).Properties("IsAutoIncrement").Value Then
miRecordset(i) = nuevoValor
End If
Next
miRecordset.Update
Con esto elimino el error de Campo no Actualizable.
sábado, 8 de octubre de 2011
Desocultando Carpetas Ocultadas por Virus con Linq
Actualización de http://electronicaamartillazos.co.nr/ (sección C#) donde muestro cómo usar Linq para crear un programita que desoculta todas las carpetas ocultas (y declaradas como carpetas de sistema) en los directorios raíz de discos duros y memorias extraíbles. Los virus que ocultan carpetas también las declaran como carpetas de sistema, de modo que no se pueden desocultar manualmente.
Este programita sirve como base para hacer programas más complejos que administren los atributos de archivos, carpetas y subcarpetas.
Este programita sirve como base para hacer programas más complejos que administren los atributos de archivos, carpetas y subcarpetas.
viernes, 9 de septiembre de 2011
Error en Crystal Reports: "Esta sección de Grupo no se puede imprimir..."
El mensaje completo es:
"Esta Seccion de grupo no se puede imprimir porque su campo de condicion no existe o no es valido. Dar formato a la seccion para elegir otro campo de condicion". Este mensaje de error aparece al querer ir a la pestaña "Vista Previa". Al presionar el botón Aceptar, aparece una página en blanco en lugar del reporte.
Busqué en Internet y no hallé cómo eliminar este error. Tampoco hallé nada útil en la Ayuda de Crystal Reports. Pero, después de probar un poco, dí yo misma con la solución.
Todos los reportes de Crystal Reports van conectados a una Base de Datos. Los grupos del reporte (por ejemplo un encabezado), están vinculadas a un campo específico de la Base de Datos. Esto es para que Crystal Reports sepa en qué orden mostrar los reportes con la data jalada desde la Base de Datos.
Este error se genera al cambiar la conexión a otra Base de Datos, eliminarla, cambiar a otra tabla, y cualquier situación en que el reporte no tenga cómo hallar el campo al que estaba vinculado.
Para solucionar esto, se debe ir al asistente de Base de Datos y configurar o crear la conexión, esto es necesario en caso de haberla eliminado:
Luego, en la pertaña Diseño, le hacemos click derecho al grupo que da problemas y elegimos la opción "Cambiar el Grupo":
Se nos abrirà la ventana que nos permitirá asignar un nuevo campo de condición:
Con esto, ya podemos ir a la Vista Previa de nuestro reporte :D
"Esta Seccion de grupo no se puede imprimir porque su campo de condicion no existe o no es valido. Dar formato a la seccion para elegir otro campo de condicion". Este mensaje de error aparece al querer ir a la pestaña "Vista Previa". Al presionar el botón Aceptar, aparece una página en blanco en lugar del reporte.
Busqué en Internet y no hallé cómo eliminar este error. Tampoco hallé nada útil en la Ayuda de Crystal Reports. Pero, después de probar un poco, dí yo misma con la solución.
Todos los reportes de Crystal Reports van conectados a una Base de Datos. Los grupos del reporte (por ejemplo un encabezado), están vinculadas a un campo específico de la Base de Datos. Esto es para que Crystal Reports sepa en qué orden mostrar los reportes con la data jalada desde la Base de Datos.
Este error se genera al cambiar la conexión a otra Base de Datos, eliminarla, cambiar a otra tabla, y cualquier situación en que el reporte no tenga cómo hallar el campo al que estaba vinculado.
Para solucionar esto, se debe ir al asistente de Base de Datos y configurar o crear la conexión, esto es necesario en caso de haberla eliminado:
Luego, en la pertaña Diseño, le hacemos click derecho al grupo que da problemas y elegimos la opción "Cambiar el Grupo":
Se nos abrirà la ventana que nos permitirá asignar un nuevo campo de condición:
Con esto, ya podemos ir a la Vista Previa de nuestro reporte :D
lunes, 1 de agosto de 2011
Leyendo data numérica desde un archivo de texto con C++
Tengo un archivo de texto que contiene una lista de números con el siguiente formato:
Pero si quiero operar con todos los números en un archivo de texto sin importar cuántos sean, usaré este código:
Ambos códigos han sido probados con el compilador gratuito de Borland.
Cómo usar el compilador, lo explico aquí.
En este link hay información sobre "fscanf" y "rewind". Y aquí hay un tutorial sobre lectura y escritura de archivos con C++.
He llamado al archivo "18.txt" por ninguna razón en especial. Lo que quiero hacer es leer los números en el archivo y realizar algunas operaciones matemáticas con ellos. Como están en formato de texto, primero debo convertirlos a números decimales.
Para ello uso la función "atof", pero hay un problema: mis números usan coma decimal, y la función "atof" considera punto decimal. Debo leer los números, línea por línea, y ponerlos en el formato con el que puede trabajar "atof", así que declaro un aray de caracteres llamado "palabra". Ninguno de los números guardados en "18.txt" ocupa más de cinco caracteres, así que "palabra" es declarada como: char palabra[6];
Luego recorro cada caracter dentro de "palabra" y si encuentro una coma, la reemplazo por un punto.
El array "beta", separa espacio en memoria para 150 números decimales ya que sólo quiero operar con 150 números en total.
El código fuente es el siguiente (el ejecutable compilado está en la misma carpeta que "18.txt"):
#include <iostream.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#pragma hdrstop
#pragma argsused
void main(int argc, char* argv[])
{ FILE *fp;
int i;
double *beta, c, promedio, rms, desviacion;
char palabra[6];
beta = (double *)malloc(sizeof(double)*151);
i=0;
fp = fopen("18.txt", "r");
if (fp==NULL)
cout<<"no existe el archivo \n";
else {
do
{
c = fscanf(fp, "%s", palabra);
for(int j=0; j<6; j++)
if (palabra[j]== ',')
{ palabra[j]='.'; break; }
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#pragma hdrstop
#pragma argsused
void main(int argc, char* argv[])
{ FILE *fp;
int i;
double *beta, c, promedio, rms, desviacion;
char palabra[6];
beta = (double *)malloc(sizeof(double)*151);
i=0;
fp = fopen("18.txt", "r");
if (fp==NULL)
cout<<"no existe el archivo \n";
else {
do
{
c = fscanf(fp, "%s", palabra);
for(int j=0; j<6; j++)
if (palabra[j]== ',')
{ palabra[j]='.'; break; }
beta[i] = atof(palabra);
cout<<beta[i];
cout<<"\n";
i++;
}
while (c != EOF && i != 151);
//valores estadísticos:
promedio=0; desviacion=0; rms=0;
//Promedio
for (int j= 0; j<=150; j++)
promedio= promedio+ beta[j];
promedio = promedio/151;
cout<<"Promedio "; cout<<promedio;
cout<<"\n";
//Desviación Estándar
for (int j= 0; j<=150; j++)
desviacion= desviacion + pow((beta[j]-promedio),2);
cout<<beta[i];
cout<<"\n";
i++;
}
while (c != EOF && i != 151);
//valores estadísticos:
promedio=0; desviacion=0; rms=0;
//Promedio
for (int j= 0; j<=150; j++)
promedio= promedio+ beta[j];
promedio = promedio/151;
cout<<"Promedio "; cout<<promedio;
cout<<"\n";
//Desviación Estándar
for (int j= 0; j<=150; j++)
desviacion= desviacion + pow((beta[j]-promedio),2);
desviacion=pow(desviacion,0.5)/pow(151,0.5);
cout<<"la desviacion estandar es: "; cout<<desviacion;
cout<<"\n";
//Valor Cuadrático Medio
for (int j= 0; j<=150; j++)
rms= rms + pow(beta[j],2);
cout<<"la desviacion estandar es: "; cout<<desviacion;
cout<<"\n";
//Valor Cuadrático Medio
for (int j= 0; j<=150; j++)
rms= rms + pow(beta[j],2);
rms=pow(rms,0.5)/pow(151,0.5);
cout<<"El valor RMS: "; cout<<rms;
cout<<"\n";
fclose(fp);
}
system("PAUSE");
}
cout<<"El valor RMS: "; cout<<rms;
cout<<"\n";
fclose(fp);
}
system("PAUSE");
}
Pero si quiero operar con todos los números en un archivo de texto sin importar cuántos sean, usaré este código:
#include <iostream.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#pragma hdrstop
#pragma argsused
void main(int argc, char* argv[])
{ FILE *fp;
double i;
double beta, c, promedio, rms, desviacion;
char palabra[6];
//valores estadísticos:
promedio=0; desviacion=0; rms=0;
i=0;
fp = fopen("18.txt", "r");
if (fp==NULL)
cout<<"no existe el archivo \n";
else {
do
{
c = fscanf(fp, "%s", palabra);
for(int j=0; j<6; j++)
if (palabra[j]== ',')
{ palabra[j]='.'; break; }
beta = atof(palabra);
cout<<beta;
cout<<"\n";
i++;
promedio = promedio + beta;
rms = rms + pow(beta,2);
}
while (c != EOF);
promedio = promedio/i;
rms=pow(rms,0.5)/pow(i,0.5);
i=0;
rewind(fp);
do
{
c = fscanf(fp, "%s", palabra);
for(int j=0; j<6; j++)
if (palabra[j]== ',')
{ palabra[j]='.'; break; }
beta = atof(palabra);
i++;
desviacion= desviacion + pow((beta-promedio),2);
}
while (c != EOF);
desviacion=pow(desviacion,0.5)/pow(i,0.5);
cout<<"Promedio "; cout<<promedio;
cout<<"\n";
cout<<"la desviacion estandar es: "; cout<<desviacion;
cout<<"\n";
cout<<"El valor RMS: "; cout<<rms;
cout<<"\n";
fclose(fp);
}
system("PAUSE");
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#pragma hdrstop
#pragma argsused
void main(int argc, char* argv[])
{ FILE *fp;
double i;
double beta, c, promedio, rms, desviacion;
char palabra[6];
//valores estadísticos:
promedio=0; desviacion=0; rms=0;
i=0;
fp = fopen("18.txt", "r");
if (fp==NULL)
cout<<"no existe el archivo \n";
else {
do
{
c = fscanf(fp, "%s", palabra);
for(int j=0; j<6; j++)
if (palabra[j]== ',')
{ palabra[j]='.'; break; }
beta = atof(palabra);
cout<<beta;
cout<<"\n";
i++;
promedio = promedio + beta;
rms = rms + pow(beta,2);
}
while (c != EOF);
promedio = promedio/i;
rms=pow(rms,0.5)/pow(i,0.5);
i=0;
rewind(fp);
do
{
c = fscanf(fp, "%s", palabra);
for(int j=0; j<6; j++)
if (palabra[j]== ',')
{ palabra[j]='.'; break; }
beta = atof(palabra);
i++;
desviacion= desviacion + pow((beta-promedio),2);
}
while (c != EOF);
desviacion=pow(desviacion,0.5)/pow(i,0.5);
cout<<"Promedio "; cout<<promedio;
cout<<"\n";
cout<<"la desviacion estandar es: "; cout<<desviacion;
cout<<"\n";
cout<<"El valor RMS: "; cout<<rms;
cout<<"\n";
fclose(fp);
}
system("PAUSE");
}
Ambos códigos han sido probados con el compilador gratuito de Borland.
Cómo usar el compilador, lo explico aquí.
En este link hay información sobre "fscanf" y "rewind". Y aquí hay un tutorial sobre lectura y escritura de archivos con C++.
viernes, 15 de julio de 2011
Calculando la potencia de un número usando recursividad en C#
Primero, el código fuente:
class Potencia
{
static void Main(string[] args)
{
Potencia pot = new Potencia();
double r = pot.potenciaR(2, 1, 3, 0);
Console.WriteLine(r.ToString());
Console.Read();
}
private double potenciaR(double base0, double p, int exponente, int i)
{
return i >= exponente ? p : potenciaR(base0, p * base0, exponente, i + 1);
}
}
Los parámetros de la función "potenciaR" son: base, resultado, exponente, condición de parada.
El parámetro "p" debe ser 1 al inicio porque es el "acumulador" dodne se irá multiplicando la base tantas veces como indique el exponente. La función "potenciaR" deja de llamarse a sí misma cuando el parámetro "i" es igual al valor "exponente". El valor inicial de "i" es cero.
Y a continuación, lo mismo, pero con una expresión lambda recursiva:
Releyendo, noté que podemos suprimir el parámetro "i" y usar el mismo parámetro "exponente" como condición de parada. Para la expresión lambda recursiva queda así:
En todos los casos, el parámetro "p" es siempre 1.
Esta es la web donde aprendí a hacer expresiones lambda recursivas:
http://commanet.blogspot.com/2008/02/recursividad-annima.html
class Potencia
{
static void Main(string[] args)
{
Potencia pot = new Potencia();
double r = pot.potenciaR(2, 1, 3, 0);
Console.WriteLine(r.ToString());
Console.Read();
}
private double potenciaR(double base0, double p, int exponente, int i)
{
return i >= exponente ? p : potenciaR(base0, p * base0, exponente, i + 1);
}
}
Los parámetros de la función "potenciaR" son: base, resultado, exponente, condición de parada.
El parámetro "p" debe ser 1 al inicio porque es el "acumulador" dodne se irá multiplicando la base tantas veces como indique el exponente. La función "potenciaR" deja de llamarse a sí misma cuando el parámetro "i" es igual al valor "exponente". El valor inicial de "i" es cero.
Y a continuación, lo mismo, pero con una expresión lambda recursiva:
class Potencia
{
static void Main(string[] args)
{
Func<double, double, double,double, double> potenciaF = null;
potenciaF = (base0, p, exponente, i) =>
i >= exponente ? p : potenciaF(base0, p * base0, exponente, i + 1);
Console.WriteLine(potenciaF(2, 1, 3, 0).ToString());
Console.Read();
}
}
{
static void Main(string[] args)
{
Func<double, double, double,double, double> potenciaF = null;
potenciaF = (base0, p, exponente, i) =>
i >= exponente ? p : potenciaF(base0, p * base0, exponente, i + 1);
Console.WriteLine(potenciaF(2, 1, 3, 0).ToString());
Console.Read();
}
}
Releyendo, noté que podemos suprimir el parámetro "i" y usar el mismo parámetro "exponente" como condición de parada. Para la expresión lambda recursiva queda así:
class Potencia
{
static void Main(string[] args)
{
Func<double, double, double, double> potenciaF = null;
potenciaF = (base0, p, exponente) =>
exponente <= 0 ? p : potenciaF(base0, p * base0, exponente - 1);
Console.WriteLine(potenciaF(2, 1, 3).ToString());
Console.Read();
}
{
static void Main(string[] args)
{
Func<double, double, double, double> potenciaF = null;
potenciaF = (base0, p, exponente) =>
exponente <= 0 ? p : potenciaF(base0, p * base0, exponente - 1);
Console.WriteLine(potenciaF(2, 1, 3).ToString());
Console.Read();
}
}
Esta es la web donde aprendí a hacer expresiones lambda recursivas:
http://commanet.blogspot.com/2008/02/recursividad-annima.html
viernes, 3 de junio de 2011
VB6 Code Snippet: Mantener la proporción de alto y ancho de una imagen
Tengo una imagen cargada en un control Image en Visual Basic 6. Quiero que esa imagen mantenga su proporción Ancho/Alto cuando el control Image tiene su propiedad Stretch en True. El código para hacerlo es el siguiente (He llamado al control Image imgProporcion):
Dim i As Double, j As Double
Dim proporcion As Double
i = imgProporcion.Width
j = imgProporcion.Height
imgProporcion.Visible = False
imgProporcion.Stretch = False
i = (i / imgProporcion.Width)
j = (j / imgProporcion.Height)
If j > i Then proporcion = j Else proporcion = i
imgProporcion.Stretch = True
imgProporcion.Width = CInt(proporcion * imgProporcion.Width)
imgProporcion.Height = CInt(proporcion * imgProporcion.Height)
imgProporcion.Visible = True
Dim proporcion As Double
i = imgProporcion.Width
j = imgProporcion.Height
imgProporcion.Visible = False
imgProporcion.Stretch = False
i = (i / imgProporcion.Width)
j = (j / imgProporcion.Height)
If j > i Then proporcion = j Else proporcion = i
imgProporcion.Stretch = True
imgProporcion.Width = CInt(proporcion * imgProporcion.Width)
imgProporcion.Height = CInt(proporcion * imgProporcion.Height)
imgProporcion.Visible = True
viernes, 29 de abril de 2011
Haciendo el Test Fizz Buzz con Linq en C#
Leyendo algunos de los muchos blogs de programación flotando por ahí, es muy probable toparse con el Test Fizz Buzz, el que yo ya he usado antes para practicar algunas cosas de programación en C#.
Y por ahí se me ocurrió hacerlo usando Linq. Todo el código es el siguiente:
using System;
using System.Linq;
using System.Collections.Generic;
namespace Operator
{
class Program
{
static void Main(string[] args)
{
int[] fbz = new int[100];
for (int i = 1; i <= 100; i++)
fbz[i - 1] = i;
IEnumerable <string > fizbuz = fbz.Select(
c=> (c % 3 == 0) & (c % 5 == 0) ? "FizzBuzz" :
(c % 3 == 0) ? "Fizz" :
(c % 5 == 0) ? "Buzz" : c.ToString() );
foreach (string c in fizbuz)
Console.WriteLine(c);
Console.Read();
}
}
}
Una cosa interesante del Linq es que tiene algo llamado "Lazy Evaluation" ó "Evaluación perezosa": la ejecución de las instrucciones no se realiza cuando se declara la interfaz IEnumerable "fizbuz", si no cuando se la recorre con el bucle foreach. De esta forma se pueden tener muchas interfaces pertenecientes a System.Collections y recién ejecutar sus códigos cuando se las recorre con un foreach.
Y luego, para cumplir con las condiciones del test, vuelvo a usar el operador ternario "?", el cual me gusta mucho porque marea cuando se lo ve las primeras veces :D :D
Y por ahí se me ocurrió hacerlo usando Linq. Todo el código es el siguiente:
using System;
using System.Linq;
using System.Collections.Generic;
namespace Operator
{
class Program
{
static void Main(string[] args)
{
int[] fbz = new int[100];
for (int i = 1; i <= 100; i++)
fbz[i - 1] = i;
IEnumerable
c=> (c % 3 == 0) & (c % 5 == 0) ? "FizzBuzz" :
(c % 3 == 0) ? "Fizz" :
(c % 5 == 0) ? "Buzz" : c.ToString() );
foreach (string c in fizbuz)
Console.WriteLine(c);
Console.Read();
}
}
}
Una cosa interesante del Linq es que tiene algo llamado "Lazy Evaluation" ó "Evaluación perezosa": la ejecución de las instrucciones no se realiza cuando se declara la interfaz IEnumerable "fizbuz", si no cuando se la recorre con el bucle foreach. De esta forma se pueden tener muchas interfaces pertenecientes a System.Collections y recién ejecutar sus códigos cuando se las recorre con un foreach.
Y luego, para cumplir con las condiciones del test, vuelvo a usar el operador ternario "?", el cual me gusta mucho porque marea cuando se lo ve las primeras veces :D :D
martes, 19 de abril de 2011
C# Code Snippet: Usando el control FontDialog
En una aplicación tipo WindowsApplication tengo un FontDialog, y quiero que cuando el usuario hace click en "Aceptar", los valores de este FontDialog se almacenen en un objeto tipo FontStyle, el que luego se utiliza para crear un objeto tipo Font.
El código es éste:
Aquí hago uso del operador ternario '?' para acortar la expresión donde se asigna el tipo de la fuente. Si no uso este operador, la expresión sería:
if (dlgFont.Font.Bold)
myFontStyle = FontStyle.Bold;
else
if (dlgFont.Font.Italic)
myFontStyle = FontStyle.Italic;
else
if (dlgFont.Font.Underline)
myFontStyle = FontStyle.Underline;
else
if (dlgFont.Font.Strikeout)
myFontStyle = FontStyle.Strikeout;
else
myFontStyle = FontStyle.Regular;
El código es éste:
if (dlgFont.ShowDialog() == DialogResult.OK)
{
{
// asigno el estilo de fuente
myFontStyle =
dlgFont.Font.Bold ? FontStyle.Bold :
dlgFont.Font.Italic ? FontStyle.Italic :
dlgFont.Font.Underline ? FontStyle.Underline :
dlgFont.Font.Strikeout ? FontStyle.Strikeout : FontStyle.Regular;
myFont =
myFontStyle =
dlgFont.Font.Bold ? FontStyle.Bold :
dlgFont.Font.Italic ? FontStyle.Italic :
dlgFont.Font.Underline ? FontStyle.Underline :
dlgFont.Font.Strikeout ? FontStyle.Strikeout : FontStyle.Regular;
myFont =
new Font(dlgFont.Font.Name, dlgFont.Font.Size, myFontStyle);
}
}
Aquí hago uso del operador ternario '?' para acortar la expresión donde se asigna el tipo de la fuente. Si no uso este operador, la expresión sería:
if (dlgFont.Font.Bold)
myFontStyle = FontStyle.Bold;
else
if (dlgFont.Font.Italic)
myFontStyle = FontStyle.Italic;
else
if (dlgFont.Font.Underline)
myFontStyle = FontStyle.Underline;
else
if (dlgFont.Font.Strikeout)
myFontStyle = FontStyle.Strikeout;
else
myFontStyle = FontStyle.Regular;
jueves, 24 de marzo de 2011
VB6: Rutina para Eliminar FIlas Repetidas en un Hierarchical FlexGrid
Esta rutina está pensada para un Hierarchical FlexGrid cuya primera fila (la que tiene el índice 0) contiene los nombres de las columnas, por ello procesa a partir de la fila con índice 1:
Sub eliminar_Repetidos()
Dim estaFila, unaFila As String
Dim i, j, m, n As Integer
estaFila = vbNullString
unaFila = vbNullString
With HierarchicalFlexGrid
m = 1 ' Apunta a la primera Fila
n = .Rows - 1 ' Cantidad de filas del HierarchicalFlexGrid
Do Until m > n
estaFila = vbNullString 'cadena con la Fila Actual
For i = 0 To .Cols - 1
estaFila = estaFila + .TextMatrix(m, i) ' Relleno la cadena con los datos de toda la fila
Next
j = 1
Do Until j > n
unaFila = vbNullString ' Fila a comparar
For i = 0 To .Cols - 1
unaFila = unaFila + .TextMatrix(j, i) ' la relleno con los datos de toda la fila
Next
If estaFila = unaFila And j <> m Then
.RemoveItem (j) ' Si son iguales remuevo unaFila solamente
n = n - 1 ' tamaño actual del HierarchicalFlexgrid, al remover disminuye en uno
End If
j = j + 1
Loop
m = m + 1
Loop
'Chequeo si la última y la penúltima fila son iguales, porque no se eliminan si lo son
For i = 0 To .Cols - 1
estaFila = estaFila + .TextMatrix(.Rows - 1, i)
unaFila = unaFila + .TextMatrix(.Rows - 2, i)
Next
If unaFila = estaFila Then .RemoveItem (.Rows - 2)
End With
End Sub
La rutina hace lo siguiente: cojo la primera fila y, en un bucle, la comparo con todas las demás y voy eliminando las que son iguales a la primera fila. Al terminar paso a la segunda fila y vuelvo a comparar y eliminar si son iguales. Esto se repite hasta llegar al final del Hierarchical FlexGrid.
Este algoritmo es más eficiente que, en dos bucles anidados, marcar las filas repetidas para eliminarlas después.
viernes, 11 de marzo de 2011
Obtener los nombres de las tablas y los nombres de sus esquemas de una BD en SQLServer desde VB6
Un día intentaba conectarme a AdventureWorks sample BD desde una app en Visual Basic 6.
Declaraba un recordset como sigue:
db.Open miConnectionString 'db es un objeto tipo Connection
Set rs = db.OpenSchema(adSchemaTables, Array(Empty, Empty, Empty, "TABLE"))
para poder listar todas sus tablas, usando un bucle.
Mi problema era que al ejecutar un query en SQL:
Dim s as String
Do Until rs.EOF
s="Select * from " & rs!Table_Name
' Hacer muchas muchas cosas con la variable "s"
rs.MoveNext
Loop
Me botaba error, ya que sólo tenía el nombre de la tabla. Para que funcionara, el query dentro de la variable "s" necessitaba también el nombre del esquema (Schema Name) y contruirlo todo de la siguiente forma:
Select * from Schema_Name.Tabla
Luego de mucho rebuscar en Google, hallé esta web
http://www.techrepublic.com/article/much-ado-about-field-properties/1045310
Donde explican lo que hace OpenSchema. Para mi caso, utilizo el SchemaID "AdSchemaTables", el cual incluye un filtro llamado "TABLE_SCHEMA".
Finalmente mi query queda:
Dim s as String
Do Until rs.EOF
s="Select * from " & rs!Table_Schema & "." & rs!Table_Name
' Hacer muchas muchas cosas con la variable "s"
rs.MoveNext
Loop
Update!
Cómo saber si una tabla tiene un nombre de esquema asignado:
Basta añadir este código en el bucle ("miTabla" es una variable tipo String):
miTabla = vbNullString
miTabla = rs!TABLE_SCHEMA
If miTabla <> vbNullString Then
miTabla = rs!TABLE_SCHEMA & "." & rs!TABLE_NAME
Else
miTabla = rs!TABLE_NAME
End If
Declaraba un recordset como sigue:
db.Open miConnectionString 'db es un objeto tipo Connection
Set rs = db.OpenSchema(adSchemaTables, Array(Empty, Empty, Empty, "TABLE"))
para poder listar todas sus tablas, usando un bucle.
Mi problema era que al ejecutar un query en SQL:
Dim s as String
Do Until rs.EOF
s="Select * from " & rs!Table_Name
' Hacer muchas muchas cosas con la variable "s"
rs.MoveNext
Loop
Me botaba error, ya que sólo tenía el nombre de la tabla. Para que funcionara, el query dentro de la variable "s" necessitaba también el nombre del esquema (Schema Name) y contruirlo todo de la siguiente forma:
Select * from Schema_Name.Tabla
Luego de mucho rebuscar en Google, hallé esta web
http://www.techrepublic.com/article/much-ado-about-field-properties/1045310
Donde explican lo que hace OpenSchema. Para mi caso, utilizo el SchemaID "AdSchemaTables", el cual incluye un filtro llamado "TABLE_SCHEMA".
Finalmente mi query queda:
Dim s as String
Do Until rs.EOF
s="Select * from " & rs!Table_Schema & "." & rs!Table_Name
' Hacer muchas muchas cosas con la variable "s"
rs.MoveNext
Loop
Update!
Cómo saber si una tabla tiene un nombre de esquema asignado:
Basta añadir este código en el bucle ("miTabla" es una variable tipo String):
miTabla = vbNullString
miTabla = rs!TABLE_SCHEMA
If miTabla <> vbNullString Then
miTabla = rs!TABLE_SCHEMA & "." & rs!TABLE_NAME
Else
miTabla = rs!TABLE_NAME
End If
jueves, 17 de febrero de 2011
C# y Ms Access: Excepciòn del tipo "Insert Into Syntaxis Error"
Sucedió un día que tenía que insertar unos datitos a una base de datos en Access 2003 usando C#. La base de datos tiene una sola tabla (la llamaré "miTabla") con tres campos: "No", "un_ID" y "Tittle" de tipos numérico, texto y texto, respectivamente.
Mi código era:
Y a pesar de estar todo bien, siempre me tiraba una excepción que decía "Syntaxis Error en Insert Into", o cualquier cosa parecida, en la línea cmd.ExecuteNonQuery().
Después de horas depurando y leyendo foros, encontré por ahí un tip clave:
A las bases de datos en Access no les gustan los campos con nombres como "Date", "login" o "Password".
Entonces el error no estaba en mi Insert Into, si no, posiblemente, en los nombres de mis campos.
Hice una pequeña modificación al código (no a la base de datos) y el problema se resolvió maravillosamente:
Dejo como tarea hallar el cambio que hice :)
Mi código era:
private void AddDato(string No, string ID, string Tittle, ref OleDbConnection cnn)
{
OleDbCommand cmd = new OleDbCommand(
{
OleDbCommand cmd = new OleDbCommand(
"INSERT INTO miTabla (No, un_ID, Tittle) VALUES(@Num, @uID, @nTittle)", cnn);
cmd.Parameters.AddWithValue("@Num", Convert.ToInt32(No));
cmd.Parameters.AddWithValue("@uID", ID);
cmd.Parameters.AddWithValue("@nTittle", Tittle);
cnn.Open();
cmd.ExecuteNonQuery();
cmd.Dispose();
cnn.Close();
}
}
cmd.Parameters.AddWithValue("@Num", Convert.ToInt32(No));
cmd.Parameters.AddWithValue("@uID", ID);
cmd.Parameters.AddWithValue("@nTittle", Tittle);
cnn.Open();
cmd.ExecuteNonQuery();
cmd.Dispose();
cnn.Close();
}
}
Y a pesar de estar todo bien, siempre me tiraba una excepción que decía "Syntaxis Error en Insert Into", o cualquier cosa parecida, en la línea cmd.ExecuteNonQuery().
Después de horas depurando y leyendo foros, encontré por ahí un tip clave:
A las bases de datos en Access no les gustan los campos con nombres como "Date", "login" o "Password".
Entonces el error no estaba en mi Insert Into, si no, posiblemente, en los nombres de mis campos.
Hice una pequeña modificación al código (no a la base de datos) y el problema se resolvió maravillosamente:
private void AddDato(string No, string ID, string Tittle, ref OleDbConnection cnn)
{
OleDbCommand cmd = new OleDbCommand(
{
OleDbCommand cmd = new OleDbCommand(
"INSERT INTO miTabla ([No], [un_ID], [Tittle]) VALUES(@Num, @uID, @nTittle)", cnn);
cmd.Parameters.AddWithValue("@Num", Convert.ToInt32(No));
cmd.Parameters.AddWithValue("@uID", ID);
cmd.Parameters.AddWithValue("@nTittle", Tittle);
cnn.Open();
cmd.ExecuteNonQuery();
cmd.Dispose();
cnn.Close();
}
}
cmd.Parameters.AddWithValue("@Num", Convert.ToInt32(No));
cmd.Parameters.AddWithValue("@uID", ID);
cmd.Parameters.AddWithValue("@nTittle", Tittle);
cnn.Open();
cmd.ExecuteNonQuery();
cmd.Dispose();
cnn.Close();
}
}
Dejo como tarea hallar el cambio que hice :)
martes, 18 de enero de 2011
C# usando LastIndexOf y Substring para separar el nombre de un archivo de la ruta donde está almacenado
Ya antes hice lo mismo en VB6. Ahora toca hacerlo desde C#.
Imaginemos que tengo este string que contiene la ruta a un archivo:
unaRuta = "C:\unaCarpeta\otraCarpeta\unArchivo.txt"
Y quisiera separalo en dos strings, con la ruta del archivo y el nombre del archivo por separado:
miRuta = "C:\unaCarpeta\otraCarpeta\"
miArchivo = "unArchivo.txt" El código es el siguiente:
int n = unaRuta.LastIndexOf(@"\"); // la @ es para que considere el "\" como caracter
// se extrae la subcadena desde la primera letra hasta n+1
string miRuta = unaRuta.Substring(0, n + 1);
// se extrae la subcadena desde la letra n+1 hasta el final
string miArchivo = unaRuta.Substring(n + 1);
Suscribirse a:
Entradas (Atom)