Tengo un DatagridView llamado dgView como el siguiente:
El DataGridView tiene su propiedad SelectMode igual a FullRowSelect.
Las filas no contienen datos únicos y, en otra parte del programa, cambio su propiedad Multiselect de true a false y viceversa.
Al cambiar el valor de la propiedad Multiselect, la fila o filas seleccionadas se deseleccionan (se pierde la selección), además el usuario puede hacer click en las cabeceras de las columnas lo cual cambia el orden y los índices de las filas (hacer click en las cabeceras de las columnas no deselecciona ninguna fila).
Lo que deseo hacer es que la última fila seleccionada por el usuario siempre se mantenga seleccionada a pesar de que se haga click en las cabeceras de las columnas y la filas ya no estén en el mismo orden, y se cambie el valor de MultiSelect (u otra propiedad que haga que se pierda la selección).
Para lograr esto hay que considerar tres eventos del DataGridView: CellMouseDown, CellMouseUp y SelectionChanged.
El código es:
int selectedIndex;
private void dgView_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (dgView.Rows.Count > 0 && dgView.SelectedRows.Count >= 1)
selectedIndex = dgView.SelectedRows[0].Index;
}
private void dgView_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
{
if (dgView.Rows.Count > 0 && dgView.SelectedRows.Count >= 1)
selectedIndex = dgView.SelectedRows[0].Index;
}
private void dgView_SelectionChanged(object sender, EventArgs e)
{
if (dgView.Rows.Count > 0 && dgView.SelectedRows.Count >= 1)
selectedIndex = dgView.SelectedRows[0].Index;
}
Para restablecer la fila seleccionada se debe poner el siguiente código en donde se cambia la propiedad Multiselect de dgView, ó después de cualquier código que haga que se pierda la selección:
dgView.Rows[selectedIndex].Selected = true;
Programación a Martillazos
martes, 11 de junio de 2013
jueves, 18 de abril de 2013
Calcular los n primeros elementos del Conjunto de Wirth
Me encontré con este problema revisando la página de PuntoPeek. Aquí copio la definición del Conjunto de Wirth:
"El conjunto de Wirth es un subconjunto de los enteros positivos que cumple con la siguiente regla: el 1 pertenece al conjunto y si un numero k pertenece al conjunto entonces los numeros 2*k+1 y 3*k+1 pertenecen al conjunto."
En un primer vistazo parecía un problema que podría resolverse con un bucle, pero en realidad es bastante más complicado:
Empiezo con 1 y calculo los siguientes dos números: 2*1+1=3 y 3*1+1=4.
Mi conjunto por ahora es: [1, 3, 4]
Los siguientes dos números son: 3*2+1=7 y 3*3+1=10
Los otros dos siguientes son: 4*2+1=9 y 4*3+1=13
Mi conjunto ahora es: [1, 3, 4, 7, 10, 9, 13]
Calculo los dos siguientes: 7*2+1=15 y 7*3+1=22
Mi conjunto ahora es: [1, 3, 4, 7, 10, 9, 13, 15, 22]
Calculo los dos siguientes: 10*2+1=21 y 10*3+1=31
Mi conjunto ahora es: [1, 3, 4, 7, 10, 9, 13, 15, 22, 21, 31]
Calculo los dos siguientes: 9*2+1=19 y 9*3+1=28
Mi conjunto ahora es: [1, 3, 4, 7, 10, 9, 13, 15, 22, 21, 31, 19, 28]
Se puede notar que los números del conjunto de Wirth no se generan de modo ascendente, si no que el conjunto se va "rellenando" a medida que se hacen más y más cálculos. Un simple bucle que calcule los 5 primeros números del conjunto de Wirth nos dará [1, 3, 4, 7, 10] cuando la respuesta correcta es [1, 3, 4, 7, 9]. El error se hace más grande con cantidades mayores.
Otro problema es que se generan números repetidos, por ejemplo en el caso de 10*3+1 y 15*2+1.
Considerando esto, se puede comprobar que varias de la respuestas dadas en esta web son erróneas.
Para evitar el caso de números faltantes, mi algoritmo calcula el doble de los números requeridos, además de comprobar que no estén repetidos, ordena el array resultante y sólo muestra la cantidad de números solicitada.
Este es el código en Python:
def Wirth(i, n, w, k):
if n == 1:
return 0
else:
k = w[i]
t = 2*k + 1
if t not in w:
w.append(t)
t = 3*k + 1
if t not in w:
w.append(t)
return Wirth(i+1, n-1, w, k)
w=[1]
n=50
Wirth(0, n*2, w, 1)
w.sort()
w = w[0 : n]
print w
Y en C# usando Linq:
class Program
{
static int Wirth(int i, int n, ref int[] w, int k, int count)
{
if (n == 0 || count >= w.Length)
return 0;
else
{
k = w[i];
int t = 2 * k + 1;
if (!w.Any(c => c == t))
{
count++;
w[count] = t;
}
t = 3 * k + 1;
if (!w.Any(c => c == t))
{
count++;
w[count] = t;
}
return Wirth(i + 1, n - 1, ref w, k, count);
}
}
static void Main(string[] args)
{
int n = 50;
int[] w = Enumerable.Repeat(0, n * 2).ToArray();
w[0] = 1;
Wirth(0, n, ref w, 1, 0);
w = w.Where(c => c != 0).OrderBy(c => c).ToArray();
for (int i = 0; i < n; i++)
Console.WriteLine(w[i]);
Console.Read();
}
}
Y obtengo la misma respuesta que PuntoPeek, cuya solución me ha gustado, es bastante elegante :D
"El conjunto de Wirth es un subconjunto de los enteros positivos que cumple con la siguiente regla: el 1 pertenece al conjunto y si un numero k pertenece al conjunto entonces los numeros 2*k+1 y 3*k+1 pertenecen al conjunto."
En un primer vistazo parecía un problema que podría resolverse con un bucle, pero en realidad es bastante más complicado:
Empiezo con 1 y calculo los siguientes dos números: 2*1+1=3 y 3*1+1=4.
Mi conjunto por ahora es: [1, 3, 4]
Los siguientes dos números son: 3*2+1=7 y 3*3+1=10
Los otros dos siguientes son: 4*2+1=9 y 4*3+1=13
Mi conjunto ahora es: [1, 3, 4, 7, 10, 9, 13]
Calculo los dos siguientes: 7*2+1=15 y 7*3+1=22
Mi conjunto ahora es: [1, 3, 4, 7, 10, 9, 13, 15, 22]
Calculo los dos siguientes: 10*2+1=21 y 10*3+1=31
Mi conjunto ahora es: [1, 3, 4, 7, 10, 9, 13, 15, 22, 21, 31]
Calculo los dos siguientes: 9*2+1=19 y 9*3+1=28
Mi conjunto ahora es: [1, 3, 4, 7, 10, 9, 13, 15, 22, 21, 31, 19, 28]
Se puede notar que los números del conjunto de Wirth no se generan de modo ascendente, si no que el conjunto se va "rellenando" a medida que se hacen más y más cálculos. Un simple bucle que calcule los 5 primeros números del conjunto de Wirth nos dará [1, 3, 4, 7, 10] cuando la respuesta correcta es [1, 3, 4, 7, 9]. El error se hace más grande con cantidades mayores.
Otro problema es que se generan números repetidos, por ejemplo en el caso de 10*3+1 y 15*2+1.
Considerando esto, se puede comprobar que varias de la respuestas dadas en esta web son erróneas.
Para evitar el caso de números faltantes, mi algoritmo calcula el doble de los números requeridos, además de comprobar que no estén repetidos, ordena el array resultante y sólo muestra la cantidad de números solicitada.
Este es el código en Python:
def Wirth(i, n, w, k):
if n == 1:
return 0
else:
k = w[i]
t = 2*k + 1
if t not in w:
w.append(t)
t = 3*k + 1
if t not in w:
w.append(t)
return Wirth(i+1, n-1, w, k)
w=[1]
n=50
Wirth(0, n*2, w, 1)
w.sort()
w = w[0 : n]
print w
Y en C# usando Linq:
class Program
{
static int Wirth(int i, int n, ref int[] w, int k, int count)
{
if (n == 0 || count >= w.Length)
return 0;
else
{
k = w[i];
int t = 2 * k + 1;
if (!w.Any(c => c == t))
{
count++;
w[count] = t;
}
t = 3 * k + 1;
if (!w.Any(c => c == t))
{
count++;
w[count] = t;
}
return Wirth(i + 1, n - 1, ref w, k, count);
}
}
static void Main(string[] args)
{
int n = 50;
int[] w = Enumerable.Repeat(0, n * 2).ToArray();
w[0] = 1;
Wirth(0, n, ref w, 1, 0);
w = w.Where(c => c != 0).OrderBy(c => c).ToArray();
for (int i = 0; i < n; i++)
Console.WriteLine(w[i]);
Console.Read();
}
}
Y obtengo la misma respuesta que PuntoPeek, cuya solución me ha gustado, es bastante elegante :D
jueves, 11 de abril de 2013
VB6: Cómo saber si existe una webcam conectada a la PC
Primero declaramos las funciones SendMessage y capCreateCaptureWindow (si se declaran en un módulo .bas las declaraciones deben ser públicas, para este ejemplo asumiremos que todo el código está dentro de un Form):
Private Declare Function capCreateCaptureWindow Lib "avicap32.dll" _
Alias "capCreateCaptureWindowA" ( _
ByVal lpszWindowName As String, _
ByVal dwStyle As Long, _
ByVal x As Long, _
ByVal y As Long, _
ByVal nWidth As Long, _
ByVal nHeight As Long, _
ByVal hwndParent As Long, _
ByVal nID As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
lParam As Any) As Long
Private Const CONNECT As Long = 1034
El código que nos dice si hay una webcam conectada es:
Dim mCapHwnd as Long
mCapHwnd = capCreateCaptureWindowA("WebCap", 0, 0, 0, 320, 240, Me.hwnd, 0)
DoEvents
If SendMessage(mCapHwnd, CONNECT, 0, 0) <> 0 Then
MsgBox "Se ha detectado una webcam conectada y lista para usarse"
Else
MsgBox "No se ha detectado una webcam"
End If
Private Declare Function capCreateCaptureWindow Lib "avicap32.dll" _
Alias "capCreateCaptureWindowA" ( _
ByVal lpszWindowName As String, _
ByVal dwStyle As Long, _
ByVal x As Long, _
ByVal y As Long, _
ByVal nWidth As Long, _
ByVal nHeight As Long, _
ByVal hwndParent As Long, _
ByVal nID As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
lParam As Any) As Long
Private Const CONNECT As Long = 1034
El código que nos dice si hay una webcam conectada es:
Dim mCapHwnd as Long
mCapHwnd = capCreateCaptureWindowA("WebCap", 0, 0, 0, 320, 240, Me.hwnd, 0)
DoEvents
If SendMessage(mCapHwnd, CONNECT, 0, 0) <> 0 Then
MsgBox "Se ha detectado una webcam conectada y lista para usarse"
Else
MsgBox "No se ha detectado una webcam"
End If
Etiquetas:
VB6,
Windows Api
miércoles, 27 de marzo de 2013
Code Snippet: Pequeño ejemplo del uso de Linq.Any
Definición de Linq.Any extraído de esta web:
"El operador Any se utiliza para determinar si existe un elemento dentro de una secuencia que cumpla una condición expecífica."
Pero lo que yo necesitaba era un ejemplo concreto para saber si un elemento no existe en una colección usando Linq.Any.
El siguiente código muestra cómo usar Linq.Any para saber si un elemento existe o no en una colección. Es autoexplicativo:
using System;
using System.Linq;
using System.Collections.Generic;
namespace LinqPractice
{
class Program
{
static void Main(string[] args)
{
IEnumerable mis_nums = Enumerable.Range(0, 4);
mis_nums = mis_nums.Select(c => c * 3);
// mis_nums = {0, 3, 6, 9}
if (mis_nums.Any(c => c != 7))
Console.WriteLine("Existe al menos un número que es diferente de 7");
if (mis_nums.Any(c => c == 9))
Console.WriteLine("El 9 sí existe en la colección");
else
Console.WriteLine("El 9 no existe en la colección");
if (!mis_nums.Any(c => c == 7))
Console.WriteLine("El 7 no existe en la colección");
else
Console.WriteLine("El 7 sí existe en la colección");
Console.Read();
}
}
}
El resultado es:
"El operador Any se utiliza para determinar si existe un elemento dentro de una secuencia que cumpla una condición expecífica."
Pero lo que yo necesitaba era un ejemplo concreto para saber si un elemento no existe en una colección usando Linq.Any.
El siguiente código muestra cómo usar Linq.Any para saber si un elemento existe o no en una colección. Es autoexplicativo:
using System;
using System.Linq;
using System.Collections.Generic;
namespace LinqPractice
{
class Program
{
static void Main(string[] args)
{
IEnumerable
mis_nums = mis_nums.Select(c => c * 3);
// mis_nums = {0, 3, 6, 9}
if (mis_nums.Any(c => c != 7))
Console.WriteLine("Existe al menos un número que es diferente de 7");
if (mis_nums.Any(c => c == 9))
Console.WriteLine("El 9 sí existe en la colección");
else
Console.WriteLine("El 9 no existe en la colección");
if (!mis_nums.Any(c => c == 7))
Console.WriteLine("El 7 no existe en la colección");
else
Console.WriteLine("El 7 sí existe en la colección");
Console.Read();
}
}
}
El resultado es:
Etiquetas:
Linq C#
lunes, 11 de marzo de 2013
Visual C++: Cómo hacer que una ventana aparezca maximizada al cargarla
Para una aplicación tipo Win32 se debe buscar en la función Initinstance la línea donde dice ShowWindow:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Almacenar identificador de instancia en una variable global
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
return FALSE;
// Visual C++ nos crea esta línea:
// ShowWindow(hWnd, nCmdShow);
// debemos reemplazarla por esta otra línea:
ShowWindow(hWnd, SW_MAXIMIZE);
UpdateWindow(hWnd);
return TRUE;
}
Los valores del parámetro que se le pasa a la api ShowWindow están declarados en WinUser.h y son los siguientes:
#define SW_HIDE 0
#define SW_SHOWNORMAL 1
#define SW_NORMAL 1
#define SW_SHOWMINIMIZED 2
#define SW_SHOWMAXIMIZED 3
#define SW_MAXIMIZE 3
#define SW_SHOWNOACTIVATE 4
#define SW_SHOW 5
#define SW_MINIMIZE 6
#define SW_SHOWMINNOACTIVE 7
#define SW_SHOWNA 8
#define SW_RESTORE 9
#define SW_SHOWDEFAULT 10
#define SW_FORCEMINIMIZE 11
#define SW_MAX 11
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Almacenar identificador de instancia en una variable global
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
return FALSE;
// Visual C++ nos crea esta línea:
// ShowWindow(hWnd, nCmdShow);
// debemos reemplazarla por esta otra línea:
ShowWindow(hWnd, SW_MAXIMIZE);
UpdateWindow(hWnd);
return TRUE;
}
Los valores del parámetro que se le pasa a la api ShowWindow están declarados en WinUser.h y son los siguientes:
#define SW_HIDE 0
#define SW_SHOWNORMAL 1
#define SW_NORMAL 1
#define SW_SHOWMINIMIZED 2
#define SW_SHOWMAXIMIZED 3
#define SW_MAXIMIZE 3
#define SW_SHOWNOACTIVATE 4
#define SW_SHOW 5
#define SW_MINIMIZE 6
#define SW_SHOWMINNOACTIVE 7
#define SW_SHOWNA 8
#define SW_RESTORE 9
#define SW_SHOWDEFAULT 10
#define SW_FORCEMINIMIZE 11
#define SW_MAX 11
Etiquetas:
Visual C++,
Windows Api
viernes, 22 de febrero de 2013
Algoritmo para obtener números primos de una forma funcional
Todo empezó cuando me puse a aprender Python (debido a que este curso requiere programar en ese lenguaje) utilizando Python Tools for Visual Studio. Primero debe bajarse e instalarse el Interpreter y, si no se tiene el Visual Studio, o se tiene la versión Express, hay que instalar The Visual Studio 2010 Shell Redistributable Package, y al final instalar Python Tools. Como resultado, tenemos un Python Express :D
Buscando tutoriales. hallé que en esta web proponían el siguiente método para obtener números primos (llamado "El Colador de Eratósthenes", no es el método más eficiente):
nums = range(2, 50)
for i in range(2, 8):
nums = filter(lambda x: x == i or x % i, nums)
Luego el autor dice: "No sé de algún lenguaje que pueda hacer lo mismo con sus características propias de una forma tan compacta y legible como en Python (excepto para lenguajes funcionales)".
¡Sorpresa! En C# sí se puede:
int[] nums = Enumerable.Range(2, 48).ToArray();
for (int i = 2; i < 8; i++)
nums = nums.Where(c => c == i || c % i != 0).ToArray();
Sólo hay que importar los espacios de nombres System y System.Linq.
:D
Buscando tutoriales. hallé que en esta web proponían el siguiente método para obtener números primos (llamado "El Colador de Eratósthenes", no es el método más eficiente):
nums = range(2, 50)
for i in range(2, 8):
nums = filter(lambda x: x == i or x % i, nums)
Luego el autor dice: "No sé de algún lenguaje que pueda hacer lo mismo con sus características propias de una forma tan compacta y legible como en Python (excepto para lenguajes funcionales)".
¡Sorpresa! En C# sí se puede:
int[] nums = Enumerable.Range(2, 48).ToArray();
for (int i = 2; i < 8; i++)
nums = nums.Where(c => c == i || c % i != 0).ToArray();
Sólo hay que importar los espacios de nombres System y System.Linq.
:D
lunes, 21 de enero de 2013
Tutorial: Creando una DLL en Visual C++ 2010 y Usándola en una Aplicación en C#
Electrónica a Martillazos, actualización de la sección de VB6 y C++:
Creando una DLL en Visual C++ 2010 y Usándola en una Aplicación en C#.
Link directo
Un mirror
:D
Creando una DLL en Visual C++ 2010 y Usándola en una Aplicación en C#.
Link directo
Un mirror
:D
Suscribirse a:
Entradas (Atom)

