<head><!-- BaNnErBlUrFlE-HeAdEr-start -->
<style>
  #pfptBanneraflyiyx { all: revert !important; display: block !important;
    visibility: visible !important; opacity: 1 !important;
    background-color: #60beeb !important;
    max-width: none !important; max-height: none !important }
  .pfptPrimaryButtonaflyiyx:hover, .pfptPrimaryButtonaflyiyx:focus {
    background-color: #77a8c4 !important; }
  .pfptPrimaryButtonaflyiyx:active {
    background-color: #8193a0 !important; }
  html:root, html:root>body { all: revert !important; display: block !important;
    visibility: visible !important; opacity: 1 !important; }
</style>

<!-- BaNnErBlUrFlE-HeAdEr-end -->
</head><!-- BaNnErBlUrFlE-BoDy-start -->
<!-- Preheader Text : BEGIN -->
<div style="display:none !important;display:none;visibility:hidden;mso-hide:all;font-size:1px;color:#ffffff;line-height:1px;max-height:0px;opacity:0;overflow:hidden;">
Hi, I created a PR to optimize the memory footprint of event handler properties and simplify the code:  https: //github. com/openjdk/jfx/pull/2088 I'd like to hear everyone's opinions. ## Summary This PR moves the event handler properties</div>
<!-- Preheader Text : END -->

<!-- Email Banner : BEGIN -->
<div style="display:none !important;display:none;visibility:hidden;mso-hide:all;font-size:1px;color:#ffffff;line-height:1px;max-height:0px;opacity:0;overflow:hidden;">ZjQcmQRYFpfptBannerStart</div>

<!--[if ((ie)|(mso))]>
  <table border="0" cellspacing="0" cellpadding="0" width="100%" style="padding: 0px 0px 10px 0px; direction: ltr" lang="en"><tr><td>
    <table border="0" cellspacing="0" cellpadding="0" style="padding: 0px 8px 6px 8px; width: 100%; border-radius:4px; border-top:4px solid #8193a0;background-color:#60beeb;"><tr><td valign="top">
      <table align="left" border="0" cellspacing="0" cellpadding="0" style="padding: 0px 8px 4px 8px; font-size: 12px; line-height: 16px">
        <tr><td style="color:#000000; font-family: 'Arial', sans-serif; font-weight:bold; font-size:14px; line-height: 20px; direction: ltr">
          This Message Is From an External Sender
        </td></tr>
        <tr><td style="color:#000000; font-weight:normal; font-family: 'Arial', sans-serif; font-size:12px; direction: ltr">
          This message came from outside your organization.
        </td></tr>

      </table>
      <![if ie]><br clear="all"><![endif]>
      <table align="right" border="0" cellspacing="0" cellpadding="0" style="padding: 0px 0px 4px 0px; font-size: 14px; line-height: 36px"><tr>
        <td style="direction: ltr">  <a target="_blank" href="https://us-phishalarm-ewt.proofpoint.com/EWT/v1/ACWV5N9M2RV99hQ!Op20OCZBWsZudD6juBifEMYdQYaA5T_UJXsSRghjY9QvjIfS1_ZhQkRLF7WKYe-LlV87D4jp29oPxZli1K4Zp-BtjKqmUp_P-MBS80ekOBCeL_APPw2BWGXCCgvs6Bcu9g$" style="mso-padding-alt: 7px; padding: 7px; border-radius: 2px; border: 1px solid #666666; "><strong style="font-weight: normal; color: #000000; text-decoration: none; font-family: 'Arial', sans-serif; font-size: 14px;">  Report Suspicious  </strong></a>  ‌ </td>
      </tr></table>
    </td></tr></table>
  </td></tr></table>
<![endif]-->

<![if !((ie)|(mso))]>
  <div dir="ltr" lang="en" id="pfptBanneraflyiyx" style="all: revert !important; display:block !important; text-align: left !important; margin: 0 0 10px 0 !important; padding:7px 16px 8px 16px !important; border-radius: 4px !important; min-width: 200px !important; background-color: #60beeb !important; background-color: #60beeb; border-top: 4px solid #8193a0 !important; border-top: 4px solid #8193a0;">
    <div id="pfptBanneraflyiyx" style="all: unset !important; float:left !important; display:block !important; margin: 1px 0 1px 0 !important; max-width: 600px !important;">
      <div id="pfptBanneraflyiyx" style="all: unset !important; display:block !important; visibility: visible !important; background-color: #60beeb !important; color:#000000 !important; color:#000000; font-family: 'Arial', sans-serif !important; font-family: 'Arial', sans-serif; font-weight:bold !important; font-weight:bold; font-size:14px !important; line-height:1.29 !important; line-height:1.29">
        This Message Is From an External Sender
      </div>
      <div id="pfptBanneraflyiyx" style="all: unset !important; display:block !important; visibility: visible !important; background-color: #60beeb !important; color:#000000 !important; color:#000000; font-weight:normal; font-family: 'Arial', sans-serif !important; font-family: 'Arial', sans-serif; font-size:12px !important; line-height:1.5 !important; line-height:1.5; margin-top:2px !important;">
This message came from outside your organization.
      </div>

    </div>
    <div id="pfptBanneraflyiyx" style="all: unset !important; float: right !important; display: block !important; display: block; margin-left: 16px !important; margin-top: 1px !important; text-align: right !important; width: fit-content !important; font-size: 12px !important">
<a id="pfptBanneraflyiyx" href="https://us-phishalarm-ewt.proofpoint.com/EWT/v1/ACWV5N9M2RV99hQ!Op20OCZBWsZudD6juBifEMYdQYaA5T_UJXsSRghjY9QvjIfS1_ZhQkRLF7WKYe-LlV87D4jp29oPxZli1K4Zp-BtjKqmUp_P-MBS80ekOBCeL_APPw2BWGXCCgvs6Bcu9g$"
    style="all: unset !important; display: inline-block !important; text-decoration: none">
    <div class="pfptPrimaryButtonaflyiyx" style="display: inline-block !important; display: inline-block; visibility: visible !important; opacity: 1 !important; color: #000000 !important; color: #000000; font-family: 'Arial', sans-serif !important; font-family: 'Arial', sans-serif; font-size: 14px !important;  font-weight: normal !important; text-decoration: none !important; border-radius: 2px !important; margin-top: 3px !important; margin-bottom: 3px !important; margin-left: 16px !important; padding: 7.5px 16px !important; white-space: nowrap !important; width: fit-content !important;
        border: 1px solid #666666">
        Report Suspicious
    </div>
</a>
    </div>
    <div style="clear: both !important; display: block !important; visibility: hidden !important; line-height: 0 !important; font-size: 0.01px !important; height: 0px"> </div>
  </div>
<![endif]>

<div style="display:none !important;display:none;visibility:hidden;mso-hide:all;font-size:1px;color:#ffffff;line-height:1px;max-height:0px;opacity:0;overflow:hidden;">ZjQcmQRYFpfptBannerEnd</div>
<!-- Email Banner : END -->

<!-- BaNnErBlUrFlE-BoDy-end -->
<div dir="ltr"><div dir="ltr">Hi,<br><div><br></div><div>I created a PR to optimize the memory footprint of event handler properties and simplify the code: <a href="https://github.com/openjdk/jfx/pull/2088">https://github.com/openjdk/jfx/pull/2088</a></div><div>I'd like to hear everyone's opinions.</div><div><br></div><div>## Summary<br><br>This PR moves the event handler properties of `Node` and its subclasses to `EventHandlerManager` for storage.<br><br>## Goals<br><br>- More lazy allocation of property objects.<br>- Simplify the way to define event handler properties.<br>- Maintain consistency between the actual event handler value and the property value.<br><br>## Motivation<br><br>In JavaFX, many controls define event handler properties.<br><br>For example, `ButtonBase` defines an `onAction` property:<br><br>```java<br>public final ObjectProperty<EventHandler<ActionEvent>> onActionProperty() { return onAction; }<br><br>public final void setOnAction(EventHandler<ActionEvent> value) { onActionProperty().set(value); }<br><br>public final EventHandler<ActionEvent> getOnAction() { return onActionProperty().get(); }<br><br>private ObjectProperty<EventHandler<ActionEvent>> onAction = new ObjectPropertyBase<>() {<br>    @Override protected void invalidated() {<br>        setEventHandler(ActionEvent.ACTION, get());<br>    }<br><br>    @Override<br>    public Object getBean() {<br>        return ButtonBase.this;<br>    }<br><br>    @Override<br>    public String getName() {<br>        return "onAction";<br>    }<br>};<br>```<br><br>However, there are several issues with defining properties in this way.<br><br>### Unnecessary allocation of `ObjectProperty` objects<br><br>Users often call the `setOnAction` method to set the event handler, but rarely call `onActionProperty()` to add listeners or bind it to other values.<br><br>The actual effect of `setOnAction` is to call `EventHandlerManager#setEventHandler(...)` to install the event handler in the `EventHandlerManager`, and the installed event handler can also be retrieved by calling `EventHandlerManager#getEventHandler(...)`.<br><br>Therefore, allocating the `ObjectProperty` object before the user explicitly calls `onActionProperty()` wastes memory and serves no real purpose. Most of these objects can be optimized away.<br><br>### The property value and EventHandlerManager may be out of sync<br><br>Consider the following code:<br><br>```java<br>EventHandler<ActionEvent> handler = event -> IO.println("On Action");<br><br>var button = new Button() {<br>    {<br>        setOnAction(handler);<br>        setEventHandler(ActionEvent.ACTION, null);<br>    }<br>};<br><br>assert button.getOnAction() == handler;<br><br>button.fire(); // Nothing happened<br>```<br><br>As you can see, the handler obtained by `getOnAction()` may not be triggered, <br>because the value of the `onActionProperty()` property is actually not associated with the handler stored in the `EventHandlerManager`.  <br>Users can override the value of `onActionProperty()` by calling `setEventHandler(...)`, which may lead to unexpected behavior.<br><br>### Defining event handler properties is verbose and cumbersome<br><br>Each time a user defines an event handler property, they need to declare a subclass of `ObjectPropertyBase` and repeat some boilerplate code.<br>This is cumbersome to write and prone to errors.<br><br>## Description<br><br>This PR adds the following APIs to the `Node` class:<br><br>```java<br>protected final <T extends Event> EventHandler<? super T> getEventHandler(<br>        final EventType<T> eventType) {<br>    return getInternalEventDispatcher().getEventHandlerManager().getEventHandler(eventType);<br>}<br>    <br>protected final <T extends Event> ObjectProperty<EventHandler<? super T>> eventHandlerProperty(<br>        final EventType<T> eventType,<br>        final String name) {<br>    return getInternalEventDispatcher().getEventHandlerManager()<br>                                       .eventHandlerProperty(eventType, name);<br>}<br>```<br><br>After this, defining event handler properties in the `Node` class and its subclasses only requires the following:<br><br>```java<br>public final void setOnMouseClicked(EventHandler<? super MouseEvent> value) {<br>    setEventHandler(MouseEvent.MOUSE_CLICKED, value);<br>}<br><br>public final EventHandler<? super MouseEvent> getOnMouseClicked() {<br>    return getEventHandler(MouseEvent.MOUSE_CLICKED);<br>}<br><br>public final ObjectProperty<EventHandler<? super MouseEvent>> onMouseClickedProperty() {<br>    return eventHandlerProperty(MouseEvent.MOUSE_CLICKED, "onMouseClicked");<br>}<br>```<br><br>In this way, calling `setOnMouseClicked(...)` will not invoke `onMouseClickedProperty()`, and the corresponding `ObjectProperty` will not be allocated.<br>The `ObjectProperty` will only be allocated and stored inside the `EventHandlerManager` when the user explicitly calls `onMouseClickedProperty()`.<br><br>The three methods `eventHandlerProperty(...)`, `getEventHandler(...)`, and `setEventHandler(...)` follow the JavaFX property conventions.<br>Calling `setEventHandler(...)` will also trigger listeners added to `eventHandlerProperty(...)`.<br><br>## Risks and Assumptions<br><br>This PR adds `getEventHandler(...)` and `eventHandlerProperty(...)` methods to the `Node` class. <br>If a user defines methods with the same signatures in a subclass of `Node`,<br>the subclass will fail JVM verification.<br><br>This PR changes the behavior of the `Node#setEventHandler(...)` method.<br>Now it's behavior is equivalent to `node.eventHandlerProperty(...).set(...)`. <br>Calling it will affect the corresponding property value, trigger listeners added to the property, and throw an exception if the property is bound.<br><br></div></div>
</div>