Introduction
On the internet I found many projects on analog meters, but few could change their appearance using a custom renderer. Because of this, I decided to create my first control in C#, and use this control in my next projects.
Background
To compile this demo you need .NET 2.0 which is available here. The project is developed with SharpDevelop, a free IDE per .NET.
Using the Code
In the zip files there is a complete solution, but it is simple enough to use the code of the control for inserting this in another project. In the next section, there is a description for how to use the class.
Control Class
The class is derived from System.Windows.Forms.UserControl. Normally, this class has a default renderer class that is used for drawing all parties, but it is possible to set a custom renderer to draw a single part, or the entire control. The main class of the control is:
namespace LBSoft.IndustrialCtrls.Meters
{
public partial class LBAnalogMeter : UserControl
{
...
}
}
You can set the following properties at design time:
Appearance Properties
MeterStyle - Style of the control. At the moment the only stile is AnalogMeterStyle.Circular.
BodyColor - Color of the body of the control.
NeedleColor - Color of the needle of the control
ScaleColor - Color of the thicks of the control scale
ScaleDivisions - Number of main division of the scale
ScaleSubDivisions - Number of the sub-division between a main division to an other of the scale
ViewGlass - Flag for the visualization of the glass effect
Behavior Properties
Value - Current value of the control
MinValue - Minimum value of the control
MaxValue - Maximum value of the control
In the next section will describe the renderer class and how it is possible to customize the control draw.
Renderer Class
The renderer class is a class with a few virtual methods which are called for the design of the individual parts of control.
namespace LBSoft.IndustrialCtrls.Meters
{
public class LBAnalogMeterRenderer
{
private LBAnalogMeter meter = null;
public LBAnalogMeter AnalogMeter
{
set { this.meter = value; }
get { return this.meter; }
}
public virtual bool DrawBackground( Graphics gr, RectangleF rc )
{
return false;
}
public virtual bool DrawBody( Graphics Gr, RectangleF rc )
{
return false;
}
public virtual bool DrawDivisions( Graphics Gr, RectangleF rc )
{
return false;
}
public virtual bool DrawThresholds( Graphics gr, RectangleF rc )
{
return false;
}
public virtual bool DrawUM( Graphics gr, RectangleF rc )
{
return false;
}
public virtual bool DrawValue( Graphics gr, RectangleF rc )
{
return false;
}
public virtual bool DrawNeedle( Graphics Gr, RectangleF rc )
{
return false;
}
public virtual bool DrawNeedleCover( Graphics Gr, RectangleF rc )
{
return false;
}
public virtual bool DrawGlass( Graphics Gr, RectangleF rc )
{
return false;
}
}
}
All the methods of the base class return False. The control class, if it has a custom renderer, call the custom renderer, and if the method called returns False, call the same method of the default renderer.
For example, if you want to eliminate the drawing of the body of the control, use the following this steps :
- Create a class derived from
LBAnalogMeterRenderer
- Override the method
DrawBody
- In this method return
True
- Create an instance of the custom renderer in the main form
- Set the renderer to the control with the property
Renderer
Code :
namespace TestApp
{
public class LBNoBodyAnalogMeterRenderer : LBAnalogMeterRenderer
{
public override bool DrawBody( Graphics Gr, RectangleF rc )
{
return true;
}
}
public partial class MainForm : Form
{
LBNoBodyAnalogMeterRenderer customRenderer = null;
...
public MainForm()
{
InitializeComponent();
this.customRenderer = new LBNoBodyAnalogMeterRenderer;
this.lbAnalogMeter.Renderer = this.customRenderer;
...
}
...
}
}
Conclusion
This is the preliminary version of the control, and many features have yet to be implemented, but I hope to do so soon
For this article, I used the code and ideas from this article:
Points of Interest
Any suggestions/comments/feedback are highly appreciated
History