JavaFX event.getPickResult()。getIntersectedNode()返回单击按钮的不同结果

时间:2014-08-19 11:30:12

标签: eclipse button javafx mouseclick-event boundary

第一个Java问题(可能是很多!)。我使用Eclipse和e(fx)clispse插件和Scene Builder 2.0学习Java和JavaFX。我在AnchorPane中构建了一个带有几个按钮的小窗口,一个TableView和一个ImageView。到目前为止一切都很好。

如果我只为所有按钮注册了一个方法(在我的情况下都是两个方法!),我原来的问题是如何识别被选中的按钮。我可以看到系统拥有所有信息(通过为event.getSource()和event.PickResult()执行System.out.println)。但是,在发布这个问题之前,我克服了这些问题,但这又带来了一些问题;

1)对于getSource()问题,我想了解按钮源信息,我希望能够在一行中完成。即event.getSource()。[期望Eclipse为我提供在提案列表中由getSource()返回的Type的方法]。但是,在event.getSource()....之后,方法的提议列表是我认为从对象方法继承的方法。我必须做的是将声明分解如下:

EventObject evo = new EventObject(event.getSource());
Object obj = evo.getSource();
Button btnMirror = (Button)obj;
System.out.println("Button id is:" + btnMirror.getId());

为什么在第一个event.getSource()..之后,getSource()不能再作为提案使用?

我的理解中明显存在差距。毕竟,我在System.out。[方法列表]之后获得的方法列表与System.in。[方法列表]不同。有人可以澄清吗?

2)第二个问题是关于getPickResult()。当使用event.getPickResult()。getIntersectedNode()。getId()时,我得到一个null结果?不能正确我认为打印event.getPickResult()显示它具有我需要的所有信息。然后我尝试了event.getPickResult()。getIntersectedNode()。getParent()。getId(),并且工作正常!啊哈,我想,但唉,太早了。我发现的是,我是否得到一个null结果,按钮id或Anchor Pane id(!)取决于我点击按钮的确切位置。按钮文本中间的Bang产生了一个null结果,稍微偏离中心产生按钮id和按钮的外部区域(但鼠标光标仍然完全在按钮内)产生了AnchorPane id。这对我来说使得PickResult非常不可靠。必须有允许这种情况发生的属性。任何人都可以启发我。

还与问题1有关,event.getPickResult()。getandSoOn ....总是在每个句点之后生成一个正确可用方法的列表。由于getPickResult返回PickResult并且以类似的方式,getSource返回一个EventType,因此很困惑为什么会发生这种情况。

感谢所有见解。

附件是Controller的代码。很多System.out可以看看发生了什么。 Main是FX项目的标准生成代码。如果要完全复制窗口布局,还会生成FXML代码。

控制器代码:

package myapplication;

import java.net.URL;
import java.util.EventObject;
import java.util.ResourceBundle;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventType;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.PickResult;
import javafx.scene.layout.AnchorPane;

public class IrfController implements Initializable {

    @FXML private AnchorPane myAnchorPane;
    @FXML private Button btnClickMe;
    @FXML private Button btnAddRow;
    @FXML private TableView<Person> myTV;
    @FXML private TableColumn<Person, String> myCol1;
    @FXML private TableColumn<Person, String> myCol2;

    final ObservableList<Person> data = FXCollections.observableArrayList(
            new Person("John","Smith"),
            new Person("Adam", "West"));

     @FXML protected void btnClick(MouseEvent event) {
/**Get source and get Pick Result both have the info**/      
         System.out.println( "Event GetSource: " + event.getSource());
         System.out.println( "Event PickResult:" + event.getPickResult());   
/** the id's of the button **/       
         System.out.println("Add Row buton id: " +  btnAddRow.getId());
         System.out.println("Click Me button id: " +  btnClickMe.getId());
/**get the Node of the pick result - a direct click returns null **/     
         System.out.println("Pick Result Node id: " + event.getPickResult().getIntersectedNode().getId());

        EventObject evo = new EventObject(event.getSource());
        Object obj = evo.getSource();
        Button btnMirror = (Button)obj;
        System.out.println("Button id is:" + btnMirror.getId());

       System.out.println( "Pick Result: " + event.getPickResult().getIntersectedNode().getParent().getId());
        PickResult pkr = event.getPickResult();
        Node nd = pkr.getIntersectedNode().getParent();
        System.out.println("Parent Node id: " + nd.getId());

        switch (btnMirror.getId()) {
        case "btnClickMe": System.out.println("You selected the Click Me Button"); break;
        case "btnAddRow":  System.out.println("You selected the Add Row Button"); break;
        default: System.out.println("No button registered"); break;
        }

        System.out.println("Event Type: " + event.getEventType().getName());
    }
    @FXML
    public void onActionFired(ActionEvent event){
        System.out.println("In ActionFired - Start");
        System.out.println(event.getClass().toGenericString()); 

        System.out.println(event.toString());
        System.out.println(event.getEventType().toString());
        System.out.println("In ActionFired - End");
    }

