如何在按钮点击时调用功能?

时间:2017-01-10 06:55:53

标签: java processing

我有一个名为Button的Processing类,它具有以下函数onClick

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

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

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

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

4 个答案:

答案 0 :(得分:3)

使用 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();
    }
}

答案 1 :(得分:1)

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

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.
    }
});


注意:可能Java 8通过lambdas支持回调函数引用。

答案 2 :(得分:0)

查看Processing Button example

它没有封装到一个类中,由你来实现, 但它确实说明了如何使用Processing的内置draw()mousePressed()方法处理事件。

如果有帮助,这是我在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

这是上面Button类的修改版本,它将包含回调方法的类和回调方法的名称作为参数:

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反射和Method类。

答案 3 :(得分:0)

我将假设您使用的是Java 8.如果您不是,那么您应该这样做!由于其对旧版本的主要改进之一就是将函数作为参数进行精确处理。

要传递一个函数对象(即lambda)作为参数,首先需要定义一个功能界面以某种方式&#34; hold&#34;你的功能的实现。功能界面可以是只有一种方法的任何界面,如下所示:

interface MyFunction {
    public void call();
}

即使在Button课程内,也可以在任何地方声明它。只要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类,也不需要覆盖任何内容。 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());

但首先要了解基础知识会更好!