How to draw a window at Mouse coordination in OnMouseMove

Created at 27 Feb 2021, 13:39
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
NO

noppanon

Joined 17.05.2017

How to draw a window at Mouse coordination in OnMouseMove
27 Feb 2021, 13:39


Hi there,

   I try to draw a small window similar to Market Snapshot window when user select the cursor. I'd like to my custom data. However, when I draw, the window is drawn a bit off from my mouse pointer. See the sample.

The blue dot is my mouse pointer. 

 

 

Here is my code. The DataForm is just a plain WinForm.

using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class CustomData : Indicator
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }

        [Output("Main")]
        public IndicatorDataSeries Result { get; set; }

        protected DataForm DataTip;

        protected override void Initialize()
        {
            Chart.MouseMove += OnMouseMove;
            Chart.MouseLeave += OnMouseLeave;

            DataTip = new DataForm();
            DataTip.Show();
            DataTip.Visible = false;
        }

        public override void Calculate(int index)
        {
            // Calculate value at specified index
            // Result[index] = ...
        }

        protected void OnMouseMove(ChartMouseEventArgs obj)
        {
            Chart chart = obj.Chart;

            if (chart != null)
            {
                if (!DataTip.Visible)
                {
                    DataTip.Visible = true;
                    DataTip.Show();
                    DataTip.TopMost = true;
                }
                var x = (int)Math.Round(obj.MouseX, 0);
                var y = (int)Math.Round(obj.MouseY, 0);

                DataTip.Location = new System.Drawing.Point(x, y);

                Print("mouse X {0}   mouse Y {1}", obj.MouseX, obj.MouseY);

            }
        }

        protected void OnMouseLeave(ChartMouseEventArgs obj)
        {
            if (obj.Chart != null)
            {
                DataTip.Visible = false;
            }
        }

    }
}

 

Thanks in advance

 

Noppanon

 


@noppanon
Replies

amusleh
01 Mar 2021, 11:29 ( Updated at: 01 Mar 2021, 11:30 )

The issue with your code is that you are using mouse position on chart not screen, the window form location (x,y) is based on your screen coordinates not chart.

To solve the issue you have two option, either use the chart controls or use Windows API to get the location of mouse on your screen.

Here is an example of how you can show a tooltip with chart controls:

using cAlgo.API;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class CustomData : Indicator
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }

        [Output("Main")]
        public IndicatorDataSeries Result { get; set; }

        private Tooltip _tooltip;

        protected override void Initialize()
        {
            var content = new TextBlock { Text = "Here you can put any control", Margin = 5 };

            _tooltip = new Tooltip(content)
            {
                VerticalAlignment = VerticalAlignment.Top,
                HorizontalAlignment = HorizontalAlignment.Left,
                IsVisible = false,
                Width = 160,
                Height = 40
            };

            Chart.AddControl(_tooltip);

            Chart.MouseMove += OnMouseMove;
            Chart.MouseLeave += OnMouseLeave;
            Chart.MouseEnter += Chart_MouseEnter;
        }

        private void Chart_MouseEnter(ChartMouseEventArgs obj)
        {
            _tooltip.IsVisible = true;
        }

        public override void Calculate(int index)
        {
            // Calculate value at specified index
            // Result[index] = ...
        }

        protected void OnMouseMove(ChartMouseEventArgs obj)
        {
            var extraDelta = 10;
            var width = _tooltip.Width;
            var height = _tooltip.Height;
            var left = Chart.Width - obj.MouseX > width + extraDelta ? obj.MouseX + extraDelta : obj.MouseX - width - extraDelta;
            var right = Chart.Height - obj.MouseY > height + extraDelta ? obj.MouseY + extraDelta : obj.MouseY - height - extraDelta;

            _tooltip.Margin = new Thickness(left, right, 0, 0);
        }

        protected void OnMouseLeave(ChartMouseEventArgs obj)
        {
            _tooltip.IsVisible = false;
        }
    }

    public class Tooltip : CustomControl
    {
        public Tooltip(ControlBase content)
        {
            var border = new Border
            {
                BackgroundColor = "#3F3F3F",
                BorderColor = "#969696",
                BorderThickness = 1,
                CornerRadius = 5
            };

            border.Child = content;

            AddChild(border);
        }
    }
}

If you want to use a Windows form then you have to use the Windows API to get the mouse location on screen.

For using Windows API you can use my GlobalHook library: 

 

Example:

using cAlgo.API;
using Gma.UserActivityMonitor;
using System;
using System.Threading;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class CustomData : Indicator
    {
        private DataForm _dataForm = new DataForm();

        private Thread _appThread;

        protected override void Initialize()
        {
            Chart.MouseLeave += OnMouseLeave;
            Chart.MouseEnter += Chart_MouseEnter;

            RunApplicationThread();
        }

        public override void Calculate(int index)
        {
        }

        private void HookManager_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            _dataForm.Location = e.Location;
        }

        private void Chart_MouseEnter(ChartMouseEventArgs obj)
        {
            _dataForm.Visible = true;

            _dataForm.TopMost = true;
        }

        protected void OnMouseLeave(ChartMouseEventArgs obj)
        {
            _dataForm.Visible = false;
        }

        private void RunApplicationThread()
        {
            _appThread = new Thread(() =>
            {
                try
                {
                    HookManager.MouseMove += HookManager_MouseMove;

                    // Without a running application loop the global hook will not work!
                    System.Windows.Forms.Application.Run(_dataForm);

                    _dataForm.Visible = false;
                }
                catch (Exception ex)
                {
                    Print(ex);
                }
            });

            _appThread.SetApartmentState(ApartmentState.STA);
            _appThread.DisableComObjectEagerCleanup();

            _appThread.Start();
        }
    }
}

 

If you use a windows form as a tooltip and move it alongside mouse cursor it will use too much resource so I recommend you to use chart controls instead.


@amusleh

... Deleted by UFO ...

noppanon
05 Mar 2021, 13:50

Thanks amusleh. It works even better than cTrader market snapshot.

Noppanon


@noppanon