In Depth Banner
Skip Navigation Links

Select your preferred language

Listing 1: The complete DXMarquee control

using System;

using System.ComponentModel;

using System.Drawing;

using System.Drawing.Text;

using System.Windows.Forms;

using Microsoft.DirectX;

using Microsoft.DirectX.DirectDraw;

 

 

namespace WellFormed

{

  /// <summary>

  /// Summary description for DXMarquee.

  /// </summary>

  public class DXMarquee : Control

  {

    Device _device;

    Surface _primary;

    Surface _backBuffer;

    Surface _textBuffer;

    Clipper _primaryClipper;

 

    int _interval=20;

    [

    Category("Behavior"),

    Description("Gets or sets the timer interval in milliseconds")

    ]

    public int Interval

    {

      get{return _interval;}

      set

      {

        _interval=value;

        if(_interval<1)

          _interval=1;

        if(t!=null)

          t.Interval=value;

      }

    }

 

    int _step=1;

    [

    Category("Behavior"),

    Description("Gets or Sets the number of pixels the text will move per tick")

    ]

    public int Step

    {

      get{return _step;}

      set

      {

        _step=value;

        if(_step<1)

          _step=1;

      }

    }

 

    Timer t=new Timer();

 

    public DXMarquee()

    {

      this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);

 

      //Create the device and set the cooperative level.

      _device=new Device();

      _device.SetCooperativeLevel(this,CooperativeLevelFlags.Normal);

 

      t.Tick+=new EventHandler(t_Tick);

      t.Interval=Interval;

      t.Enabled=true;

    }

 

    protected override void OnPaintBackground(PaintEventArgs pevent)

    {

      //Don't paint the background

    }

 

 

    protected void CreateSurfaces(Bitmap bm)

    {

      SurfaceDescription sd=new SurfaceDescription();

      //Create DirectX surfaces. First the primary surface.

      if(_primary==null)

      {

        sd.SurfaceCaps.PrimarySurface=true;

        _primary=new Surface(sd,_device);

      }

 

      //This can be called if the control changes size so we always create a new backbuffer

      if(_backBuffer!=null)

        _backBuffer.Dispose();

      //now the back buffer surface as an offscreen plain buffer built from the bitmap handed in

      sd.Clear();

      sd.Width=this.Width;

      sd.Height=this.Height;

      sd.SurfaceCaps.OffScreenPlain=true;

      _backBuffer=new Surface(sd,_device);

 

      if(_textBuffer!=null)

        _textBuffer.Dispose();

      //now the image surface from which the text is copied

      sd.Clear();

      sd.SurfaceCaps.OffScreenPlain=true;

      sd.Height=bm.Height;

      sd.Width=bm.Width;

      _textBuffer=new Surface(bm,sd,_device);

 

      //Finally, the clipper is set up to ensure the output is limited to the area of this control

      if(_primaryClipper!=null)

        _primaryClipper.Dispose();

      _primaryClipper=new Clipper(_device);

      _primaryClipper.Window=this;

      _primary.Clipper=_primaryClipper;

 

    }

 

    Bitmap _bm;

 

    int _textWidth;

 

    int _marqueeOffset=0;

 

    protected void CreateText()

    {

      if(this.Height==0 || this.Width==0)

        return;

      Font=new Font(Font.FontFamily,0.6f*this.Height);

      Graphics g=CreateGraphics();

      g.TextRenderingHint=TextRenderingHint.AntiAlias;

      SizeF sf=g.MeasureString(this.Text,this.Font,2048,StringFormat.GenericTypographic);

      _textWidth=(int)(0.5f+sf.Width);

      if(_textWidth==0)

        return;

 

      if(_bm!=null)

        _bm.Dispose();

      _bm=new Bitmap(_textWidth,this.Height);

      

      g=Graphics.FromImage(_bm);

      g.Clear(this.BackColor);

      g.TextRenderingHint=TextRenderingHint.AntiAlias;

      SolidBrush sb=new SolidBrush(this.ForeColor);

      g.DrawString(Text,Font,sb,0,0,StringFormat.GenericTypographic);

      sb.Dispose();

 

      _marqueeOffset=0;

 

      this.CreateSurfaces(_bm);

 

    }

 

    protected override void OnSizeChanged(EventArgs e)

    {

      this.CreateText();

      base.OnSizeChanged (e);

    }

 

    protected override void OnTextChanged(EventArgs e)

    {

      this.CreateText();

      base.OnTextChanged (e);

    }

 

    protected override void OnBackColorChanged(EventArgs e)

    {

      this.CreateText();

      base.OnBackColorChanged (e);

    }

 

    protected override void OnFontChanged(EventArgs e)

    {

      this.CreateText();

      base.OnFontChanged (e);

    }

 

    protected override void OnForeColorChanged(EventArgs e)

    {

      this.CreateText();

      base.OnForeColorChanged (e);

    }

 

 

 

 

    private void t_Tick(object sender, EventArgs e)

    {

      _marqueeOffset+=Step;

      if(_marqueeOffset>this.Width+_textWidth)

        _marqueeOffset=0;

    }

 

    protected override void OnPaint(PaintEventArgs e)

    {

      //the back bufffer is copied to the primary surface.

      //First a quick check to see if there's actually anything to do.

      if(_primary==null || this._backBuffer==null)

        return;

 

      //define the destination rectangle

      Rectangle dest=new Rectangle(this.ClientSize.Width-_marqueeOffset,0,this._textWidth,this.Height);

      dest.Intersect(new Rectangle(0,0,this.Width,this.Height));

 

      //The source is a moving window onto the pre-drawn bitmap.

      //The marquee starts from the right and scrolls left

      //so the offset is used to calculate the amount of text seen

 

      Rectangle src=new Rectangle(0,0,Math.Min(dest.Width,_textWidth),this.Height);

      if(_marqueeOffset>this.Width)

        src.Offset(this._marqueeOffset-this.Width,0);

      src.Intersect(new Rectangle(0,0,_textWidth,this.Height));

 

      _backBuffer.ColorFill(this.BackColor);

 

      if(src.Width!=0 && dest.Width!=0)

      {

          _backBuffer.Draw(dest,_textBuffer,src,DrawFlags.DoNotWait);

          _primary.Draw(RectangleToScreen(this.ClientRectangle),_backBuffer,this.ClientRectangle,DrawFlags.DoNotWait);

      }

 

      base.OnPaint(e);

    }

 

  }

}

 

 

Hit you back button to return to the article.

Copyright © Bob Powell 2003-2009. All rights reserved