Работа с клавиатурой и мышью. Основы

Индикаторы умеют реагировать на события нажатия клавиш клавиатуры, нажатия клавиш мыши, перемещения мыши.

Для этих целей предусмотрены следующие методы, которые можно переопределить в своем индикаторе:

  • ProcessMouseClick(RenderControlMouseEventArgs e) - обработка кликов мыши
  • ProcessMouseDown(RenderControlMouseEventArgs e) - обработка нажатия клавиши мыши
  • ProcessMouseUp(RenderControlMouseEventArgs e) - обработка отпускания клавиши мыши
  • ProcessMouseMove(RenderControlMouseEventArgs e) - обработка движения мыши
  • ProcessMouseDoubleClick(RenderControlMouseEventArgs e) - обработка двойного клика мыши
  • ProcessKeyDown(KeyEventArgs e) - обработка нажатия на клавишу клавиатуры
  • ProcessKeyUp(KeyEventArgs e) - обработка отпускания клавиши клавиатуры

Каждый из этих методов должен возвращать true либо false.

Если метод возвращает true, это обозначает, что индикатор данное событие обработал и данное событие не нужно вызывать у следующих индикаторов.

Такая логика нужна для ситуаций, когда на графике есть ряд индикаторов и событие должен обработать только один из них(тот, который первый обработал событие). 

Также, в некоторых случаях в зависимости от положения мыши нужно иметь возможность менять курсор. Для этого предусмотрен метод GetCursor(RenderControlMouseEventArgs e). 

Переопределив данный метод, можно возвращать курсор в зависимости от положения мыши

Пример работы с данными событиями:

public class SampleKeyboardAndMouseProcessor : Indicator
    {
        private bool _selected;
        private Rectangle _rectangle=new Rectangle(30,30,150,50);
        private Point _pressedPoint;
        private Point _lastPoint;
        private bool _pressed;

        public SampleKeyboardAndMouseProcessor()
            : base(true)
        {
            EnableCustomDrawing = true;
            DenyToChangePanel = true;
            DataSeries[0].IsHidden = true;
            SubscribeToDrawingEvents(DrawingLayouts.Final);
        }

        #region Overrides of BaseIndicator

        protected override void OnCalculate(int bar, decimal value)
        {

        }

        #endregion

        protected override void OnRender(RenderContext context, DrawingLayouts layout)
        {
            context.FillRectangle(System.Drawing.Color.Coral, _rectangle);

            if (_selected)
                context.DrawRectangle(new RenderPen(System.Drawing.Color.Blue, 3), _rectangle);

            context.DrawString(DateTime.Now.ToString("T"),new RenderFont("Arial",20),System.Drawing.Color.AliceBlue, _rectangle, new RenderStringFormat(){LineAlignment = StringAlignment.Center, Alignment = StringAlignment.Center});
        }

        public override bool ProcessMouseClick(RenderControlMouseEventArgs e)
        {
            this.LogInfo("Mouse click");

            return false;
        }

        public override bool ProcessMouseDown(RenderControlMouseEventArgs e)
        {
            this.LogInfo("Mouse down");

            if (e.Button == RenderControlMouseButtons.Left && IsPointInsideRectangle(_rectangle, e.Location))
            {
                _pressedPoint = _lastPoint = e.Location;
                _pressed = true;
                
                return true;
            }

            return false;
        }

        public override bool ProcessMouseUp(RenderControlMouseEventArgs e)
        {
            this.LogInfo("Mouse up");

            if (Math.Abs(e.Location.X- _pressedPoint.X)<4 && Math.Abs(e.Location.Y - _pressedPoint.Y) < 4 && e.Button == RenderControlMouseButtons.Left && IsPointInsideRectangle(_rectangle, e.Location))
            {
                _selected = !_selected;
                _pressed = false;

                return true;
            }

            if (_pressed)
            {
                _pressed = false;

                return true;
            }

            return false;
        }

        public override bool ProcessMouseMove(RenderControlMouseEventArgs e)
        {
            if (_pressed && _selected)
            {
                var dX = e.Location.X - _lastPoint.X;
                var dY = e.Location.Y - _lastPoint.Y;
                _lastPoint = e.Location;
                _rectangle.X += dX;
                _rectangle.Y += dY;

                return true;
            }

            return false;
        }

        public override bool ProcessMouseDoubleClick(RenderControlMouseEventArgs e)
        {
            this.LogInfo("Mouse double click");

            return false;
        }

        public override bool ProcessKeyDown(KeyEventArgs e)
        {
            this.LogInfo("Key down {0}",e.Key);

            return false;
        }

        public override bool ProcessKeyUp(KeyEventArgs e)
        {
            this.LogInfo("Key up {0}", e.Key);

            return false;
        }

        public override StdCursor GetCursor(RenderControlMouseEventArgs e)
        {
            if(_selected&&IsPointInsideRectangle(_rectangle,e.Location))
                return StdCursor.Hand;

            return StdCursor.NULL;
        }

        private bool IsPointInsideRectangle(Rectangle rectangle, Point point)
        {
            return point.X >= rectangle.X && point.X <= rectangle.X + rectangle.Width && point.Y >= rectangle.Y && point.Y <= rectangle.Y + rectangle.Height;
        }
    }