Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Duda Windows Forms Con Vs.net 03 Y C#

Iniciado por nsL, 16 de Febrero de 2006, 08:58:00 PM

« anterior - próximo »

nsL

 Acabo de probar el bitblt que me acabas de pasar y funciona perfecto :P . No te puedo decir en cuanto a rendimiento, pues estoy haciendo pruebas con un solo bitmap y no se nota la diferencia de momento.

Respecto a lo del panel hijo. Ya he hecho pruebas y funciona perfecto para que salgan las barras de scroll. De todas formas, ¿como puedo hacer para que no se vea? Si lo pongo invisible deja de haber scroll, y si le pongo color transparente, al mover las barras de scroll se deforma la imagen. Ha de haber alguna forma, o bien de pintar encima de el, o de hacer q no se pinte, pero que este ahi.

Saludos y muchas gracias ;)
Yo no muero hasta la muerte -

zupervaca

 Para que no se vea debes de posicionarlo como te indique, ademas con tamaño 0, 0

Puede que esto vaya mas rapido que la version anterior, es lo mismo salvo que no creas el dc del graphics constantemente:

       // Preparar un graphics para su renderizado mediante DrawBlk
       private void PrepareGraphics(Graphics g, ref IntPtr target, ref IntPtr source)
       {
           target = g.GetHdc();
           source = CreateCompatibleDC(target);
       }

       // Pintar un bloque indicando los minimos atributos
       private void DrawBlk(IntPtr target, IntPtr source, IntPtr bitmap, int x, int y, int width, int height)
       {
           IntPtr oldObj = SelectObject(source, bitmap);
           BitBlt(target, x, y, width, height, source, 0, 0, 0x00CC0020);
           IntPtr newObj = SelectObject(source, oldObj);
           DeleteObject(newObj);
       }

       // Liberar el graphics preparado
       private void ReleasePrepareGraphics(Graphics g, IntPtr target, IntPtr source)
       {
           DeleteDC(source);
           g.ReleaseHdc(target);
       }
Un ejemplo de como utilizarlo:

IntPtr target = (IntPtr)0, source = (IntPtr)0;
PrepareGraphics(g, ref target, ref source);
for( int y = 0; y < 16; y++ )
{
 for( int x = 0; x < 16; x++ )
 {
   this.DrawBlk(target, source, tile.GetHbitmap(), x*tile.Width, y*tile.Height, tile.Width, tile.Height);
 }
}
ReleasePrepareGraphics(g, target, source);


PD: Escribir codigo en este foro es un infierno :angry:  

Vicente

 Hola,

lo que te pasa es que aunque parezca que tu panel es más grande, no lo es, y por eso no fuerza que aparezca el autoscroll (pintar fuera del panel no cambia su tamaño). Si tu imagen es más grande que tu panel (o quieres pintar fuera), tienes que redimensionar tu a mano el tamaño del mismo como te ha dicho Zupervaca (el mismo problema lo tienes en java).

Respecto al docking, se parece al BorderLayout de Java. Indica donde quieres que esté un control respecto a su contenedor. Puede situarlo arriba, abajo, derecha, izquierda o fill (que coja todo el hueco libre). El problema es que si por ejemplo tu formulario es de 500x500, pones un panel en fill (que ocuparía por ejemplo 498x498) y tu vas y lo redimensionas a mano a 1000x1000 (para que aparezcan barras de scroll), pues el docking te lo vuelve a poner de 498x498 (lo mismo con layout).

Pero vamos, que el truco es ese, si quieres pintar algo fuera de tu panel, tu panel tiene que ser más grande (y lo tienes que hacer más grande tu a mano desgraciadamente). Un saludo!

Vicente

nsL

 Ok ok, ya me va quedando todo mas claro :D

Voy a probar a ver estas cosas. Es que cuando me pusiste:

determinatamanio.Bounds = new Rectangle( anchomapa, altomapa, 0, 0);

Pensaba que lo estabas dibujando de la esquina inferior derecha hasta la superior izquierda, de ahi el 0,0, pero resulta q era el tamaño :P

Voy a hacer pruebas a ver q sale.

Gracias a los 2 por vuestro tiempo ;)
Yo no muero hasta la muerte -

Vicente

Cita de: "Vicente"Pero vamos, que el truco es ese, si quieres pintar algo fuera de tu panel, tu panel tiene que ser más grande (y lo tienes que hacer más grande tu a mano desgraciadamente). Un saludo!
Con lo de fuera de tu panel me refería a "fuera del área visible" de tu panel. Un saludo!

Vicente

zupervaca

 No problem si estoy aburrido jeje
