- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
在一个没有可用的真实库的平台上,除了“坐标(x,y)处的维度(x,y,xx,yy)的显示对象之外的最小图形,我正在尝试创建一个简单的图形用户界面。
谁能给我指出一个引用资料,我可以在其中理解在屏幕上显示一组对象和突出显示所选对象所涉及的逻辑原则,从而允许用户在对象之间导航并将突出显示移动到每个对象。看起来应该很简单,但我想了解人们对此的看法。
如何使用像 obj.highlight() 这样的方法创建一个对象,其中 obj.highlight 会关闭所有其他对象的突出显示?是否可以简单地对一组对象执行 for next 循环,跳过当前对象,关闭突出显示,然后将当前对象设置为 true?突出显示将通过在具有透明中心的所选对象的顶部绘制另一个对象来完成。
这是一个单线程系统,(但允许少量的异步处理)。
我正在寻找更多的概念性想法,但不使用专有图形调用的 VB 代码可能会有用。
最佳答案
我编写了一个小型示例应用程序,它通过使用 .Net C# 在窗体上绘制来执行自己的控制框架。这个结果只是一些简单的事情:
我通过递归禁用所有控件并切换单击的控件来完成 IsSelected。查看带有 window.MouseUp += (sender, arg) =>
的部分。
选择可以通过鼠标或Tab键。
代码方法应该可以移植到其他语言,并且可以在线翻译成 VB.Net。
相关代码片段:
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);
}
}
}
所有需要的类和接口(interface):
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);
}
}
}
扩展(用于扁平化递归的遍历方法):
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;
}
}
}
}
}
}
关于algorithm - 从头开始创建一个简单的 GUI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6513674/
我需要用这样的数据构建一个表: ┌────────┬───────────┬────────┐ │ ID │ Name │ Age │ ├────
我是一名优秀的程序员,十分优秀!