La batallita del agüelo
Pues eso... que por "necesidad" me he tenido que fabricar una utilidad que
capture la pantalla completa o la ventana que tenga el foco.
Y esa necesidad viene de la mano del sistema operativo que estoy usando
ahora, que es el Windows Server 2008 RC1 de 64 bits, y en el Windows Server
2008 no existe la utilidad Snipping
Tool que es la que podemos usar en Windows Vista para realizar capturas de
la pantalla. (Recuerda que Windows Server 2008 es como el hermano "serio" de
Windows Vista.)
Por supuesto, ni esa utilidad está en mi sistema, ni tampoco ningún otro
programa que me permita hacer capturas, ya que en el otro equipo que tengo
con el Windows Vista Ultimate, la herramienta que uso para hacer las
capturas es el
Corel Paint Shop Pro Photo X2 (o el PSP 12), que también uso para editar
las fotos.
Así que... me dije... pues hagamos una utilidad para capturar la
pantalla... y en vez de ponerme a hacer pruebas, busqué en mi sitio, cosa
que tenías que hacer cada vez que necesites algún código, ya que, casi
seguro, que lo que busques está en el sitio del Guille, ya sea porque lo he
publicado yo o porque algún colaborador lo haya hecho, y esa búsqueda me
mostró un artículo del colega Miliuco:
Captura
de pantalla.
Así que, me fijé en cómo capturaba él las pantallas y use ese código.
Por supuesto lo he adaptado a "mis gustos", pero la "base" de todo es la
llamada al método
SendWait de la clase SendKeys, y particularmente
el parámetro que indica que queremos capturar la pantalla, que no es otro
que el envío de la tecla Print Screen o Impr Pant, que se indica con la
cadena {PRTSC}.
Inicialmente lo hice para que capturara la imagen y la guardara en el
portapapeles, con idea de posteriormente usar un programa (el Paint, por
ejemplo) y pegar esa imagen para después guardarla.
Pero hace un rato me dije (sí, es que
hablo yo conmigo mismo y me digo cosas, je, je), pues... ¿por qué no
guardar directamente lo capturado? o mejor aún, ¿por qué no poder ver
lo capturado y después decidir si lo quiero guardar o no?
Y eso es lo que he hecho, crear un formulario de "previsualización", muy
simple, pero totalmente funcional. Ahora te muestro cómo es ese formulario.
La utilidad para capturar la pantalla o ventana activa
No me voy a enrollar demasiado, así que iré al grano.
La pantalla principal es muy simple (ver la figura 1), ya que solo tiene
tres botones y un NumericUpDown.
El control NumericUpDown sirve para indicar el retardo que
queremos dar para realizar la captura (ya que si la captura la hiciéramos
directamente, pues la ventana activa siempre sería nuestra aplicación). Las
capturas se guardan en el portapapeles, con idea de poder pegarlo en
cualquier aplicación que "entienda" de gráficos.
Dos de los botones sirven para indicar qué es lo que queremos capturar, y el
tercero servirá para mostrar lo que hay capturado. Este botón se habilitará
solo si se ha podido capturar, es decir, si hay alguna imagen en el
portapapeles, esa comprobación también se hace al iniciarse la aplicación,
por tanto, si en el portapapeles hay una imagen, la podremos ver con esta
utilidad.
Figura 1. La ventana principal (en ejecución)
Debido a que la utilidad esta la podemos usar en un Windows Vista, el
icono ese que hay en la parte inferior derecha nos avisa si estamos
ejecutando la aplicación como administrador (icono verde, tal como se
muestra en la figura 1) o un icono naranja (de advertencia). Esto lo he
hecho porque en ocasiones, si quieres capturar una ventana que está
ejecutándose como administrador solamente podrás hacerlo si el programa se
ejecuta también como administrador. En el caso de la captura de la pantalla
completa, si hay una aplicación que se está ejecutando como administrador
tampoco se capturará... salvo que la utilidad también se ejecute como
administrador. Por supuesto esto es solo aplicable en Windows Vista.
Si la utilidad se ejecuta como administrador, siempre podrá capturar todo lo
que haya, se esté ejecutando como se esté ejecutando. El único caso curioso
es al intentar capturar una imagen (máquina virtual) de Smartphone, que no
la copiaba ni en modo ventana ni en modo pantalla completa... en fin...
Una vez que hemos hecho una captura, podemos mostrarla en una ventana
aparte, por ejemplo en la figura 2 tenemos una captura de esa ventana
mostrando algo capturado.
Figura 2. La ventana de mostrar las capturas
Esta ventana tiene tres botones, dos de ellos sirven para la forma de
mostrar la imagen, el primero es para el tamaño normal, en ese caso se
muestran las barras de desplazamiento con idea de que puedas ver el resto de
la imagen. El otro botón es para hacer un Stretch, es decir, para mostrar la
captura completa, pero encajándola en el picture (o la ventana).
El tercer botón nos permite guardar la imagen en uno de los formatos
soportados por la clase Image, esos tipos de imágenes son
los formatos que define la clase ImageFormat (definida
en System.Drawing.Imaging).
El formulario que muestra las capturas se muestra por medio de
Show (en vez de ShowDialog) y sin usar la
instancia predeterminada que crea Visual Basic a la que podemos acceder por
medio del nombre del formulario o usando My.Forms.
Esto es para que se puedan abrir varios formularios con varias capturas, de
forma que no tengamos que guardarla antes de tomar la siguiente, sino que
podemos capturar, mostrar la captura realizada y seguir capturando más
cosas.
Algunas cosas interesantes del código de esta utilidad
Si miras la documentación de Visual Studio buscando una propiedad para
mostrar las barras de desplazamiento (scroll) en un control
PictureBox, no busques, porque no tiene esa propiedad (al menos en
el .NET 2.0).
Para mostrar las barras de scroll en el caso de que la imagen sea más
grande que la ventana, lo que he hecho es poner el control
PictureBox (picClipB) dentro de un panel (panelPic).
Ese panel tiene un valor True en la propiedad
AutoScroll y la propiedad Dock con un valor
Fill, con idea de que ocupe toda la pantalla... y eso es lo
que hacía... ¡ocupar toda la ventana! Tanto ocupaba, que se ponía detrás del
ToolStrip de la botonera, impidiendo ver la parte superior
de la imagen.
¿Solución? Poner el ToolStrip dentro de otro panel,
acoplado a la parte de arriba, y así se ajusta el panel de la imagen al
resto de la ventana... cosas que pasan con esto del "docking", en fin...
En la figura 3 puedes ver la ventana del "Document Outline"
en el que se aprecia que el ToolStrip está dentro de un
panel, lo mismo que el PictureBox está dentro de otro.
Figura 3. Con el Document Outline podemos ver qué controles están dentro de
otros
El problema es que ese scroll no se mostraba... ¡jooorrrr! ¿y ahora qué?
Pues... si el scroll aparece cuando lo que tiene dentro es más grande que lo
que se muestra... la solución es hacer crecer la imagen, es decir, no
dejarla con el tamaño que tuviera.
Para que la imagen crezca al tamaño que tiene la imagen lo podemos hacer
de dos formas:
1- Dejando el valor de la propiedad SizeMode del PictureBox en
Normal y
asignando al PictureBox el tamaño de la imagen:
picClipB.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Normal
' Cambiar el tamaño del pictureBox
' para que se muestre el scroll del contenedor si fuera necesario
picClipB.Size = picClipB.Image.Size
2- Asignando el valor AutoSize a la propiedad SizeMode, ya que de esta
forma el PictureBox se redimensiona automáticamente al tamaño de la imagen
que está mostrando:
picClipB.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize
En cualquiera de los dos casos, tenemos que indicarle al panel que sea
del mismo tamaño que la imagen, con idea de que muestre las barras de
desplazamiento:
panelPic.Size = picClipB.Size
Para comprobar si hay imagen en el portapapeles y para copiar la imagen,
he usado el objeto My.Computer.Clipboard.
Para saber si hay una imagen, lo compruebo por medio del método
ContainsImage, y para recuperar la imagen del portapapeles, he
usado el método GetImage.
Nota:
Decir que el objeto My.Computer.Keyboard define un método
SendKeys similar al de la clase SendKeys,
pero en este ejemplo he usado la clase del .NET Framework en vez del objeto
definido en My.
Más abajo tienes el código de los dos formularios, así como
el ZIP con el
proyecto completo para Visual Basic 2008, pero aunque esté creado con el
Visual Basic 2008, no utiliza nada de lo incluido en el .NET Framework 3.5,
además de que le he indicado que use el .NET Framework 2.0, por tanto,
podrás usar directamente el ejecutable si ya tienes el runtime del .NET
Framework 2.0 instalado.
Nota si quieres usar el proyecto desde Visual Basic
2005:
El código en sí te servirá también para Visual Basic 2005, pero no el
fichero del proyecto. Si quieres usarlo con Visual Basic 2005, tendrás que
quitar algunas líneas del fichero de proyecto (.vbpoj) o bien crear un nuevo
proyecto con Visual Basic 2005, añadir las imágenes como recursos y añadir
los dos formularios al proyecto que acabas de crear (te dirá si quieres
sobrescribir el Form1, le dices que sí).
Espero que te sea de utilidad.
Nos vemos.
Guillermo