How to return mouse x and y positions relative to main window?

Hi Everyone.

Im trying to check the distance between the mouse position and a component. ill change some of the states of the component based on this distance.

From reading the documentation I’ve tried using getScreenX and getScreenY but they return a fixed value when printing to the console. How would I get constantly updated mouse x & y positions relative to the main window?

After looking in to the matter further, getScreenX and Y are not what I need. Im just after the mouse x and y values when the mouse is inside the UI.

you can subtract the screenPos of the component from the screenPos of the pluginEditor of your project. beware that pluginEditor != getTopLevelComponen() because in the standalone builds as well as hosts made with juce the topLevelComponent is that whole window instead of just your plugin’s one

Hey, so theres not a method that constantly returns the mouse x and y position then?

Ive got a component thats drawing a circle. Im using mouseEnter() to switch a boolean to true, I’m changing the colour of the circle component based on that bool inside paint. This is working but its changing the bool to true when the mouse is in the rectangular area specified in resize. I would like to the bool to switch when the mouse is inside the circle.

Which is why I’m asking from a way to keep track of the mouse position, I was going to use a distance function so when the distance between the middle of the circle component and the mouse position is less than the circle components radius it would switch the bool and change the colour of the component.

override the component’s hitTest to return true only if the length of a line from center to x,y is smaller than std::min(width,height)

May I be so bold as to ask if I can see some examples of the syntax on implementing hitTest() to work in my scenario, as I’m going round in circles (pun intended).

heres what my simple class looks like

MyBtn.h

class MyBtn  : public juce::Component
{
public:
    MyBtn();
    ~MyBtn() override;

    void paint (juce::Graphics&) override;
    void mouseEnter (const juce::MouseEvent& event) override;
    void mouseExit (const juce::MouseEvent& event) override;
    void resized() override;
    bool isEntered { false };
    
private:
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MyBtn)
};

MyBnt.cpp

MyBtn::MyBtn()
{
}

MyBtn::~MyBtn()
{
}

void MyBtn::paint (juce::Graphics& g)
{
    g.setColour(isEntered ? juce::Colours::black : juce::Colours::white);
    g.drawEllipse(1, 1, 60, 60, 1);
}

void MyBtn::mouseEnter(const juce::MouseEvent &event)
{
    isEntered = true;
}

void MyBtn::mouseExit(const juce::MouseEvent &event)
{
    isEntered = false;
}

void MyBtn::resized()
{ 
}

my circles outline currently changes then the mouse is with in the rectangular area specified when I set the bounds within resize in the mainComponent.cpp, but how might I use hitTest() to know wether the mouse is inside the radius of the circle component?

Apologise if this is like pulling teeth, Im still really new to JUCE.
Thanks.

first of all i’d make sure that the component’s width always equals its height, cause then you don’t have to type in absolute values like 0, 0, 60, 60 into igs paint method but you can just use getLocalBounds().

then you override hitTest(int x, int y).

hitTest is a virtual method of juce::Component, just like paint and resized. the base class’ implementation always returns true, meaning as long as your mouse event is inside of the component’s rectangle that component also consumes the events, typically in its mouse event methods, like mouseEnter, mouseDrag, mouseUp etc.

if you want only the circle to be clickable you have to make your own hitTest, where the length from the middle of the component does not exceed the circle’s radius. and if your component’s bounds define that circle’s size, as suggested in the beginning, your circle’s radius is getWidth() / 2

Right, so if I understand correctly. Mouse event methods, like mouseEnter, mouseDrag, mouseUp etc call hitTest() behind the scenes to figure out when the mouse is within the component, and when you override and write your own hitTest() it changes the mouse event methods to recognise wether the mouse position is inside the component according to the conditions set inside of the overridden hitTest()?

Most things are local to the component where it occurs. There are methods to translate a position into the context of another component. E.g. in your mainComponent you might have a function that gets called from a child:
getLocalPoint()

void MainComponent::foo (juce::Component* child, juce::Point<int> pos)
{
    auto localPos = getLocalPoint (child, pos);
}

This will take care of all transfomations that might be applied in any level of the hierarchy.

The juce::MouseEvent has also a convenience function getRelativeTo (Component*):

void MainComponent::calledFromChild (const juce::MouseEvent& event)
{
    auto newEvent = event.getRelativeTo (this);
}

Hope that helps

1 Like

the other way around. hitTest gets called and determines if mouse event methods are going to be a thing. if not the event is passed to the parent component. if the top level component has been reached and no one consumed the event nothing happens

1 Like

You could try mouseMove instead of mouseEnter and mouseExit:

void MyBtn::mouseMove (const juce::MouseEvent& event)
{
	isEntered = event.position.getDistanceFrom (getLocalBounds().getCentre().toFloat()) < 30.0f;
}
1 Like