6

利用可能な実際のライブラリがなく、「座標 (x,y) の次元 (x,y,xx,yy) の表示オブジェクト」以外の最小限のグラフィックしかないプラットフォームで、単純な GUI を作成しようとしています。

画面上に一連のオブジェクトを表示し、選択したオブジェクトを強調表示して、ユーザーがオブジェクト間を移動し、強調表示を各オブジェクトに移動できるようにするためのロジスティクスの原則を理解できるリファレンスを教えてください。簡単にできるように思えますが、人々がこれについてどのように考えているかを理解したいと思います。

obj.highlight() のようなメソッドを使用して、obj.highlight が他のすべてのオブジェクトのハイライトをオフにするオブジェクトを作成するにはどうすればよいでしょうか? オブジェクトの配列を介して for next ループを実行し、現在のオブジェクトをスキップし、強調表示をオフにしてから、現在のオブジェクトを true に設定しますか? 強調表示は、選択したオブジェクトの上に透明な中心を持つ別のオブジェクトを描画することによって実現されます。

これはシングル スレッド システムです (ただし、少量の非同期処理が可能です)。

私は概念的なアイデアをもっと探していますが、独自のグラフィック呼び出しを使用しない VB のコードが役に立つかもしれません。

4

2 に答える 2

3

.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);
        }
    }
}

必要なすべてのクラスとインターフェース:

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);
    }
}

IGUIコンテナ:

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;
            }
        }
    }
}

GUI コントロール:

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;
            }
        }
    }
}

GUIラベル:

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);
        }
    }
}

拡張 (再帰を平坦化するための Traverse メソッド用):

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;

                    }

                }

            }

        }
    }
}
于 2011-06-29T03:15:04.920 に答える
2

それは百万通りの方法で答えることができる 1 つの質問です... :)

しかし、ピクセル (またはそれに似たもの) を描画できる限り、GUI を描画できます。手元にオブジェクト指向言語がある場合、現在のオブジェクトを強調表示および非強調表示することは選択しません。if focus を指定してフォーカスを削除し、オブジェクト自体に再描画する必要があるかどうか、および再描画する方法を決定させます。

すべてのオブジェクトが何らかのコンテナに配置されている場合、前のオブジェクトのフォーカスを自動的に解除できます。ナビゲーション キー (Tab など) を押すか、マウス ボタンを押すと、そのコンテナーはそのメッセージを処理し、次のオブジェクトにフォーカスし、最後のオブジェクトのフォーカスを外すことができます。

多少のプログラミングが必要ですが、概念は非常に簡単です。うまく機能させたい、滑らかに見せたい、あらゆる種類の注釈やトランジションを持たせたいと思うと、それは難しくなります... しかし、私が言ったように、概念は単純であり、それを行うのに OO さえ必要ありません。あなたははるかにきれいな結果です。必要に応じて、雨の午後に DOS Batch で ASCII ベースの GUI をプログラムできると思います。

于 2011-06-28T22:18:07.863 に答える