Ya que estamos te pongo el codigo para pintar imagenes con el mismo sistema pero indicando un alfa

       private struct AlphaBlendOp
       {
           public byte BlendOp;
           public byte BlendFlags;
           public byte SourceConstantAlpha;
           public byte AlphaFormat;
       }
       [DllImport("Msimg32.dll")]
       private static extern bool AlphaBlend(IntPtr obj, int xDest, int yDest, int widthDest, int heightDest, IntPtr objSource, int xSource, int ySource, int widthSource, int heightSource, AlphaBlendOp blend);
       // Pintar un bloque con mascaraa
       private void DrawBlkMask(IntPtr target, IntPtr source, IntPtr bitmap, int x, int y, int width, int height, AlphaBlendOp blend)
       {
           IntPtr oldObj = SelectObject(source, bitmap);
           AlphaBlend(target, x, y, width, height, source, 0, 0, width, height, blend);
           IntPtr newObj = SelectObject(source, oldObj);
           DeleteObject(newObj);
       }

Y el ejemplo de uso:

               AlphaBlendOp blend;
               blend.BlendOp = 0;// AC_SRC_OVER;
               blend.BlendFlags = 0;
               blend.SourceConstantAlpha = 100; // Intensidad del alfa
               blend.AlphaFormat = 1;// AC_SRC_ALPHA;
               IntPtr target = (IntPtr)0, source = (IntPtr)0;
               PrepareGraphics(g, ref target, ref source);
               this.DrawBlkMask(target, source, tile.GetHbitmap(), 0, 0, tile.Width, tile.Height, blend);
               ReleasePrepareGraphics(g, target, source);

La forma correcta seria hacer una clase GDI32 para no tener los dllimport por ahi perdidos ;), he buscado algo de info por internet y ya hay gente usando este sistema por la lentitud de drawimage.
Otro tema si vas a usar el gdi de win32, creo recordar que la funcion transparentblt del gdi32 tiene un fallo y es que cada vez que se llama no libera bien los recursos del sistema con lo que en vez de usar transparentblt usaria en ese caso la drawimage del .net o haria una atraves de varios bitblt.

Suerte en el proyecto ;)

PD: Pues el tema del panel pense que lo habia hecho en plan guarro, pero esta claro que no soy el unico que encuentra soluciones artesanales (ole)  

nsL

 Jejeje, la verdad que el metodo tiene tela :P

He estado probando cosillas y mi nueva funcion es esta:


 public void assignForm(Panel mainPanel)
 {
  panelHijo = new Panel();
  panelHijo.Location = new System.Drawing.Point(540, 440);
  panelHijo.Name = "panelHijo";
  panelHijo.Size = new System.Drawing.Size(0,0);
  panelHijo.TabIndex = 0;
  mainPanel.Controls.Add(panelHijo);

  imagen = new Bitmap("hola.jpg");

  mainPanel.Paint += new PaintEventHandler(panelPaint);

  Rectangle rect = new Rectangle();
 
  x=0;
  y=0;
  rect.X=x;
  rect.Y=y;
  rect.Height = 100;
  rect.Width = 100;
  mainPanel.Invalidate(rect);

  x=300;
  y=300;
  rect.X=x;
  rect.Y=y;
  mainPanel.Invalidate(rect);
 }


Estoy haciendo la prueba para 2 imagenes. Pero solo me muestra la segunda. No se si es que uso mal el invalidate o que pasa.

Esto sigue siendo igual, a salvedad de que uso tu optima funcion ;):

 public void panelPaint (object sender,PaintEventArgs e)
 {
  this.DrawImage(e.Graphics,imagen, x,y);
 }

x e y son variables private de la clase. Solo se me ocurre q use mal el invalidate con rectangulos. Si lo uso para todo el panel, es decir, mainPanel.invalidate(); tb me muestra solo la segunda imagen :P

Saludos!

PD: En cuanto consiga ordenar todo esto un poco, pruebo tus nuevas funciones de GDI :P
Yo no muero hasta la muerte -

zupervaca

 Prueba a poner dos variables X, Y para dibujar

El problema puede estar en que el evento donde lo haces puede que no vaya bien el invalidate, es decir, despues de hacer tus invalidates hace el otro entero sobre el control.

nsL

 Es que me modifica el valor de las variables antes de entrar a la funcion de pintado. Si pongo esto:

 public void assignForm(Panel mainPanel)
 {
  panelHijo = new Panel();
  panelHijo.Location = new System.Drawing.Point(540, 440);
  panelHijo.Name = "panelHijo";
  panelHijo.Size = new System.Drawing.Size(0,0);
  panelHijo.TabIndex = 0;
  mainPanel.Controls.Add(panelHijo);

  imagen = new Bitmap("hola.jpg");

  mainPanel.Paint += new PaintEventHandler(panelPaint);

  x=0;
  y=0;
             
  mainPanel.Invalidate();

  x=200;
  y=200;
 
//  mainPanel.Invalidate();
 }