    @FXML protected void clickAnchor(MouseEvent event) {
        System.out.println(event.toString());
        System.out.println("Hello Click Anchor!");
        System.out.println(event.getEventType().toString());
    }

和FXML文件:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.effect.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane fx:id="myAnchorPane" onMouseClicked="#clickAnchor" prefHeight="441.0" prefWidth="578.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="myapplication.IrfController">
   <children>
      <Button fx:id="btnClickMe" layoutX="481.0" layoutY="135.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onMouseClicked="#btnClick" prefHeight="50.0" prefWidth="83.0" text="ClickMe" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="135.0">
         <opaqueInsets>
            <Insets />
         </opaqueInsets>
         <effect>
            <Glow />
         </effect></Button>
      <ImageView fitHeight="100.0" fitWidth="143.0" layoutX="35.0" layoutY="22.0" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="344.0" AnchorPane.topAnchor="22.0">
         <image>
            <Image url="@../../../../../Users/Ayesha/Pictures/2014-03-06/IMG_0324.JPG" />
         </image>
      </ImageView>
      <TableView fx:id="myTV" layoutX="35.0" layoutY="135.0" prefHeight="264.0" prefWidth="396.0" AnchorPane.bottomAnchor="42.0" AnchorPane.leftAnchor="35.0" AnchorPane.rightAnchor="147.0" AnchorPane.topAnchor="135.0">
        <columns>
          <TableColumn fx:id="myCol1" prefWidth="75.0" text="First Name" />
          <TableColumn fx:id="myCol2" prefWidth="100.0" text="Last Name" />
            <TableColumn fx:id="myCol3" prefWidth="140.0" text="Something Else" />
        </columns>
      </TableView>
      <Button fx:id="btnAddRow" layoutX="481.0" layoutY="204.0" mnemonicParsing="false" onMouseClicked="#btnClick" prefHeight="50.0" prefWidth="83.0" text="Add Row" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="204.0" />
   </children>
</AnchorPane>

1 个答案:

答案 0 :(得分:0)

我不熟悉JavaFX和所有的东西。但是点击听众的小按钮我可以帮到你。这是一个正常的impl。 eventlisteners的模式和一个通用的解决方案。

首先,根据每种小部件都可以发送相同类型的事件,事件的来源必须是对象。 但这不是问题,您是开发人员,并且您知道哪个侦听器已连接到哪个窗口小部件。如果只有一个侦听器正在侦听一个窗口小部件(例如内联),则可以始终忽略源,因为您知道唯一的一个。 当您重复使用一个侦听器(例如,包含小部件的类)时,您必须检查源以确定谁调用了该事件。

最简单的方法是

widgetObject == event.getSource()

所以第一个意图是,将对象与“==”进行比较。但在这种情况下这不是问题,因为event.getSource()与发送事件的widgetObject是同一个实例。因此可以对对象进行比较。

另一方面,如果您的侦听器更复杂或者动画小部件实例是动态的,您可以通过“instanceof”检查对象的类型,然后转换为所需的实现。 在GUI框架中,Normaly任何小部件都有一个setData / getData实现,您可以在其中放置任何您想要的内容。所以线索是:

if (event.getSource() instanceof Button) {
  Button eventBtn = (Button) event.getSource();

  Enum kindOfButton = (Enum) eventBtn.getData();

  switch (kindOfButton) {
   case SAVE:
     doSave();
   break;

   ...

  }
}

通过组合“instanceof”和小部件中的数据poket,您可以根据需要实现复杂的侦听器。动态生成小部件也不是问题,界面保持干净。

注意:上面的代码是伪代码然后是真实代码。例如,枚举应该是Enum impl。你提供;)

希望有所帮助。