如何在单击按钮时调用函数?

How to call function on button click?

我有一个名为 Button 的 Processing class,它具有以下功能 onClick

class Button() {
    // Extra code
    void onClick() {
        // Run function here
    }
}

应该会在单击按钮时触发函数调用,并且该函数是从参数中获取的,如下所示:

Button test = new Button(..., callFunction())

其中 callFunction() 保证是 void 函数。单击 test 后如何调用函数 callFunction()?我可以检查按钮是否被单击,但我不知道如何将其连接到参数提供的函数调用。

我不确定这是否符合您的目的。但是外部处理程序会很方便。

class Button {
    // Extra code
    private ClickHandler handler;

    //Constructor
    Button(..., ClickHandler handler) {
        this.handler = handler;
    }
    void onClick() {
    // Run function here
        handler.handle();
    }
}

interface ClickHandler {
    void handle();
}

现在您可以像这样创建对象:

Button test = new Button(..., new ClickHandler() {
    public void handle() {
        //do your stuff.
    }
});


注意:大概Java8支持通过lambdas引用回调函数

使用Runnable.

Button test = new Button(..., new Runnable(){

     public void run() {
         // your stuff.
         callFunction();
     }
});

然后:

class Button() {

    private Runnable runnable;

    public Button (... Runnable runnable ){
       this.runnable  = runnable;
    }

    // Extra code
    void onClick() {
        runnable.start();
    }
}

看看Processing Button example

没有封装成一个class,那要看你自己实现了, 但它确实说明了如何使用 Processing 的内置 draw()mousePressed() 方法处理事件。

如果有帮助,这里有一个按钮 class 我在一些 my sketches:

中使用
int numButtons = 3;
Button[] buttons = new Button[numButtons];

void setup(){
  size(180,200);

  int buttonWidth = 150;
  int buttonHeight = 50;
  int buttonSpacing = 15;

  for(int i = 0 ; i < numButtons; i++){
    buttons[i] = new Button("button "+(i+1),buttonSpacing,(buttonHeight+buttonSpacing) * i,buttonWidth,buttonHeight);  
  }
}
void draw(){
  background(255);

  for(int i = 0 ; i < numButtons; i++){
    buttons[i].update(mouseX, mouseY, mousePressed);
    buttons[i].draw();
  }
}
//hacky way callback the main sketch from a button - look into callbacks
void onButtonClicked(Button b){
  println(b.label,"was pressed at",new java.util.Date());
}

class Button{
  float w,h,x,y;//width, height and position
  color bg = color(200);//background colour
  color fg = color(0);//foreground colour
  String label;//button label

  boolean isOver,wasPressed;
  int pw = 10;
  Button(String label,float x,float y,float w,float h){
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    this.label = label;
  }
  //mouseY,mouseY,mouseDown
  void update(int mx,int my,boolean md){
    //it's over if it's within the button's bounding box
    isOver = ((mx >= x && mx <= (x+w))&&(my >= y && my <= (y+h)));
    //if it's over and pressed it's a click
    if(isOver && md){
      //if it wasn't pressed before, trigger click callback
      if(!wasPressed){
        onButtonClicked(this);
        wasPressed = true;
      }
    }else wasPressed = false;
  }

  void draw(){
    pushStyle();
      noStroke();
      fill(isOver ? fg : bg);
      rect(x,y,w,h);
      fill(isOver ? bg : fg);
      text(label,x+pw,y+h*.75);
    popStyle();
  }
}

您可能需要以不同的方式实现它,但希望这会给您一些想法。

更新 如果感觉回调是您追求的主要目标。 如果是这种情况,一种选择是使用 Java Reflection to invoke a Method.

这是上述按钮 class 的修改版本,它采用包含回调方法和回调方法名称的 class 作为参数:

import java.lang.reflect.*;

int numButtons = 3;
Button[] buttons = new Button[numButtons];