Solo repinto despues del primero. Y aun asi me pinta la imagen en la (200,200). Yo no se como estara programado internamente los eventos, pero parece q estuviesen con Threads :P y sigue ejecutando el procedimiento antes de llamar a la rutina del evento, en este caso de pintado.

Saludos!
Yo no muero hasta la muerte -

zupervaca

 Es lo que te comento en el anterior post, despues de ejecutarse la funcion assignForm el dialogo se vuelve a invalidar, ¿podrias poner la funcion desde donde llamas a la funcion assignForm?

nsL

 
 private void menuItem12_Click(object sender, System.EventArgs e)
 {
  Mapa.assignForm(panel1);
 }


Es del menu Archivo del Form principal, del apartado Nuevo.

Claro, seguramente tengas razon. Al ser un menu desplegable que se pinta sobre el panel y demas controles, provocara un invalidate sobre los que se dibuje.

Editado: Acabo de llamar la funcion desde un botn, en vez de un menu y me pasa lo mismo :o
Editado2: Acabo de agregar otro boton, modifique assigForm pa solo pintar una vez y hice una funcion assignForm2 que pinta la segunda imagen. Cada uno de ellos con un invalidate(rect). y va bien. Entoces la pregunta del millon es: ¿Que debo llamar a assignForm varias veces para pintar todas las cosas, en vez de pintar todas las cosas dentro del assigForm? que cosas mas raras :D

Saludos!
Yo no muero hasta la muerte -

zupervaca

 Fijate que en la funcion assignForm estas creando un nuevo panel y esto implica que repinte todo el dialogo ya que deben de recalcularse todos los controles.

nsL

 Aunq ponga en comentarios la creacion de ese panel sucede lo mismo, sigue dibujando en la ultima posicion. Voy a hacer el bucle de pintado fuera del assigForm en vez de dentro, a ver si asi se soluciona el problema. Y si veo que funciona, hago otro metodo de interfaz para el bucle de llamadas pa quede mas curioso y fuera.

En un rato comento a ver qtal :P

Saludos!
Yo no muero hasta la muerte -

nsL

 Na de na, esto es lo que hago ahora y pasa lo mismo...

 public void panelPaint (object sender,PaintEventArgs e)
 {
  this.DrawImage(e.Graphics,imagen, x,y);
 }

 public void configMap(Panel mainPanel)
 {
  panelHijo = new Panel();
  panelHijo.Location = new System.Drawing.Point(540, 440);
  panelHijo.Name = "panelHijo";
  panelHijo.Size = new System.Drawing.Size(0,0);
  panelHijo.TabIndex = 0;
  mainPanel.Controls.Add(panelHijo);
  imagen = new Bitmap("hola.jpg");
  mainPanel.Paint += new PaintEventHandler(panelPaint);
 }

 public void drawTile(Panel mainPanel,int posX, int posY)
 {
  Rectangle rect = new Rectangle();
  x=posX;
  y=posY;
  rect.X=x;
  rect.Y=y;
  rect.Height=100;
  rect.Width=100;

    mainPanel.Invalidate(rect);
 }


  private void button1_Click(object sender, System.EventArgs e)
  {
   Mapa.configMap(panel1);
   Mapa.drawTile(panel1,0,0);
   Mapa.drawTile(panel1,200,200);
  }


Y pasa lo mismo.  Solo funciona cuando hago las llamas a DrawTile (q es el que hace el invalidate) desde sitios distintos. Si estan en la misma funcion, en este caso la funcion de evento de click al boton, pues solo funciona la ultima. SOCORROOOOO jejeje

Saludos!
Yo no muero hasta la muerte -

zupervaca

 Date cuenta que en la funcion button1_Click estas llamando Mapa.configMap que crea el el panel y este hace un invalidate de todo el control o dialogo.
Debes saber que la funcion invalidate no repinta al momento, es decir, deja en la cola de mensajes del dialogo un mensaje indicando que debe de repintarse esa zona, esa cola de mensajes solo es tratada despues de salir de la funcion button1_Click, con lo que pasa esto:

- Al crear el panel se agrega a la cola de mensajes un invalidate de todo el control
- Al dibujar creas un invalidate de la zona que quieres
- Al dibujar otra vez creas un invalidate de la zona que quieres
- Se tratan los mensajes
  - Primer invalidate que repinta todo, pinta la imagen en las coordenadas X e Y, las ultimas que indicaste
  - Segundo invalidate, repinta la parte del control, como las coordenas X e Y son las del ultimo que indicaste no pinta nada
  - Tercer invalidate, repinta la parte del control, las coordenadas X e Y son correctas y pinta otra vez la imagen en esa posicion

Como ves el problema esta que en el invalidate no hace que pinte de forma inmediata.






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.