using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Design; using System.Windows.Forms; using System.Windows.Forms.Design; namespace MyLib { // This UITypeEditor can be associated with Int32, Double and Single // properties to provide a design-mode angle selection interface. //[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")] public class AngleEditor : System.Drawing.Design.UITypeEditor { public AngleEditor() { } // Indicates whether the UITypeEditor provides a form-based (modal) dialog, // drop down dialog, or no UI outside of the properties window. public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context) { return UITypeEditorEditStyle.DropDown; } // Displays the UI for value selection. public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value) { // Return the value if the value is not of type Int32, Double and Single. if (value.GetType() != typeof(double) && value.GetType() != typeof(float) && value.GetType() != typeof(int)) return value; // Uses the IWindowsFormsEditorService to display a // drop-down UI in the Properties window. IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)); if (edSvc != null) { // Display an angle selection control and retrieve the value. AngleControl angleControl = new AngleControl((double)value); edSvc.DropDownControl(angleControl); // Return the value in the appropraite data format. if (value.GetType() == typeof(double)) return angleControl.angle; else if (value.GetType() == typeof(float)) return (float)angleControl.angle; else if (value.GetType() == typeof(int)) return (int)angleControl.angle; } return value; } // Draws a representation of the property's value. public override void PaintValue(System.Drawing.Design.PaintValueEventArgs e) { int normalX = (e.Bounds.Width / 2); int normalY = (e.Bounds.Height / 2); // Fill background and ellipse and center point. e.Graphics.FillRectangle(new SolidBrush(Color.DarkBlue), e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height); e.Graphics.FillEllipse(new SolidBrush(Color.White), e.Bounds.X + 1, e.Bounds.Y + 1, e.Bounds.Width - 3, e.Bounds.Height - 3); e.Graphics.FillEllipse(new SolidBrush(Color.SlateGray), normalX + e.Bounds.X - 1, normalY + e.Bounds.Y - 1, 3, 3); // Draw line along the current angle. double radians = ((double)e.Value * Math.PI) / (double)180; e.Graphics.DrawLine(new Pen(new SolidBrush(Color.Red), 1), normalX + e.Bounds.X, normalY + e.Bounds.Y, e.Bounds.X + (normalX + (int)((double)normalX * Math.Cos(radians))), e.Bounds.Y + (normalY + (int)((double)normalY * Math.Sin(radians)))); } // Indicates whether the UITypeEditor supports painting a // representation of a property's value. public override bool GetPaintValueSupported(System.ComponentModel.ITypeDescriptorContext context) { return true; } } // Provides a user interface for adjusting an angle value. internal class AngleControl : System.Windows.Forms.UserControl { // Stores the angle. public double angle; // Stores the rotation offset. private int rotation = 0; // Control state tracking variables. private int dbx = -10; private int dby = -10; private int overButton = -1; public AngleControl(double initial_angle) { this.angle = initial_angle; this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); } protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) { // Set angle origin point at center of control. int originX = (this.Width / 2); int originY = (this.Height / 2); // Fill background and ellipse and center point. e.Graphics.FillRectangle(new SolidBrush(Color.DarkBlue), 0, 0, this.Width, this.Height); e.Graphics.FillEllipse(new SolidBrush(Color.White), 1, 1, this.Width - 3, this.Height - 3); e.Graphics.FillEllipse(new SolidBrush(Color.SlateGray), originX - 1, originY - 1, 3, 3); // Draw angle markers. int startangle = (270 - rotation) % 360; e.Graphics.DrawString(startangle.ToString(), new Font("Arial", 8), new SolidBrush(Color.DarkGray), (this.Width / 2) - 10, 10); startangle = (startangle + 90) % 360; e.Graphics.DrawString(startangle.ToString(), new Font("Arial", 8), new SolidBrush(Color.DarkGray), this.Width - 18, (this.Height / 2) - 6); startangle = (startangle + 90) % 360; e.Graphics.DrawString(startangle.ToString(), new Font("Arial", 8), new SolidBrush(Color.DarkGray), (this.Width / 2) - 6, this.Height - 18); startangle = (startangle + 90) % 360; e.Graphics.DrawString(startangle.ToString(), new Font("Arial", 8), new SolidBrush(Color.DarkGray), 10, (this.Height / 2) - 6); // Draw line along the current angle. double radians = ((((angle + rotation) + 360) % 360) * Math.PI) / (double)180; e.Graphics.DrawLine(new Pen(new SolidBrush(Color.Red), 1), originX, originY, originX + (int)((double)originX * (double)Math.Cos(radians)), originY + (int)((double)originY * (double)Math.Sin(radians))); // Output angle information. e.Graphics.FillRectangle(new SolidBrush(Color.Gray), this.Width - 84, 3, 82, 13); e.Graphics.DrawString("Angle: " + angle.ToString("F4"), new Font("Arial", 8), new SolidBrush(Color.Yellow), this.Width - 84, 2); // Draw square at mouse position of last angle adjustment. e.Graphics.DrawRectangle(new Pen(new SolidBrush(Color.Black), 1), dbx - 2, dby - 2, 4, 4); // Draw rotation adjustment buttons. if (overButton == 1) { e.Graphics.FillRectangle(new SolidBrush(Color.Green), this.Width - 28, this.Height - 14, 12, 12); e.Graphics.FillRectangle(new SolidBrush(Color.Gray), 2, this.Height - 13, 110, 12); e.Graphics.DrawString("Rotate 90 degrees left", new Font("Arial", 8), new SolidBrush(Color.White), 2, this.Height - 14); } else e.Graphics.FillRectangle(new SolidBrush(Color.DarkGreen), this.Width - 28, this.Height - 14, 12, 12); if (overButton == 2) { e.Graphics.FillRectangle(new SolidBrush(Color.Green), this.Width - 14, this.Height - 14, 12, 12); e.Graphics.FillRectangle(new SolidBrush(Color.Gray), 2, this.Height - 13, 116, 12); e.Graphics.DrawString("Rotate 90 degrees right", new Font("Arial", 8), new SolidBrush(Color.White), 2, this.Height - 14); } else e.Graphics.FillRectangle(new SolidBrush(Color.DarkGreen), this.Width - 14, this.Height - 14, 12, 12); e.Graphics.DrawEllipse(new Pen(new SolidBrush(Color.White), 1), this.Width - 11, this.Height - 11, 6, 6); e.Graphics.DrawEllipse(new Pen(new SolidBrush(Color.White), 1), this.Width - 25, this.Height - 11, 6, 6); if (overButton == 1) e.Graphics.FillRectangle(new SolidBrush(Color.Green), this.Width - 25, this.Height - 6, 4, 4); else e.Graphics.FillRectangle(new SolidBrush(Color.DarkGreen), this.Width - 25, this.Height - 6, 4, 4); if (overButton == 2) e.Graphics.FillRectangle(new SolidBrush(Color.Green), this.Width - 8, this.Height - 6, 4, 4); else e.Graphics.FillRectangle(new SolidBrush(Color.DarkGreen), this.Width - 8, this.Height - 6, 4, 4); e.Graphics.FillPolygon(new SolidBrush(Color.White), new Point[] { new Point(this.Width - 7, this.Height - 8), new Point(this.Width - 3, this.Height - 8), new Point(this.Width - 5, this.Height - 4) }); e.Graphics.FillPolygon(new SolidBrush(Color.White), new Point[] { new Point(this.Width - 26, this.Height - 8), new Point(this.Width - 21, this.Height - 8), new Point(this.Width - 25, this.Height - 4) }); } protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e) { // Handle rotation adjustment button clicks. if (e.X >= this.Width - 28 && e.X <= this.Width - 2 && e.Y >= this.Height - 14 && e.Y <= this.Height - 2) { if (e.X <= this.Width - 16) rotation -= 90; else if (e.X >= this.Width - 14) rotation += 90; if (rotation < 0) rotation += 360; rotation = rotation % 360; dbx = -10; dby = -10; } else UpdateAngle(e.X, e.Y); this.Refresh(); } protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e) { if (e.Button == MouseButtons.Left) { UpdateAngle(e.X, e.Y); overButton = -1; } else if (e.X >= this.Width - 28 && e.X <= this.Width - 16 && e.Y >= this.Height - 14 && e.Y <= this.Height - 2) overButton = 1; else if (e.X >= this.Width - 14 && e.X <= this.Width - 2 && e.Y >= this.Height - 14 && e.Y <= this.Height - 2) overButton = 2; else overButton = -1; this.Refresh(); } private void UpdateAngle(int mx, int my) { // Store mouse coordinates. dbx = mx; dby = my; // Translate y coordinate input to GetAngle function to correct for ellipsoid distortion. double widthToHeightRatio = (double)this.Width / (double)this.Height; int tmy; if (my == 0) tmy = my; else if (my < this.Height / 2) tmy = (this.Height / 2) - (int)(((this.Height / 2) - my) * widthToHeightRatio); else tmy = (this.Height / 2) + (int)((double)(my - (this.Height / 2)) * widthToHeightRatio); // Retrieve updated angle based on rise over run. angle = (GetAngle(this.Width / 2, this.Height / 2, mx, tmy) - rotation) % 360; } private double GetAngle(int x1, int y1, int x2, int y2) { double degrees; // Avoid divide by zero run values. if (x2 - x1 == 0) { if (y2 > y1) degrees = 90; else degrees = 270; } else { // Calculate angle from offset. double riseoverrun = (double)(y2 - y1) / (double)(x2 - x1); double radians = Math.Atan(riseoverrun); degrees = radians * ((double)180 / Math.PI); // Handle quadrant specific transformations. if ((x2 - x1) < 0 || (y2 - y1) < 0) degrees += 180; if ((x2 - x1) > 0 && (y2 - y1) < 0) degrees -= 180; if (degrees < 0) degrees += 360; } return degrees; } } public class AngleEditorTestControl : System.Windows.Forms.UserControl { private double int_angle; [BrowsableAttribute(true)] [Editor(typeof(AngleEditor), typeof(System.Drawing.Design.UITypeEditor))] public double Angle { get { return int_angle; } set { int_angle = value; } } public AngleEditorTestControl() { int_angle = 90; this.Size = new Size(190, 42); this.BackColor = Color.Beige; } protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) { if (this.DesignMode) { e.Graphics.DrawString("Use the Properties Window to access", new Font("Arial", 8), new SolidBrush(Color.Black), 3, 2); e.Graphics.DrawString("the AngleEditor UITypeEditor by", new Font("Arial", 8), new SolidBrush(Color.Black), 3, 14); e.Graphics.DrawString("configuring the \"Angle\" property.", new Font("Arial", 8), new SolidBrush(Color.Black), 3, 26); } else e.Graphics.DrawString("This example requires design mode.", new Font("Arial", 8), new SolidBrush(Color.Black), 3, 2); } } }
namespace MyLib { using System; using System.ComponentModel; using System.ComponentModel.Design; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Design; using System.Windows.Forms; using System.Diagnostics; using System.Windows.Forms.Design; [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")] public class FlashTrackBar : System.Windows.Forms.Control { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.Container components; private const int LeftRightBorder = 10; private int value = 0; private int min = 0; private int max = 100; private bool showPercentage = false; private bool showValue = false; private bool allowUserEdit = true; private bool showGradient = true; private int dragValue = 0; private bool dragging = false; private Color startColor = Color.Red; private Color endColor = Color.LimeGreen; private EventHandler onValueChanged; private Brush baseBackground = null; private Brush backgroundDim = null; private byte darkenBy = 200; public FlashTrackBar() { // // Required for Windows Form Designer support // InitializeComponent(); SetStyle(ControlStyles.Opaque, true); SetStyle(ControlStyles.ResizeRedraw, true); Debug.Assert(GetStyle(ControlStyles.ResizeRedraw), "Should be redraw!"); } /// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose(bool disposing) { if (disposing) { if (components != null) { components.Dispose(); } } base.Dispose(disposing); } /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.ForeColor = System.Drawing.Color.White; this.BackColor = System.Drawing.Color.Black; this.Size = new System.Drawing.Size(100, 23); this.Text = "FlashTrackBar"; } [ Category("Flash"), DefaultValue(true) ] public bool AllowUserEdit { get { return allowUserEdit; } set { if (value != allowUserEdit) { allowUserEdit = value; if (!allowUserEdit) { Capture = false; dragging = false; } } } } [ Category("Flash") ] public Color EndColor { get { return endColor; } set { endColor = value; if (baseBackground != null && showGradient) { baseBackground.Dispose(); baseBackground = null; } Invalidate(); } } public bool ShouldSerializeEndColor() { return !(endColor == Color.LimeGreen); } [ Category("Flash"), Editor(typeof(FlashTrackBarDarkenByEditor), typeof(UITypeEditor)), DefaultValue((byte)200) ] public byte DarkenBy { get { return darkenBy; } set { if (value != darkenBy) { darkenBy = value; if (backgroundDim != null) { backgroundDim.Dispose(); backgroundDim = null; } OptimizedInvalidate(Value, max); } } } [ Category("Flash"), DefaultValue(100) ] public int Max { get { return max; } set { if (max != value) { max = value; Invalidate(); } } } [ Category("Flash"), DefaultValue(0) ] public int Min { get { return min; } set { if (min != value) { min = value; Invalidate(); } } } [ Category("Flash") ] public Color StartColor { get { return startColor; } set { startColor = value; if (baseBackground != null && showGradient) { baseBackground.Dispose(); baseBackground = null; } Invalidate(); } } public bool ShouldSerializeStartColor() { return !(startColor == Color.Red); } [ Category("Flash"), RefreshProperties(RefreshProperties.Repaint), DefaultValue(false) ] public bool ShowPercentage { get { return showPercentage; } set { if (value != showPercentage) { showPercentage = value; if (showPercentage) { showValue = false; } Invalidate(); } } } [ Category("Flash"), RefreshProperties(RefreshProperties.Repaint), DefaultValue(false) ] public bool ShowValue { get { return showValue; } set { if (value != showValue) { showValue = value; if (showValue) { showPercentage = false; } Invalidate(); } } } [ Category("Flash"), DefaultValue(true) ] public bool ShowGradient { get { return showGradient; } set { if (value != showGradient) { showGradient = value; if (baseBackground != null) { baseBackground.Dispose(); baseBackground = null; } Invalidate(); } } } [ Category("Flash"), Editor(typeof(FlashTrackBarValueEditor), typeof(UITypeEditor)), DefaultValue(0) ] public int Value { get { if (dragging) { return dragValue; } return value; } set { if (value != this.value) { int old = this.value; this.value = value; OnValueChanged(EventArgs.Empty); OptimizedInvalidate(old, this.value); } } } // ValueChanged Event [Description("Raised when the Value displayed changes")] public event EventHandler ValueChanged { add { onValueChanged += value; } remove { onValueChanged -= value; } } private void OptimizedInvalidate(int oldValue, int newValue) { Rectangle client = ClientRectangle; float oldPercentValue = ((float)oldValue / ((float)Max - (float)Min)); int oldNonDimLength = (int)(oldPercentValue * (float)client.Width); float newPercentValue = ((float)newValue / ((float)Max - (float)Min)); int newNonDimLength = (int)(newPercentValue * (float)client.Width); int min = Math.Min(oldNonDimLength, newNonDimLength); int max = Math.Max(oldNonDimLength, newNonDimLength); Rectangle invalid = new Rectangle( client.X + min, client.Y, max - min, client.Height); Invalidate(invalid); string oldToDisplay; string newToDisplay; if (ShowPercentage) { oldToDisplay = Convert.ToString((int)(oldPercentValue * 100f)) + "%"; newToDisplay = Convert.ToString((int)(newPercentValue * 100f)) + "%"; } else if (ShowValue) { oldToDisplay = Convert.ToString(oldValue); newToDisplay = Convert.ToString(newValue); } else { oldToDisplay = null; newToDisplay = null; } if (oldToDisplay != null && newToDisplay != null) { Graphics g = CreateGraphics(); SizeF oldFontSize = g.MeasureString(oldToDisplay, Font); SizeF newFontSize = g.MeasureString(newToDisplay, Font); RectangleF oldFontRect = new RectangleF(new PointF(0, 0), oldFontSize); RectangleF newFontRect = new RectangleF(new PointF(0, 0), newFontSize); oldFontRect.X = (client.Width - oldFontRect.Width) / 2; oldFontRect.Y = (client.Height - oldFontRect.Height) / 2; newFontRect.X = (client.Width - newFontRect.Width) / 2; newFontRect.Y = (client.Height - newFontRect.Height) / 2; Invalidate(new Rectangle((int)oldFontRect.X, (int)oldFontRect.Y, (int)oldFontRect.Width, (int)oldFontRect.Height)); Invalidate(new Rectangle((int)newFontRect.X, (int)newFontRect.Y, (int)newFontRect.Width, (int)newFontRect.Height)); } } protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); if (!allowUserEdit) { return; } Capture = true; dragging = true; SetDragValue(new Point(e.X, e.Y)); } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (!allowUserEdit || !dragging) { return; } SetDragValue(new Point(e.X, e.Y)); } protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); if (!allowUserEdit || !dragging) { return; } Capture = false; dragging = false; value = dragValue; OnValueChanged(EventArgs.Empty); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); if (baseBackground == null) { if (showGradient) { baseBackground = new LinearGradientBrush(new Point(0, 0), new Point(ClientSize.Width, 0), StartColor,EndColor); } else if (BackgroundImage != null) { baseBackground = new TextureBrush(BackgroundImage); } else { baseBackground = new SolidBrush(BackColor); } } if (backgroundDim == null) { backgroundDim = new SolidBrush(Color.FromArgb(DarkenBy, Color.Black)); } Rectangle toDim = ClientRectangle; float percentValue = ((float)Value / ((float)Max - (float)Min)); int nonDimLength = (int)(percentValue * (float)toDim.Width); toDim.X += nonDimLength; toDim.Width -= nonDimLength; string text = Text; string toDisplay = null; RectangleF textRect = new RectangleF(); if (ShowPercentage || ShowValue || text.Length > 0) { if (ShowPercentage) { toDisplay = Convert.ToString((int)(percentValue * 100f)) + "%"; } else if (ShowValue) { toDisplay = Convert.ToString(Value); } else { toDisplay = text; } SizeF textSize = e.Graphics.MeasureString(toDisplay, Font); textRect.Width = textSize.Width; textRect.Height = textSize.Height; textRect.X = (ClientRectangle.Width - textRect.Width) / 2; textRect.Y = (ClientRectangle.Height - textRect.Height) / 2; } e.Graphics.FillRectangle(baseBackground, ClientRectangle); e.Graphics.FillRectangle(backgroundDim, toDim); e.Graphics.Flush(); if (toDisplay != null && toDisplay.Length > 0) { e.Graphics.DrawString(toDisplay, Font, new SolidBrush(ForeColor), textRect); } } protected override void OnTextChanged(EventArgs e) { base.OnTextChanged(e); Invalidate(); } protected override void OnBackColorChanged(EventArgs e) { base.OnTextChanged(e); if ((baseBackground != null) && (!showGradient)) { baseBackground.Dispose(); baseBackground = null; } } protected override void OnBackgroundImageChanged(EventArgs e) { base.OnTextChanged(e); if ((baseBackground != null) && (!showGradient)) { baseBackground.Dispose(); baseBackground = null; } } protected override void OnResize(EventArgs e) { base.OnResize(e); if (baseBackground != null) { baseBackground.Dispose(); baseBackground = null; } } protected virtual void OnValueChanged(EventArgs e) { if (onValueChanged != null) { onValueChanged.Invoke(this, e); } } private void SetDragValue(Point mouseLocation) { Rectangle client = ClientRectangle; if (client.Contains(mouseLocation)) { float percentage = (float)mouseLocation.X / (float)ClientRectangle.Width; int newDragValue = (int)(percentage * (float)(max - min)); if (newDragValue != dragValue) { int old = dragValue; dragValue = newDragValue; OptimizedInvalidate(old, dragValue); } } else { if (client.Y <= mouseLocation.Y && mouseLocation.Y <= client.Y + client.Height) { if (mouseLocation.X <= client.X && mouseLocation.X > client.X - LeftRightBorder) { int newDragValue = min; if (newDragValue != dragValue) { int old = dragValue; dragValue = newDragValue; OptimizedInvalidate(old, dragValue); } } else if (mouseLocation.X >= client.X + client.Width && mouseLocation.X < client.X + client.Width + LeftRightBorder) { int newDragValue = max; if (newDragValue != dragValue) { int old = dragValue; dragValue = newDragValue; OptimizedInvalidate(old, dragValue); } } } else { if (dragValue != value) { int old = dragValue; dragValue = value; OptimizedInvalidate(old, dragValue); } } } } } public class FlashTrackBarDarkenByEditor : FlashTrackBarValueEditor { protected override void SetEditorProps(FlashTrackBar editingInstance, FlashTrackBar editor) { base.SetEditorProps(editingInstance, editor); editor.Min = 0; editor.Max = byte.MaxValue; } } public class FlashTrackBarValueEditor : System.Drawing.Design.UITypeEditor { private IWindowsFormsEditorService edSvc = null; protected virtual void SetEditorProps(FlashTrackBar editingInstance, FlashTrackBar editor) { editor.ShowValue = true; editor.StartColor = Color.Navy; editor.EndColor = Color.White; editor.ForeColor = Color.White; editor.Min = editingInstance.Min; editor.Max = editingInstance.Max; } public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { if (context != null && context.Instance != null && provider != null) { edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)); if (edSvc != null) { FlashTrackBar trackBar = new FlashTrackBar(); trackBar.ValueChanged += new EventHandler(this.ValueChanged); SetEditorProps((FlashTrackBar)context.Instance, trackBar); bool asInt = true; if (value is int) { trackBar.Value = (int)value; } else if (value is byte) { asInt = false; trackBar.Value = (byte)value; } edSvc.DropDownControl(trackBar); if (asInt) { value = trackBar.Value; } else { value = (byte)trackBar.Value; } } } return value; } public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { if (context != null && context.Instance != null) { return UITypeEditorEditStyle.DropDown; } return base.GetEditStyle(context); } private void ValueChanged(object sender, EventArgs e) { if (edSvc != null) { edSvc.CloseDropDown(); } } } }
本文配套源碼