zoukankan      html  css  js  c++  java
  • How to Create a Microsoft .NET Compact Frameworkbased Image Button

    Alex Yakhnin
    IntelliProg, Inc.

    March 2003

    Applies to:
    Microsoft® .NET Compact Framework
    Microsoft® Visual Studio® .NET 2003

    Summary: Learn how to create a .NET Compact Framework-based image button. (10 printed pages)

    Download ImageButton.msi.

    Contents

    Introduction
    What’s available?
    Best Practices for Creating Graphics
    Applying the rules
    The usage…
    Conclusion

    Introduction

    The .NET Compact Framework provides a rich set of controls for designing the user interface in your applications. But the first thing to realize as a .NET Framework developer is that not all of the features of the .NET Framework Windows Forms package have been implemented in version 1.0 of the .NET Compact Framework. Demand for memory, CPU, and other resources are at a premium on the Microsoft® Windows® CE platform. This means that you will see a variety of differences between the full .NET Framework and the .NET Compact Framework. For example, most of the standard controls, such as Button, ListBox or Label, don’t allow you to override the OnPaint event and add custom drawing to them. The primary example for this whitepaper will be a simple ImageButton control. This will be used to show principal techniques for creating an owner-drawn custom control, and best practice guidelines on achieving optimal graphics performance when dealing with image, text or line drawing in .NET Compact Framework-based applications.

    What’s available?

    Due to the resource constraints, there is no full GDI+ support in the .NET Compact Framework. As you may know, the services of GDI+ fall into the following three broad categories:

    • 2-D vector graphics
    • Imaging
    • Typography

    Of the 2-D Vector Graphics in the .NET Compact Framework, only the core drawing primitives like Ellipse, Line, Image, Polygon, Rectangle, String, Fill Ellipse, Fill Polygon, Fill Rectangle, and Fill Region are supported by the Graphics object.

    In the Imaging category, the Bitmap class doesn’t support image manipulation (at the bit level) or saving the bitmap to file. Additionally, the double-buffering that’s supported by the .NET Framework through ControlStyles is not available either.

    The Typography category is concerned with the display of text in a variety of fonts, sizes, and styles. GDI in the .NET Compact Framework provides support for this task, except for the usage of any sub-pixel anti-aliasing.

    But fear not! The available subset of the GDI functionality still permits us to create quite a graphically-robust application. Just take a look at the System.Windows.Forms.DataGrid control that comes with the .NET Compact Framework. It is a fully-managed, owner-drawn control that yields a really good graphics performance by rendering multiple data rows and cells. In order to achieve this kind of performance, we just need to play by the rules that have been set up for us by the platform.

    Best Practices for Creating Graphics
    1. When creating an owner-drawn controls, derive from System.Windows.Forms.Control and override the OnPaint and OnPaintBackground events.
      using System;
      using System.Drawing;
      using System.Windows.Forms;
      
      public class MyButton : Control
      {
      
         protected override void OnPaint(PaintEventArgs e )
         {
            //Some drawing logic
            Graphics gr = e.Graphics;
            gr.DrawImage(image, 0, 0);
            Graphics gr = e.Graphics;
            gr.DrawImage(image, 0, 0);
            gr.DrawRectangle(pen, this.ClientRectangle);
         }
      
         protected override void OnPaintBackground(PaintEventArgs e )
         {
            //Do nothing
         }
      
      }
      
    2. Pre-cache Pen, Bitmap, and Brush objects when using them inside OnPaint event. The nature of the OnPaint event is that it can be called as many times as the operating system requires. Losing some time on instantiating and destroying these objects could affect your drawing performance.
    3. Use double-buffering from code to reduce the possible flickering when refreshing the graphics on the screen. In general, the double-buffering logic would look like this:
      protected override void OnPaint(PaintEventArgs e )
      {
      Graphics gxOff; //Offscreen graphics
      
         if (m_bmpOffscreen == null) //Bitmap for doublebuffering
         {
            m_bmpOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height);
         }
      
         gxOff = Graphics.FromImage(m_bmpOffscreen);
      
         gxOff.Clear(this.BackColor);
         //Draw some bitmap
         gxOff.DrawImage(bmpParent, 0, 0, bmpRect, GraphicsUnit.Pixel);
      
         //Boundary rectangle
      Rectangle rc = this.ClientRectangle;
         rc.Width--;
         rc.Height--;
      
         //Draw boundary
         gxOff.DrawRectangle(new Pen(Color.Black), rc);
         //Draw from the memory bitmap
         e.Graphics.DrawImage(m_bmpOffscreen, 0, 0);
      
         base.OnPaint(e);
      }
      

    In the code above, we create a Graphics object from the empty Bitmap with the size of our control by calling the static FromImage method on the Graphics class. We make all the drawing on the Graphics object in memory, and when we are done, just “blit” the whole prepared bitmap on the controls graphics.

    The ability to draw bitmaps transparently though the usage of the ImageAttributes parameter still exists in the .NET Compact Framework, but it’s a little bit more work than on the desktop.

    Copy

    ImageAttributes imageAttr = new ImageAttributes();
    // Make a transparent key
    imageAttr.SetColorKey(Color.White, Color.White);
    //Use the key when drawing
    gxOff.DrawImage(m_bmp, imgRect, 0, 0, img.Width, img.Height,
                                        GraphicsUnit.Pixel, imageAttr); 
    

    Keep in mind that the low and high color-key values in the SetColorKey method should have the same value, mainly because the .NET Compact Framework doesn’t support setting transparent colors in any other way.

    Applying the rules

    As a real-life exercise in utilizing these best practices, we are going to create an owner-drawn ImageButton control. The requirements will be to create a “push button”-style control that will display an image on its surface, and that will provide visual confirmation to the user that the button has been pressed.

    We start by creating a new Smart Device Application project in Visual Studio .NET and selecting Windows Application as its type. Let’s add the new ImageButton class to the project:

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    public class ImageButton : Control
    {
       //Private members
       private Image image;
       //flag to indicate the pressed state
       private bool bPushed;
       private Bitmap m_bmpOffscreen;
    
    public ImageButton()
       {
          bPushed = false;
          //default minimal size
          this.Size = new Size(21, 21);
       }
    
    protected override void OnPaint(PaintEventArgs e )
       {
          //Some drawing logic
       }
    
       protected override void OnPaintBackground(PaintEventArgs e )
       {
          //Do nothing
       }
    }
    

    In the code above, we derive an ImageButton class from Control, and override the OnPaint and OnPaintBackground events, as was described earlier. The ImageButton will require an image to be displayed, so we add the Image property:

    public Image Image
    {
       get
       {
          return image;
       }
       set
       {
          image = value;
       }
    }
    

    And of course, the “meat” of all owner-drawn controls is the drawing code in the OnPaint event:

    protected override void OnPaint(System.Windows.Forms.PaintEventArgs e )
    {
       Graphics gxOff;      //Offscreen graphics
       Rectangle imgRect; //image rectangle
       Brush backBrush;   //brush for filling a backcolor
    
       if (m_bmpOffscreen == null) //Bitmap for doublebuffering
       {
          m_bmpOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height);
       }
    
       gxOff = Graphics.FromImage(m_bmpOffscreen);
    
       gxOff.Clear(this.BackColor);
    
       if (!bPushed)
          backBrush = new SolidBrush(Parent.BackColor);
       else //change the background when it's pressed
          backBrush = new SolidBrush(Color.LightGray);
    
       gxOff.FillRectangle(backBrush, this.ClientRectangle);
    
       if (image != null)
       {
          //Center the image relativelly to the control
          int imageLeft = (this.Width - image.Width) / 2;
          int imageTop = (this.Height - image.Height) / 2;
    
          if (!bPushed)
          {
             imgRect = new Rectangle(imageLeft, imageTop, image.Width,
     image.Height);
          }
          else //The button was pressed
          {
             //Shift the image by one pixel
             imgRect = new Rectangle(imageLeft + 1, imageTop + 1, image.Width,
                                                              image.Height);
          }
          //Set transparent key
          ImageAttributes imageAttr = new ImageAttributes();
          imageAttr.SetColorKey(BackgroundImageColor(image),
                                                BackgroundImageColor(image));
          //Draw image
          gxOff.DrawImage(image, imgRect, 0, 0, image.Width, image.Height,
                                              GraphicsUnit.Pixel, imageAttr);    
    
    }
    
       if (bPushed) //The button was pressed
       {
          //Prepare rectangle
          Rectangle rc = this.ClientRectangle;
          rc.Width--;
          rc.Height--;
          //Draw rectangle
          gxOff.DrawRectangle(new Pen(Color.Black), rc);
       }
    
       //Draw from the memory bitmap
       e.Graphics.DrawImage(m_bmpOffscreen, 0, 0);
    
       base.OnPaint(e);
    }
    

    When creating this code, I followed the guidelines for successful drawing in the .NET Compact Framework that I outlined in the previous section. I pre-cached drawing objects, where it was possible, and used the double-buffering to reduce flicker. To make an image transparent, we identify its background color by using this helper function:

    private Color BackgroundImageColor(Image image)
    {
       Bitmap bmp = new Bitmap(image);
       return bmp.GetPixel(0, 0);
    }
    

    The task of this function is to retrieve the color of the pixel in the top left corner of the bitmap. When drawing the button, we check the bPushed flag that we need when the user pressed the button down. We can easily achieve that by overriding OnMouseDown and OnMouseUpevents:

    protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e )
    {
          bPushed = true;
          this.Invalidate();
    }
    
    protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
    {
       bPushed = false;
       this.Invalidate();
    }
    
    The usage…

    The usage of the newly-created ImageButton should be quite simple. Just add these few lines of code in the form’s constructor:

    public Form1()
    {
       InitializeComponent();
    
       imageButton1 = new ImageButton();
       imageButton1.Image = new
    Bitmap(Assembly.GetExecutingAssembly().GetManifestResourceStream("ImageButtonProject.doorin2.gif"));
       imageButton1.Location = new Point(30, 50);
       imageButton1.Size = new Size(44, 34);
       //Hook up into click event
       imageButton1.Click+=new EventHandler(imageButton1_Click);
       this.Controls.Add(imageButton1);
    }
    

    I’ve chosen to add the image file, doorin2.gif, as an embedded resource into project that is easy to retrieve by using the GetManifestResourceStream method of the current assembly.

    IC138447

    Figure 1. Three ImageButton controls on a form

    IC136872

    Figure 2. First ImageButton depressed

    Conclusion

    The .NET Compact Framework does not provide many of the graphics and drawing functions that are available in the full .NET Framework. This is due to platform resource constraints. But, knowing some of the guidelines for custom drawing, it is possible to create rich and responsive graphics in your applications.

  • 相关阅读:
    alpine python3中使用mysql报错ModuleNotFoundError: No module named 'MySQLdb'
    Galera集群部署
    Kibana did not load properly.Check the server output for more information。
    zabbix-server迁移
    traefik使用etcd存储配置
    Rancher2.4搭建单机版rabbitmq
    ngx_http_upstream_module模块说明
    【说明】
    运维日常集合(个人向 坚持更新)
    Linux监控-历史细项数据回溯
  • 原文地址:https://www.cnblogs.com/zjmsky/p/1898844.html
Copyright © 2011-2022 走看看