void setup(){
  size(180,200);

  int buttonWidth = 150;
  int buttonHeight = 50;
  int buttonSpacing = 15;

  for(int i = 0 ; i < numButtons; i++){
    buttons[i] = new Button(this,"onButton"+(i+1)+"Clicked","button "+(i+1),buttonSpacing,(buttonHeight+buttonSpacing) * i,buttonWidth,buttonHeight);  
  }
}
void draw(){
  background(255);

  for(int i = 0 ; i < numButtons; i++){
    buttons[i].update(mouseX, mouseY, mousePressed);
    buttons[i].draw();
  }
}
public void onButton1Clicked(){
  println("button 1 clicked");
}
public void onButton2Clicked(){
  println("button 2 clicked");
}
public void onButton3Clicked(){
  println("button 3 clicked");
}

class Button{
  float w,h,x,y;//width, height and position
  color bg = color(200);//background colour
  color fg = color(0);//foreground colour
  String label;//button label

  boolean isOver,wasPressed;
  int pw = 10;

  Object parent;
  Method callback;

  Button(Object parent,String callbackName,String label,float x,float y,float w,float h){

    this.parent = parent; 
    try{
      callback = parent.getClass().getMethod(callbackName);
    }catch(Exception e){
      e.printStackTrace();
    }

    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    this.label = label;
  }
  //mouseY,mouseY,mouseDown
  void update(int mx,int my,boolean md){
    //it's over if it's within the button's bounding box
    isOver = ((mx >= x && mx <= (x+w))&&(my >= y && my <= (y+h)));
    //if it's over and pressed it's a click
    if(isOver && md){
      //if it wasn't pressed before, trigger click callback
      if(!wasPressed){
        //onButtonClicked(this);
        if(callback != null){
           try{
            callback.invoke(parent);
          }catch(Exception e){
            e.printStackTrace();
          }
        }
        wasPressed = true;
      }
    }else wasPressed = false;
  }

  void draw(){
    pushStyle();
      noStroke();
      fill(isOver ? fg : bg);
      rect(x,y,w,h);
      fill(isOver ? bg : fg);
      text(label,x+pw,y+h*.75);
    popStyle();
  }
}

这是解决问题的一种方法。如果您需要这些回调的参数,请务必深入研究 java 反射和方法 class。

我假设您正在使用 Java 8。如果您没有,您应该!作为它对旧版本的主要改进之一是精确地将函数作为参数。

要将函数对象(即 lambda)作为参数传递,您首先需要定义一个函数接口以某种方式 "hold" 实现您的函数。函数式接口可以是任何只有一种方法的接口,像这样:

interface MyFunction {
    public void call();
}

在任何你想要的地方声明它,甚至在你的 Button class 中。只要 Button 可以访问就没关系。

然后你只需告诉你的 Button 构造函数最后一个参数是一个函数,将它存储为一个私有字段,然后在单击按钮时调用它:

class Button() {
    MyFunction buttonFunction;
    public Button(..., MyFunction myFunction) {
        // ... other initialization ...
        buttonFunction = myFunction;
    }
    // Extra code
    void onClick() {
        // Run function here
        buttonFunction.call();
    }
}

要将您的函数作为参数传递,请这样做:

Button test = new Button(..., () -> callFunction());

您不需要创建匿名 MyFunction class,也不需要覆盖任何内容。 Java 8 为您解决所有问题。它知道 Button 构造函数需要一个 MyFunction 参数,并且它知道 MyFunction 只有一个方法, call() 没有参数;所以当你提供一个没有参数的函数体时,Java 知道它是 MyFunction#call().

的实现

事实上,您甚至不需要定义接口:您只需将 MyFunction 替换为 Runnable,将 call() 替换为 run(),一切都会按预期工作,因为 Runnable 也是一个功能接口:

class Button() {
    Runnable buttonFunction;
    public Button(..., Runnable myFunction) {
        // ... other initialization ...
        buttonFunction = myFunction;
    }
    // Extra code
    void onClick() {
        // Run function here
        buttonFunction.run();
    }
}

Button test = new Button(..., () -> callFunction());

但最好先了解基础知识!