如何在Processing中允许可编程键输入?

时间:2017-10-19 15:45:26

标签: java arrays if-statement switch-statement processing

我正在编写一个Processing脚本,想要检测一个密钥(使用key变量)是否是用户提前选择的一组密钥之一(例如,在设置JSON文件中或某些其他方法)。我使用switch / case语句进行设置,但事实证明我不能将变量用作case表达式。

我使用final关键字将它们标记为常量,这适用于定义为直接变量的那些,但不适用于存储在数组中的那些。

有没有办法避免使用长if / elseif语句或将数组拆分为多个变量?

如果不清楚(双关语),这是我目前的代码:

// constants
final char[] teamHotkeys  = {'b', 'y', 'p', 'o', 'r'};

final char animationHotkey = ' ';
final char doAllHotkey = 'a';

...

// keyPressed handler
void keyPressed(){
 float[] chartArea = {gridSizeHeight * 2, gridSizeHeight * 22, gridSizeWidth * 1, gridSizeWidth * 23};
 // check which key has been pressed
 switch (key){
   case teamHotkeys[0]:
     drawBar(0, chartArea);
     break;
   case teamHotkeys[1]:
     drawBar(1, chartArea);
     break;
   case teamHotkeys[2]:
     drawBar(2, chartArea);
     break;
   case teamHotkeys[3]:
     drawBar(3, chartArea);
     break;
   case teamHotkeys[4]:
     drawBar(4, chartArea);
     break;
   case animationHotkey:
     runAnimation();
     break;
   case doAllHotkey:
     showFinalScores();
     break;
 }
}

编译器可以正常访问animationHotkeydoAllHotkey,现在它们是常量,但它不能访问teamHotkeys[]的索引,因为只有数组是常量,但是它的成员在技术上可能已经改变了,但是编译器并没有改变。知道他们永远不会改变。

2 个答案:

答案 0 :(得分:1)

我只会使用if语句。有时最愚蠢的代码是最好的。这是最容易理解的,一旦编写完成,你就可以把它放在某个地方的功能中,而不是真的很好看。

但是如果你真的想避免if语句,你可能采取的一种方法是创建一个HashMap,将字符键映射到可运行的动作。这是一个非常基本的例子:

HashMap<Character, Runnable> keyRunnableMap = new HashMap<Character, Runnable>();

void setup() {
  Runnable aRunnable = new Runnable() {
    public void run() {
      println("A pressed.");
    }
  };

  Runnable bRunnable = new Runnable() {
    public void run() {
      println("B pressed.");
    }
  };

  keyRunnableMap.put('a', aRunnable);
  keyRunnableMap.put('b', bRunnable);
}

void draw() {
}

void keyPressed() {
  if (keyRunnableMap.containsKey(key)) {
    keyRunnableMap.get(key).run();
  }
}

这使您可以将keyPressed()逻辑设置得非常短,但需要设置更多代码。您可以使用Java 8 lambdas稍微缩短一点,但如果您使用当前版本的Processing编辑器,则无法工作。我实际上并没有推荐这种方法。坚持使用if语句。

编辑:您还可以依赖幕后的事实,key变量是char类型,实际上是一个数字。小写'a'是数字97。更多信息here。这是一个例子:

Runnable[] runnableArray = new Runnable[2];

void setup() {
  Runnable aRunnable = new Runnable() {
    public void run() {
      println("A pressed.");
    }
  };

  Runnable bRunnable = new Runnable() {
    public void run() {
      println("B pressed.");
    }
  };

  runnableArray[0] = aRunnable;
  runnableArray[1] = bRunnable;
}

void draw() {
}

void keyPressed() {

  // a = 97, b = 98
  if(key >= 'a' && key <= 'b'){
    int index = key - 97;
    runnableArray[index].run();
  }
}

同样,我并没有真正推荐这种方法,因为它不比if语句更具可读性。

答案 1 :(得分:0)

好吧,在C#中,一个long开关基本上是一个HashMap,但是在Java中它只是......很多if / else&#39; s,所以当我可以使用时,我通常更喜欢HashMap。

如果您只想知道您的密钥是否属于某个群组(让我们说,&#34; teamHotkeys&#34;)您可以使用HashMap<Character, String>HashMap<Character, KeyType>(与KeyType作为枚举),用于将多个键映射到同一个动作。在最坏的情况下,它仍然是O(n),但由于密钥是分组的,因此它应该比许多if / else&#39更好。

HashMap<Character, KeyType> keyTypePairs = new HashMap<Character, KeyType>();
switch(keyTypePairs.get(key)) {
    case teamHotkeys:
        // ...
        break;
}

enum KeyType { teamHotkeys, otherType1, otherType2 }

这就是全部,如果我理解了这个问题,它应该有用。

编辑:通过快速测试,我可以说在最坏的情况下,HashMap占用的空间介于2.3到3.5千字节之间。大约300个条目= null保留空间,120(int)键和KeyType(每个枚举使用4或8字节地址,具体取决于CPU)。不是那么多,但如果我是你,我会接受它。另外,我说300作为近似;我没有120个钥匙,所以可能会少得多或多得多。