FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

DCs

 
Post new topic   Reply to topic     Forum Index -> DFL
View previous topic :: View next topic  
Author Message
jvr



Joined: 19 Nov 2007
Posts: 10

PostPosted: Wed Dec 19, 2007 12:03 pm    Post subject: DCs Reply with quote

Hi,

There is a problem in DFL with the device contexts (DC) in Win95/98/ME, the DCs should be created just before any painting operation and released immediately.
It's a source of problems to create a DC and save it as a class member.
It seems that -at least- MemoryGraphics/Graphics creates the DC in its constructor and release it in the destructor, this works in NT/2K/XP but it doesn't work in Win9x, (play with one or two dozens of MemoryGraphics in Win9x and you'll see the effects).

This is not a problem in 2K/NT/XP (it only happens in extreme cases), but in Win9x/ME the DCs are very limited;
from MSDN: "Windows 95/98/Me: There are only 5 common DCs available per thread, thus failure to release a DC can prevent other applications from accessing one".
http://msdn2.microsoft.com/en-us/library/ms533241.aspx

Cheers,

Javi
Back to top
View user's profile Send private message
Chris Miller



Joined: 27 Mar 2004
Posts: 514
Location: The Internet

PostPosted: Wed Dec 19, 2007 2:32 pm    Post subject: Re: DCs Reply with quote

The Graphics objects are "scope" allocated, which means they are destructed once execution leaves its scope, which should be sufficient. Did you run into real problems? I've tested DFL on Windows 9x in the past and the DCs were fine.
Back to top
View user's profile Send private message
jvr



Joined: 19 Nov 2007
Posts: 10

PostPosted: Wed Dec 19, 2007 4:18 pm    Post subject: Re: DCs Reply with quote

Yes, I've programmed a class of skin buttons, and each object has 4 MemoryGraphics (to hold the generated button images of up, down, selected and disabled), in the mouse event functions -mouseEnter, mouseDown, etc.- these images are copied (copyTo()) to the PictureBox that represents each button. It runs perfectly on XP but in Win9x there are no enough free DCs and only 3 o 4 buttons are displayed correctly.

Here you have the source code if you want to check it:

Code:

module skinbutton;

import dfl.all;


class SkinButton
{
private:
  const char[] RESOURCE_STR = "SKINBUTTON_";
  PictureBox m_picbox;
  Graphics m_picbox_gfx;
  MemoryGraphics m_mem_gfx_up;
  MemoryGraphics m_mem_gfx_down;
  MemoryGraphics m_mem_gfx_high;
  MemoryGraphics m_mem_gfx_disable;
  bool m_enable;
  int m_width;
  int m_height;
  Font m_font;
  char[] m_text;
  Icon m_icon;
  char[] m_icon_name;
  uint m_icon_pos;
  void delegate() m_callback_click;
  bool m_keep_pushed;

 
  void Paint(Object sender, EventArgs ea)
  {
    // Repintar el boton pulsado o normal, activado/desactivado?
    if(m_keep_pushed)
    {
      if(m_enable)
      {
        m_mem_gfx_down.copyTo(m_picbox_gfx, 0, 0, m_width, m_height);
      }
      else
      {
        m_mem_gfx_disable.copyTo(m_picbox_gfx, 0, 0, m_width, m_height);
      }
     
    }
    else
    {
      if(m_enable)
      {
        m_mem_gfx_up.copyTo(m_picbox_gfx, 0, 0, m_width, m_height);
      }
      else
      {
        m_mem_gfx_disable.copyTo(m_picbox_gfx, 0, 0, m_width, m_height);
      }
    }
  }
 
  void MouseEnter(Object sender, EventArgs ea)
  {
    // Poner imagen high si el boton no esta pulsado y esta activado
    if(!m_keep_pushed && m_enable)
    {
      m_mem_gfx_high.copyTo(m_picbox_gfx, 0, 0, m_width, m_height);
    }
  }

  void MouseLeave(Object sender, EventArgs ea)
  {
    // Poner imagen up si el boton no esta pulsado y esta activado
    if(!m_keep_pushed && m_enable)
    {
      m_mem_gfx_up.copyTo(m_picbox_gfx, 0, 0, m_width, m_height);
    }
  }

