Tôi đã mã hóa một ứng dụng mẫu nhỏ có khung điều khiển của riêng nó bằng cách vẽ trên biểu mẫu bằng .Net C#. Chỉ cần một cái gì đó đơn giản với kết quả này:
tôi đã thực hiện các IsSelected bằng cách đệ quy vô hiệu hóa tất cả các điều khiển và chuyển đổi qua lại các nhấp một. Xem phần với window.MouseUp += (sender, arg) =>
.
Lựa chọn có thể đi qua chuột hoặc phím Tab.
Cách tiếp cận mã nên được di chuyển sang các ngôn ngữ khác và có thể dịch trực tuyến sang VB.Net.
đoạn có liên quan của mã:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
using System.Threading.Tasks;
namespace CustomGUI
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form window = new Form1();
window.BackColor = Color.Gray;
Graphics api = window.CreateGraphics();
GUIControl form = new GUIControl();
form.Location = new Point(30,30);
form.Size = new Size(200, 300);
GUIControl control1 = new GUIControl();
control1.Location = new Point(0, 0);
control1.Size = new Size(200, 130);
control1.Background = Color.Blue;
GUIControl control11 = new GUIControl();
control11.Location = new Point(140, 30);
control11.Size = new Size(30, 30);
control11.Background = Color.Red;
GUIControl control12 = new GUIControl();
control12.Location = new Point(30, 30);
control12.Size = new Size(30, 30);
control12.Background = Color.Red;
control12.BorderColor = Color.Green;
control12.BorderWidth = 5;
GuiLabel control2 = new GuiLabel();
control2.Location = new Point(10, 200);
control2.Size = new Size(180, 30);
control2.Background = Color.Green;
control2.Text = "Hello World!";
control1.AddChild(control11);
control1.AddChild(control12);
form.AddChild(control1);
form.AddChild(control2);
window.MouseUp += (sender, arg) =>
{
// hit test the control where the mouse has landed
IGUIContainer control = form.HitTest(arg.Location);
if (control != null)
{
// recursive on all controls
foreach (var ct in (new IGUIContainer[] { form }).Traverse(c => c.Controls))
{
//deselecting all others
if (ct != control) ct.IsSelected = false;
}
control.IsSelected = !control.IsSelected;
}
window.Invalidate(); // force paint
};
window.KeyUp += (sender, key) =>
{
if (key.KeyCode == Keys.Tab && key.Modifiers == Keys.None)
{
var selected = (new IGUIContainer[] { form }).Traverse(c => c.Controls).FirstOrDefault(c => c.IsSelected);
IGUIContainer parent;
if (selected == null)
{
parent = form;
}
else
{
parent = selected;
}
IGUIContainer control;
if (parent.Controls.Count > 0)
{
control = parent.Controls[0];
}
else
{
control = GUIControl.Next(parent);
}
if (control == null) control = form;
foreach (var ct in (new IGUIContainer[] { form }).Traverse(c => c.Controls))
{
if (ct != control) ct.IsSelected = false;
}
control.IsSelected = true;
window.Invalidate();
}
};
window.Paint += (sender, args) =>
{
form.Draw(api, new Point(0,0));
};
Application.Run(window);
}
}
}
Tất cả các lớp học cần thiết và giao diện:
IDrawable:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace CustomGUI
{
public interface IDrawable
{
Point Location { get; set; }
Size Size { get; set; }
Rectangle GetRealRect(Point origin);
void Draw(Graphics gfxApi, Point origin);
}
}
IGUIContainer:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace CustomGUI
{
delegate void SelectionChangedHandler(object sender, bool newIsSelected);
interface IGUIContainer : IUIElement
{
IGUIContainer Parent { get; set; }
List<IGUIContainer> Controls { get; }
void AddChild(IGUIContainer child);
bool IsSelected { get; set; }
event SelectionChangedHandler SelectionChanged;
IGUIContainer HitTest(Point mouseCoord);
}
}
UIElement:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Diagnostics;
namespace CustomGUI
{
abstract class UIElement : IUIElement
{
private Point _location;
private Size _size;
private Color _background;
private Color _foreground;
private Color _borderColor;
private int _borderWidth;
public UIElement()
{
_foreground = Color.Black;
_background = Color.White;
_borderColor = Color.Transparent;
}
public Point Location
{
get
{
return _location;
}
set
{
_location = value;
}
}
public Size Size
{
get
{
return _size;
}
set
{
_size = value;
}
}
public virtual void Draw(Graphics drawingApi, Point origin)
{
Rectangle inside = GetRealRect(origin);
Pen borderPen = new Pen(new SolidBrush(_borderColor), _borderWidth);
drawingApi.FillRectangle(new SolidBrush(_background), inside);
drawingApi.DrawRectangle(borderPen, inside);
}
public Rectangle ClientRect
{
get
{
return new Rectangle(_location, _size);
}
}
public Color Background
{
get
{
return _background;
}
set
{
_background = value;
}
}
public Color Foreground
{
get
{
return _foreground;
}
set
{
_foreground = value;
}
}
public Rectangle GetRealRect(Point origin)
{
int left = ClientRect.Left + origin.X;
int top = ClientRect.Top + origin.Y;
int width = ClientRect.Width;
int height = ClientRect.Height;
Debug.WriteLine("GetRealRect " + left + ", " + top + ", " + width + ", " + height);
return new Rectangle(left, top, width, height);
}
public int BorderWidth
{
get
{
return _borderWidth;
}
set
{
_borderWidth = value;
}
}
public Color BorderColor
{
get
{
return _borderColor;
}
set
{
_borderColor = value;
}
}
}
}
GUIControl:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace CustomGUI
{
class GUIControl : UIElement, IGUIContainer
{
private IGUIContainer _parent;
private List<IGUIContainer> _controls = new List<IGUIContainer>();
private bool _isSelected;
public List<IGUIContainer> Controls
{
get
{
return _controls;
}
}
public override void Draw(Graphics api, Point origin)
{
Point original = origin;
base.Draw(api, origin);
origin.Offset(this.Location);
foreach (var ctrl in Controls)
{
ctrl.Draw(api, origin);
}
if (IsSelected)
{
Pen selection = new Pen(Color.Yellow, 3);
selection.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
api.DrawRectangle(selection, GetRealRect(original));
}
}
public IGUIContainer HitTest(Point coord)
{
Point newOrigin = coord;
newOrigin.Offset(-this.Location.X, -this.Location.Y);
foreach (var ctrl in Controls)
{
IGUIContainer hit = ctrl.HitTest(newOrigin);
if (hit != null)
{
return hit;
}
}
return ClientRect.Contains(coord) ? this : null;
}
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
if (SelectionChanged != null)
{
SelectionChanged(this, _isSelected);
}
}
}
public event SelectionChangedHandler SelectionChanged;
public void AddChild(IGUIContainer child)
{
// if you need to implement event propagation this is the place to attach them to children
child.Parent = this;
Controls.Add(child);
}
public IGUIContainer Parent
{
get
{
return _parent;
}
set
{
_parent = value;
}
}
public static IGUIContainer Next(IGUIContainer self)
{
if (self.Parent != null &&
self.Parent.Controls.Count - 1 > self.Parent.Controls.IndexOf(self))
{
return self.Parent.Controls[self.Parent.Controls.IndexOf(self) + 1];
}
else if (self.Parent != null)
{
return Next(self.Parent);
}
else
{
return null;
}
}
}
}
GUILabel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace CustomGUI
{
class GuiLabel : GUIControl
{
public string Text { get; set; }
public Font Font { get; set; }
public GuiLabel()
{
Font = new Font(new FontFamily("Tahoma"), 12, FontStyle.Regular);
}
public override void Draw(System.Drawing.Graphics api, System.Drawing.Point origin)
{
base.Draw(api, origin);
Rectangle controlRect = GetRealRect(origin);
SizeF size = api.MeasureString(Text, Font);
Point textPosition = new Point(controlRect.Location.X + (int)(controlRect.Width - size.Width)/2,
controlRect.Location.Y + (int)(controlRect.Height - size.Height)/2);
api.DrawString(Text, Font, new SolidBrush(Foreground), textPosition);
}
}
}
mở rộng (đối với phương pháp Traverse để san bằng đệ quy):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CustomGUI
{
static class Extensions
{
public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse)
{
foreach (T item in source)
{
yield return item;
IEnumerable<T> seqRecurse = fnRecurse(item);
if (seqRecurse != null)
{
foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse))
{
yield return itemRecurse;
}
}
}
}
}
}