A C# Oscilloscope Display In Windows Forms
A C# Oscilloscope Display In Windows Forms
Written by Mike James   
Thursday, 04 June 2015
Article Index
A C# Oscilloscope Display In Windows Forms
ScrollWindowEx

Using ScrollWindowEx

One solution to the problem is to use a direct API call to ScrollWindowEx to scroll the picturebox's display directly.

This has the disadvantage that you have go outside of a managed environment but it is relatively safe. There are some real problems, however.

The ScrollWindowEx call scrolls the internal display bitmap used to show the window. This isn't persistent and in fact if you cause the picturebox to redraw itself at any point you will loose the scrolling and revert to either its background image or its initial state.

This non-persistent effect is one reason why many programmers think that ScrollWindowEx doesn't work - because they never see it for long enough! So we are going to have to be careful not to trigger a redraw of the picturebox and we can't use a bitmap to draw on.

Add a new button to the form and add to the static MyExtensions class:

public static void Scroll(this PictureBox BP,
                             int dx, int dy)
{
 ScrollWindowEx(BP.Handle,
                dx, dy,
                null, null,         
                IntPtr.Zero,
                null, 2);
}

 

This time the extension method has been added directly to the PictureBox. We also need the definition of the API call and the RECT structure it uses. This should be added to the static class:

[DllImport("user32.dll")]
private static extern int ScrollWindowEx(
 System.IntPtr hWnd,
 int dx,
 int dy,
[MarshalAs(UnmanagedType.LPStruct)]
 RECT prcScroll,
[MarshalAs(UnmanagedType.LPStruct)]
 RECT prcClip,
 System.IntPtr hrgnUpdate,
[MarshalAs(UnmanagedType.LPStruct)]
 RECT prcUpdate,
 System.UInt32 flags);

[StructLayout(LayoutKind.Sequential)]
public class RECT
{
 public Int32 left;
 public Int32 top;
 public Int32 right;
 public Int32 bottom;
}

Don't forget to add:

using System.Runtime.InteropServices;

The second button's click handler starts off in roughly the same way:

private void button2_Click(
              object sender, EventArgs e)
{
 Graphics G = pictureBox1.CreateGraphics();
 for (int x = 0; x < 10000; x++)
 {
  int y = (int)(Math.Sin((double)x / 50) *
        pictureBox1.ClientSize.Height / 2 +
        pictureBox1.ClientSize.Height / 2);
        G.DrawLine(Pens.Blue, 1, y, 1, y + 1);

Notice that now we don't need to use a bitmap but draw directly onto the picturebox's Graphics object. 

All that remains is to use the scroll method:

  pictureBox1.Scroll(1, 0);
  Application.DoEvents();
 }

Finally we need to clean up the Graphics object created:

 G.Dispose();
}

It may only be a single Graphics object but not cleaning up still means a memory leak.

Now if you try it out and compare the two plots you will discover that the API based one works much faster. The difference is a factor of more than 100 and very worth the effort.  The only problem is that the API scroll isn't persistent so when the display is completed covering up the final plot erases it.

One final question remains - would this be better done/easier to do using WPF?

But this is another story.

If you would like the code for this project then register and click on CodeBin.

Complete Listing

Omitting the usual using statements:

using System.Runtime.InteropServices;
namespace stripchart1
{

 public partial class Form1 : Form
 {
  public Form1()
  {
   InitializeComponent();
  }

  private void button1_Click(object sender,
                                EventArgs e)
  {
   Bitmap BM = new Bitmap(
              pictureBox1.ClientSize.Width,
              pictureBox1.ClientSize.Height);
   pictureBox1.Image = BM;
   for (int x = 0; x < 10000; x++)
   {
    int y = (int)(Math.Sin((double)x / 50) *
              BM.Height / 2 + BM.Height / 2);
    BM.SetPixel(0, y, Color.Black);
    BM = BM.Scroll(1, 0);
    pictureBox1.Image = BM;
    Application.DoEvents();
   }
  }
 
  private void button2_Click(object sender,
                               EventArgs e)
  {
   Graphics G = pictureBox1.CreateGraphics();
   for (int x = 0; x < 10000; x++)
   {
    int y = (int)(Math.Sin((double)x / 50) *
         pictureBox1.ClientSize.Height / 2 +
         pictureBox1.ClientSize.Height / 2);
    G.DrawLine(Pens.Blue, 1, y, 1, y + 1);
    pictureBox1.Scroll(1, 0);
    Application.DoEvents();
   }
   G.Dispose();
  }
 }
 
 public static class MyExtensions
 {
 [DllImport("user32.dll")]
  private static extern int ScrollWindowEx(
   System.IntPtr hWnd,  
   int dx,
   int dy,
 [MarshalAs(UnmanagedType.LPStruct)]
   RECT prcScroll,
 [MarshalAs(UnmanagedType.LPStruct)]
   RECT prcClip,
   System.IntPtr hrgnUpdate,
 [MarshalAs(UnmanagedType.LPStruct)]
   RECT prcUpdate,
   System.UInt32 flags);

  public static Bitmap Scroll(this Bitmap BM,
                                int dx, int dy)
  {
   Bitmap BMTemp = new Bitmap(BM.Width,
                                   BM.Height);
   Graphics G = Graphics.FromImage(BMTemp);
   G.DrawImage(BM, dx, dy);
   G.Dispose();
   return BMTemp;
  }

  public static void Scroll(this PictureBox BP,
                                   int dx, int dy)
  {
   ScrollWindowEx(BP.Handle,
                  dx, dy,
                  null, null,
                  IntPtr.Zero,
                  null, 2);
  }
 }

 [StructLayout(LayoutKind.Sequential)]
 public class RECT
 {
  public Int32 left;
  public Int32 top;
  public Int32 right;
  public Int32 bottom;
 }
}

Related Articles

Looking at Chaos

Snake - using the GDI+       

 

To be informed about new articles on I Programmer, install the I Programmer Toolbar, subscribe to the RSS feed, follow us on, Twitter, FacebookGoogle+ or Linkedin,  or sign up for our weekly newsletter.

 


Getting Started With Azure Linux VMs

If you are a Visual Studio user there are lots of advantages to making use of Azure as your Virtual Machine host. In this article the general ideas of using Azure and how to work with Linux VMs is des [ ... ]



Automatic Web Page Use With .NET

Using web browser macros, the need to get more control over what is happening during the automated use of a web page becomes increasingly obvious. After trying a number of possible solutions, C# and . [ ... ]


Other Projects

 


N Is For Nougat AKA Android 7.0
01/07/2016

Google has revealed that the next version of Android will be named Nougat - which may cause some problems due to variations in its pronunciation - and will be version 7, with a new statue added to its [ ... ]



Coursera and IBM Join Forces in India
05/07/2016

Coursera is partnering with IBM to strengthen the developer ecosystem in India via its Full Stack Web Development Specialization. Twenty Indian students will be awarded up to $120,000 per ye [ ... ]


More News

 

blog comments powered by Disqus

 

<ASIN:9812791035>

<ASIN:0979372518>

<ASIN:0735623945>

 

 



Last Updated ( Thursday, 04 June 2015 )
 
 

   
Banner
RSS feed of all content
I Programmer - full contents
Copyright © 2016 i-programmer.info. All Rights Reserved.
Joomla! is Free Software released under the GNU/GPL License.