  void MouseDown(Object sender, EventArgs ea)
  {
    // Poner imagen down al pulsar el boton
    if(m_enable && (cast(MouseEventArgs)ea).button == MouseButtons.LEFT)
    {
      m_mem_gfx_down.copyTo(m_picbox_gfx, 0, 0, m_width, m_height);
    }
  }

  void MouseUp(Object sender, EventArgs ea)
  {
    // Llamar a la funcion si el boton esta activado
    if(m_callback_click !is null && m_enable && (cast(MouseEventArgs)ea).button == MouseButtons.LEFT)
    {
      m_callback_click();
    }

    // Poner imagen high si el boton no esta pulsado y esta activado,
    // y si el puntero del raton sigue encima del boton.
    Point mouse = m_picbox.pointToClient(m_picbox.mousePosition());
    if(!m_keep_pushed && m_enable && (cast(MouseEventArgs)ea).button == MouseButtons.LEFT &&
       mouse.x < m_width && mouse.y < m_height)
    {
      m_mem_gfx_high.copyTo(m_picbox_gfx, 0, 0, m_width, m_height);
    }
  }

 
public:
  this(char[] text, Control parent, void delegate() on_click, Rect bounds,
       uint resource_button=0, char[] resource_icon=null, uint icon_pos=0,
       Font font=null, bool enable=true, bool keep_pushed=false)
  {
    // Nombre inicial de los bmps de recurso a cargar
    char[] resource_bmps = RESOURCE_STR ~ std.string.toString(resource_button) ~ "_";
   
    // Funcion callback de click
    m_callback_click = on_click;
   
    // Mantener pulsado?
    m_keep_pushed = keep_pushed;
   
    // Estado
    m_enable = enable;
   
    // Icono?
    m_icon_name = resource_icon;
    m_icon_pos = icon_pos; // 0 arriba, 1 izquierda
    if(m_icon_name !is null)
    {
      m_icon = Application.resources.loadIcon(m_icon_name);
    }
   
    // Fuente
    if(font is null)
    {
      // Fuente standard
      m_font = new Font("MS Sans Serif", 9f, FontStyle.REGULAR);
    }
    else
    {
      m_font = font;
    }
    m_text = text;
   
    // Crear PictureBox
    m_picbox = new PictureBox();
    m_picbox.name = "SkinButton";
    m_picbox.bounds = bounds;
    m_picbox.parent = parent;

    // Crear bitmaps del boton
    m_picbox_gfx = m_picbox.createGraphics();     
    m_width  = m_picbox.width;
    m_height = m_picbox.height;
    m_mem_gfx_up      = new MemoryGraphics(m_width, m_height);
    m_mem_gfx_down    = new MemoryGraphics(m_width, m_height);
    m_mem_gfx_high    = new MemoryGraphics(m_width, m_height);
    m_mem_gfx_disable = new MemoryGraphics(m_width, m_height);

    /*------------------------------------------------------------
      Boton normal (UP)
    ------------------------------------------------------------*/
    // Rellenar bitmap borde superior
    Bitmap bmp = Application.resources.getBitmap(resource_bmps ~ "UP_UP");
    for(uint x=0; x < m_width; x++)
    {
      bmp.draw(m_mem_gfx_up, Point(x, 0));
    }
   
    // Rellenar bitmap central
    int up_bmp_h = bmp.height;
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_CENTER");
    for(uint x=0; x < m_width; x++)
    {
      bmp.draw(m_mem_gfx_up, Point(x, up_bmp_h));
    }

    // Rellenar bitmap borde inferior
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_DOWN");
    for(uint x=0; x < m_width; x++)
    {
      bmp.draw(m_mem_gfx_up, Point(x, m_height-bmp.height));
    }

    // Rellenar bitmap borde izquierdo
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_LEFT");
    for(uint y=0; y < m_height; y++)
    {
      bmp.draw(m_mem_gfx_up, Point(0, y));
    }

    // Rellenar bitmap borde derecho
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_RIGHT");
    for(uint y=0; y < m_height; y++)
    {
      bmp.draw(m_mem_gfx_up, Point(m_width-bmp.width, y));
    }
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_UP_LEFT");
    bmp.draw(m_mem_gfx_up, Point(0, 0));
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_UP_RIGHT");
    bmp.draw(m_mem_gfx_up, Point(m_width-bmp.width, 0));
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_DOWN_RIGHT");
    bmp.draw(m_mem_gfx_up, Point(m_width-bmp.width, m_height-bmp.height));
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_DOWN_LEFT");
    bmp.draw(m_mem_gfx_up, Point(0, m_height-bmp.height));

    // Medidas del texto
    Size ts = m_mem_gfx_up.measureText(m_text, m_font);
    uint tx = (m_width-ts.width)/2;
    uint ty = (m_height-ts.height)/2;
   
    // Icono?
    if(m_icon_name !is null)
    {
      switch(m_icon_pos)
      {
        case 0:
          // Icono arriba
          uint ix = (m_width-m_icon.width)/2;
          uint iy = (m_height-m_icon.height)/2 - ts.height/2 - 2;
          m_mem_gfx_up.drawIcon(m_icon, ix, iy);
          m_mem_gfx_up.drawText(m_text, m_font, Color(0, 0, 0), Rect(tx, ty+ty/2+4, ts.width, ts.height));
          break;
        case 1:
          // Icono a la izquierda
          uint ix = m_width/12;
          uint iy = (m_height-m_icon.height)/2;
          m_mem_gfx_up.drawIcon(m_icon, ix, iy);
          m_mem_gfx_up.drawText(m_text, m_font, Color(0, 0, 0), Rect(tx+m_icon.width/2, ty, ts.width, ts.height));
          break;
      }
    }
    else
    {
      // Dibujar solo texto centrado
      m_mem_gfx_up.drawText(m_text, m_font, Color(0, 0, 0), Rect(tx, ty, ts.width, ts.height));
    }
   
   
    /*------------------------------------------------------------
      Boton pulsado (DOWN)
    ------------------------------------------------------------*/
    // Rellenar bitmap borde superior
    bmp = Application.resources.getBitmap(resource_bmps ~ "DOWN_UP");
    for(uint x=0; x < m_width; x++)
    {
      bmp.draw(m_mem_gfx_down, Point(x, 0));
    }
   
    // Rellenar bitmap central
    up_bmp_h = bmp.height;
    bmp = Application.resources.getBitmap(resource_bmps ~ "DOWN_CENTER");
    for(uint x=0; x < m_width; x++)
    {
      bmp.draw(m_mem_gfx_down, Point(x, up_bmp_h));
    }

    // Rellenar bitmap borde inferior
    bmp = Application.resources.getBitmap(resource_bmps ~ "DOWN_DOWN");
    for(uint x=0; x < m_width; x++)
    {
      bmp.draw(m_mem_gfx_down, Point(x, m_height-bmp.height));
    }

    // Rellenar bitmap borde izquierdo
    bmp = Application.resources.getBitmap(resource_bmps ~ "DOWN_LEFT");
    for(uint y=0; y < m_height; y++)
    {
      bmp.draw(m_mem_gfx_down, Point(0, y));
    }

    // Rellenar bitmap borde derecho
    bmp = Application.resources.getBitmap(resource_bmps ~ "DOWN_RIGHT");
    for(uint y=0; y < m_height; y++)
    {
      bmp.draw(m_mem_gfx_down, Point(m_width-bmp.width, y));
    }
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "DOWN_UP_LEFT");
    bmp.draw(m_mem_gfx_down, Point(0, 0));
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "DOWN_UP_RIGHT");
    bmp.draw(m_mem_gfx_down, Point(m_width-bmp.width, 0));
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "DOWN_DOWN_RIGHT");
    bmp.draw(m_mem_gfx_down, Point(m_width-bmp.width, m_height-bmp.height));
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "DOWN_DOWN_LEFT");
    bmp.draw(m_mem_gfx_down, Point(0, m_height-bmp.height));
   
    // Icono?
    if(m_icon_name !is null)
    {
      switch(m_icon_pos)
      {
        case 0:
          // Icono arriba
          uint ix = (m_width-m_icon.width)/2;
          uint iy = (m_height-m_icon.height)/2 - ts.height/2 - 2;
          m_mem_gfx_down.drawIcon(m_icon, ix+1, iy+1);
          m_mem_gfx_down.drawText(m_text, m_font, Color(0, 0, 0), Rect(tx+1, ty+ty/2+4+1, ts.width, ts.height));
          break;
        case 1:
          // Icono a la izquierda
          uint ix = m_width/12;
          uint iy = (m_height-m_icon.height)/2;
          m_mem_gfx_down.drawIcon(m_icon, ix+1, iy+1);
          m_mem_gfx_down.drawText(m_text, m_font, Color(0, 0, 0), Rect(tx+m_icon.width/2+1, ty+1, ts.width, ts.height));
          break;
      }
    }
    else
    {
      // Dibujar solo texto centrado
      m_mem_gfx_down.drawText(m_text, m_font, Color(0, 0, 0), Rect(tx+1, ty+1, ts.width, ts.height));
    }
   
   
    /*------------------------------------------------------------
      Boton resaltado (HIGH)
    ------------------------------------------------------------*/
    // Rellenar bitmap borde superior
    bmp = Application.resources.getBitmap(resource_bmps ~ "HIGH_UP");
    for(uint x=0; x < m_width; x++)
    {
      bmp.draw(m_mem_gfx_high, Point(x, 0));
    }
   
    // Rellenar bitmap central
    up_bmp_h = bmp.height;
    bmp = Application.resources.getBitmap(resource_bmps ~ "HIGH_CENTER");
    for(uint x=0; x < m_width; x++)
    {
      bmp.draw(m_mem_gfx_high, Point(x, up_bmp_h));
    }

    // Rellenar bitmap borde inferior
    bmp = Application.resources.getBitmap(resource_bmps ~ "HIGH_DOWN");
    for(uint x=0; x < m_width; x++)
    {
      bmp.draw(m_mem_gfx_high, Point(x, m_height-bmp.height));
    }

    // Rellenar bitmap borde izquierdo
    bmp = Application.resources.getBitmap(resource_bmps ~ "HIGH_LEFT");
    for(uint y=0; y < m_height; y++)
    {
      bmp.draw(m_mem_gfx_high, Point(0, y));
    }

    // Rellenar bitmap borde derecho
    bmp = Application.resources.getBitmap(resource_bmps ~ "HIGH_RIGHT");
    for(uint y=0; y < m_height; y++)
    {
      bmp.draw(m_mem_gfx_high, Point(m_width-bmp.width, y));
    }
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "HIGH_UP_LEFT");
    bmp.draw(m_mem_gfx_high, Point(0, 0));
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "HIGH_UP_RIGHT");
    bmp.draw(m_mem_gfx_high, Point(m_width-bmp.width, 0));
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "HIGH_DOWN_RIGHT");
    bmp.draw(m_mem_gfx_high, Point(m_width-bmp.width, m_height-bmp.height));
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "HIGH_DOWN_LEFT");
    bmp.draw(m_mem_gfx_high, Point(0, m_height-bmp.height));

    // Icono?
    if(m_icon_name !is null)
    {
      switch(m_icon_pos)
      {
        case 0:
          // Icono arriba
          uint ix = (m_width-m_icon.width)/2;
          uint iy = (m_height-m_icon.height)/2 - ts.height/2 - 2;
          m_mem_gfx_high.drawIcon(m_icon, ix, iy);
          m_mem_gfx_high.drawText(m_text, m_font, Color(0, 0, 0), Rect(tx, ty+ty/2+4, ts.width, ts.height));
          break;
        case 1:
          // Icono a la izquierda
          uint ix = m_width/12;
          uint iy = (m_height-m_icon.height)/2;
          m_mem_gfx_high.drawIcon(m_icon, ix, iy);
          m_mem_gfx_high.drawText(m_text, m_font, Color(0, 0, 0), Rect(tx+m_icon.width/2, ty, ts.width, ts.height));
          break;
      }
    }
    else
    {
      // Dibujar solo texto centrado
      m_mem_gfx_high.drawText(m_text, m_font, Color(0, 0, 0), Rect(tx, ty, ts.width, ts.height));
    }
   
   
    /*------------------------------------------------------------
      Boton desactivado (DISABLE)
    ------------------------------------------------------------*/
    // Rellenar bitmap borde superior
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_UP");
    for(uint x=0; x < m_width; x++)
    {
      bmp.draw(m_mem_gfx_disable, Point(x, 0));
    }
   
    // Rellenar bitmap central
    up_bmp_h = bmp.height;
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_CENTER_DISABLE");
    for(uint x=0; x < m_width; x++)
    {
      bmp.draw(m_mem_gfx_disable, Point(x, up_bmp_h));
    }

    // Rellenar bitmap borde inferior
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_DOWN");
    for(uint x=0; x < m_width; x++)
    {
      bmp.draw(m_mem_gfx_disable, Point(x, m_height-bmp.height));
    }

    // Rellenar bitmap borde izquierdo
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_LEFT");
    for(uint y=0; y < m_height; y++)
    {
      bmp.draw(m_mem_gfx_disable, Point(0, y));
    }

    // Rellenar bitmap borde derecho
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_RIGHT");
    for(uint y=0; y < m_height; y++)
    {
      bmp.draw(m_mem_gfx_disable, Point(m_width-bmp.width, y));
    }
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_UP_LEFT");
    bmp.draw(m_mem_gfx_disable, Point(0, 0));
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_UP_RIGHT");
    bmp.draw(m_mem_gfx_disable, Point(m_width-bmp.width, 0));
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_DOWN_RIGHT");
    bmp.draw(m_mem_gfx_disable, Point(m_width-bmp.width, m_height-bmp.height));
   
    bmp = Application.resources.getBitmap(resource_bmps ~ "UP_DOWN_LEFT");
    bmp.draw(m_mem_gfx_disable, Point(0, m_height-bmp.height));

    // Medidas del texto
    ts = m_mem_gfx_disable.measureText(m_text, m_font);
    tx = (m_width-ts.width)/2;
    ty = (m_height-ts.height)/2;
   
    // Icono?
    if(m_icon_name !is null)
    {
      switch(m_icon_pos)
      {
        case 0:
          // Icono arriba
          uint ix = (m_width-m_icon.width)/2;
          uint iy = (m_height-m_icon.height)/2 - ts.height/2 - 2;
          m_mem_gfx_disable.drawIcon(m_icon, ix, iy);
          m_mem_gfx_disable.drawText(m_text, m_font, Color(120, 120, 120), Rect(tx, ty+ty/2+4, ts.width, ts.height));
          break;
        case 1:
          // Icono a la izquierda
          uint ix = m_width/12;
          uint iy = (m_height-m_icon.height)/2;
          m_mem_gfx_disable.drawIcon(m_icon, ix, iy);
          m_mem_gfx_disable.drawText(m_text, m_font, Color(120, 120, 120), Rect(tx+m_icon.width/2, ty, ts.width, ts.height));
          break;
      }
    }
    else
    {
      // Dibujar solo texto centrado
      m_mem_gfx_disable.drawText(m_text, m_font, Color(120, 120, 120), Rect(tx, ty, ts.width, ts.height));
    }

   
   
    // Empezar por mostrar el boton pulsado o normal, activado/desactivado?
    Paint(null, null);
   
    // Asignar funcion de repintado
    m_picbox.paint ~= &Paint;
   
    // Control de eventos del raton
    m_picbox.mouseEnter ~= &MouseEnter;
    m_picbox.mouseLeave ~= &MouseLeave;
    m_picbox.mouseDown  ~= &MouseDown;
    m_picbox.mouseUp    ~= &MouseUp;    
  }

  void KeepPushed(bool keep_pushed)
  {
    m_keep_pushed = keep_pushed;
    Paint(null, null);
  }

  bool IsKeepPushed()
  {
    return(m_keep_pushed);
  }
 
  void Enable(bool enable)
  {
    m_enable = enable;
    Paint(null, null);
  }
 
  bool IsEnable()
  {
    return(m_enable);
  }
 
  void Visible(bool visible)
  {
    m_picbox.visible = visible;
  }
 
  bool IsVisible()
  {
    return(m_picbox.visible());
  }
 
  PictureBox GetPictureBox()
  {
    return(m_picbox);
  }
}
Back to top
View user's profile Send private message
Chris Miller



Joined: 27 Mar 2004
Posts: 514
Location: The Internet

PostPosted: Sat Dec 22, 2007 8:01 am    Post subject: Re: DCs Reply with quote

The *Graphics classes are DC wrappers. You are holding on to them yourself. Perhaps you should hold on to images and paint them instead.
Back to top
View user's profile Send private message
jvr



Joined: 19 Nov 2007
Posts: 10

PostPosted: Sat Dec 22, 2007 10:10 am    Post subject: Re: DCs Reply with quote

Never mind, I've changed the SkinButton class to avoid problems and now "standard" buttons are used automatically if the o. system is Win9x/ME.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic     Forum Index -> DFL All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group