(又名应付作业第二弹——痛苦计算器)
0.效果图
其实按下去的css调得蛮有动感的hhh
1.界面制作
这次界面写的,梦回小时候在4399上玩装饰大蛋糕。
背景是一个朴实无华的VBox,上面放一个朴实无华的HBox,下面是一个GridPane。具体就不写。
将HBox里东西向右靠齐:
textField.setAlignment(Pos.CENTER_RIGHT);
GridPane的网格顺序是和数组反着来的orz
好接下来美化一下。
试图用FX里自带的函数,然后,
BorderStroke borderStroke = new BorderStroke(Paint.valueOf("#8A2BE2"), BorderStrokeStyle.DASHED, new CornerRadii(0), new BorderWidths(2)); Border border = new Border(borderStroke);
出来的结果-------->
bt.setEffect(new DropShadow());
册那。放弃挣扎,写css吧。
连接Java和css:
Application.setUserAgentStylesheet("CalculatorGUI.css");
这句放在start函数里。
VBox vBox=new VBox(); vBox.getStyleClass().add("vbox"); //CSS部分 .vbox{ -fx-padding: 20 10 10 10; -fx-background-color:#009FCC; }
给它起个名。
.button{ -fx-alignment: center; -fx-background-color: #009FCC; -fx-background-radius: 0; -fx-text-fill: white; -fx-border-width: 0 2 2 0; -fx-border-color: black; -fx-border-style:solid; -fx-pref-height:40; -fx-pref-width:50; }
这是不起名,所有Button都写这样的。
但是JavaFX的CSS和实际的CSS还是有点区别,可以参照官方文档写:点这里
这是中文版的,不是很全,但会讲一下怎么写:戳这里
关于用什么颜色好看:我是色板
CSS动态状态:here
好可以绑定函数了。
3.动态
这次的动态绑定有点烦,毕竟后缀表达式中缀表达式也有那么几十行代码,就当复习数据结构了。
先搞简单的,加入数字。这里偷懒了,每次清空重来一遍。反正我也不输多长的式子,能跑就行()附带的好处就是不用清零键了。
(顺便一提本来想加个清零键点一下就会发出响亮的“归零!”那种,但面板上实在放lan不de下gai了就没弄hhh)
给等于号单独一个函数。为了能让屏幕上多出现一点不同的字符就抛个异常吧。(喂
String[][] a={{"7","8","9","+"}, {"4", "5", "6", "-"}, {"1", "2", "3", "*"}, {"0", ".", "=", "/"}}; for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ Button bt=new Button(a[i][j]); if(!a[i][j].equals("=")){ int x=i,y=j; bt.setOnAction(actionEvent -> addToText(a[x][y])); //注意这里不能直接写i和j,它不接受临时变量。 } else { bt.setOnAction(actionEvent -> { try { cal(); } catch (Exception e) { if(e instanceof MathException) printError(e.toString()); //错误有两种,一是除以0这类数学错误,二是多输了符号啊什么的输入错误。多写了一个异常类区分一下。 else printError("Input Error!"); } }); } gridPane.add(bt,j,i+1); } }
private void cal() throws Exception{ textField.getChildren().clear(); textField.getChildren().add(new Label(calSuff())); pres=""; } private void addToText(String s){ pres+=s; textField.getChildren().clear(); textField.getChildren().add(new Label(pres)); }
两个处理函数。没错字符和文本框那里开了全局变量。说到文本框本来看作业要求,真的弄了个TextField,后来发现这玩意不仅一闪一闪的还没法动态添加。换HBox了,但变量名没改。
**到这里为止这个计算器除了不能算数以外没什么缺点啦**
开始处理String。输进来的是中缀表达式,转成后缀表达式,然后计算。好在这个计算器表面没有括号,可以少写一点。
具体看注释:
private boolean isOperator(String op){ return op.equals("+") || op.equals("-") || op.equals("*") || op.equals("/"); }//判符号 private int priority(String op){ if(op.equals("*") || op.equals("/")){ return 1; }else if(op.equals("+") || op.equals("-")){ return 0; } return -1; }//判优先级 private List<String> Suff(String exp) { Stack<String> opStack = new Stack<>(); List<String> s=new LinkedList<>(); StringBuilder temp = new StringBuilder();//因为可能有小数,所以不能一位一位读。先把两个符号之间的东西存下来,然后统一转Double for(int i=0;i<exp.length();i++){ String item=String.valueOf(exp.charAt(i)); if(isOperator(item)){ if(temp.length()!=0) { s.add(String.valueOf(temp)); temp.delete(0,temp.length());//也可以重新new一个啦,但是效率会差一点 } if(opStack.isEmpty() ||priority(item) > priority(opStack.peek())){ opStack.push(item); }else { while (!opStack.isEmpty()){ if(priority(item) <= priority(opStack.peek())) s.add(opStack.pop()); } opStack.push(item); } } else temp.append(item); } //把剩下的东西都加进来 s.add(String.valueOf(temp)); while(!opStack.empty()){ s.add(opStack.peek()); opStack.pop(); } return s; } private String calSuff() throws Exception{ Stack<Double> stack=new Stack<>(); List<String> ans=Suff(pres); for(String i:ans){ if(i.equals("+")){ Double x=stack.peek();stack.pop(); Double y=stack.peek();stack.pop(); stack.push(x+y); } else if(i.equals("-")){ Double x=stack.peek();stack.pop(); Double y=stack.peek();stack.pop(); stack.push(y-x); } else if(i.equals("*")){ Double x=stack.peek();stack.pop(); Double y=stack.peek();stack.pop(); stack.push(x*y); } else if(i.equals("/")){ Double x=stack.peek();stack.pop(); if(x==0) throw new MathException("Error!The divisor can't be 0!"); Double y=stack.peek();stack.pop(); stack.push(y/x); } else{ double temp=Double.parseDouble(i); stack.push(temp); } } String r=String.format("%.2f",stack.peek()); return r; } private void cal() throws Exception{ textField.getChildren().clear(); textField.getChildren().add(new Label(calSuff())); pres=""; }
到这里好像就写完了?那就这样吧。感谢您的观看(如果真的有人看的话
完整代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import javafx.application.Application; 2 import javafx.geometry.Pos; 3 import javafx.scene.Scene; 4 import javafx.scene.control.Button; 5 import javafx.scene.control.Label; 6 import javafx.scene.layout.*; 7 import javafx.stage.Stage; 8 9 import java.util.LinkedList; 10 import java.util.List; 11 import java.util.Stack; 12 13 class MathException extends Exception{ 14 public MathException(String message){ 15 super(message); 16 } 17 } 18 19 public class CalculatorGUI extends Application { 20 HBox textField; 21 String pres=""; 22 private void printError(String s){ 23 textField.getChildren().add(new Label(s)); 24 pres=""; 25 } 26 private void addToText(String s){ 27 pres+=s; 28 textField.getChildren().clear(); 29 textField.getChildren().add(new Label(pres)); 30 } 31 private boolean isOperator(String op){ 32 return op.equals("+") || op.equals("-") || op.equals("*") || op.equals("/"); 33 } 34 private int priority(String op){ 35 if(op.equals("*") || op.equals("/")){ 36 return 1; 37 }else if(op.equals("+") || op.equals("-")){ 38 return 0; 39 } 40 return -1; 41 } 42 private List<String> Suff(String exp) { 43 Stack<String> opStack = new Stack<>(); 44 List<String> s=new LinkedList<>(); 45 StringBuilder temp = new StringBuilder(); 46 for(int i=0;i<exp.length();i++){ 47 String item=String.valueOf(exp.charAt(i)); 48 if(isOperator(item)){ 49 if(temp.length()!=0) { 50 s.add(String.valueOf(temp)); 51 temp.delete(0,temp.length()); 52 } 53 if(opStack.isEmpty() ||priority(item) > priority(opStack.peek())){ 54 opStack.push(item); 55 }else { 56 while (!opStack.isEmpty()){ 57 if(priority(item) <= priority(opStack.peek())) 58 s.add(opStack.pop()); 59 } 60 opStack.push(item); 61 } 62 } 63 else 64 temp.append(item); 65 } 66 s.add(String.valueOf(temp)); 67 while(!opStack.empty()){ 68 s.add(opStack.peek()); 69 opStack.pop(); 70 } 71 return s; 72 } 73 private String calSuff() throws Exception{ 74 Stack<Double> stack=new Stack<>(); 75 List<String> ans=Suff(pres); 76 for(String i:ans){ 77 if(i.equals("+")){ 78 Double x=stack.peek();stack.pop(); 79 Double y=stack.peek();stack.pop(); 80 stack.push(x+y); 81 } 82 else if(i.equals("-")){ 83 Double x=stack.peek();stack.pop(); 84 Double y=stack.peek();stack.pop(); 85 stack.push(y-x); 86 } 87 else if(i.equals("*")){ 88 Double x=stack.peek();stack.pop(); 89 Double y=stack.peek();stack.pop(); 90 stack.push(x*y); 91 } 92 else if(i.equals("/")){ 93 Double x=stack.peek();stack.pop(); 94 if(x==0) 95 throw new MathException("Error!The divisor can't be 0!"); 96 Double y=stack.peek();stack.pop(); 97 stack.push(y/x); 98 } 99 else{ 100 double temp=Double.parseDouble(i); 101 stack.push(temp); 102 } 103 } 104 String r=String.format("%.2f",stack.peek()); 105 return r; 106 } 107 private void cal() throws Exception{ 108 textField.getChildren().clear(); 109 textField.getChildren().add(new Label(calSuff())); 110 pres=""; 111 } 112 private GridPane getGridPane(){ 113 GridPane gridPane=new GridPane(); 114 gridPane.getStyleClass().add("gridPane"); 115 gridPane.setHgap(10); 116 gridPane.setVgap(10); 117 String[][] a={{"7","8","9","+"}, 118 {"4", "5", "6", "-"}, 119 {"1", "2", "3", "*"}, 120 {"0", ".", "=", "/"}}; 121 for(int i=0;i<4;i++){ 122 for(int j=0;j<4;j++){ 123 Button bt=new Button(a[i][j]); 124 if(!a[i][j].equals("=")){ 125 int x=i,y=j; 126 bt.setOnAction(actionEvent -> addToText(a[x][y])); 127 } 128 else { 129 bt.setOnAction(actionEvent -> { 130 try { 131 cal(); 132 } 133 catch (Exception e) { 134 if(e instanceof MathException) 135 printError(e.toString()); 136 else 137 printError("Input Error!"); 138 } 139 }); 140 } 141 gridPane.add(bt,j,i+1); 142 } 143 } 144 return gridPane; 145 } 146 private VBox getVBox(){ 147 VBox vBox=new VBox(); 148 vBox.getStyleClass().add("vbox"); 149 150 textField=new HBox(); 151 textField.getChildren().add(new Label("0.0")); 152 textField.setAlignment(Pos.CENTER_RIGHT); 153 textField.getStyleClass().add("text"); 154 vBox.getChildren().add(textField); 155 156 GridPane gridPane=getGridPane(); 157 vBox.getChildren().add(gridPane); 158 159 return vBox; 160 } 161 public void start(Stage stage){ 162 Application.setUserAgentStylesheet("CalculatorGUI.css"); 163 VBox vBox=getVBox(); 164 165 Scene scene=new Scene(vBox,300,350); 166 stage.setTitle("CalculatorGUI"); 167 stage.setScene(scene); 168 stage.setMinWidth(300); 169 stage.setMinHeight(330); 170 stage.setHeight(330); 171 stage.show(); 172 } 173 public static void main(String[] args){ 174 Application.launch(args); 175 } 176 }
CSS部分:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 .button{ 2 -fx-alignment: center; 3 -fx-background-color: #009FCC; 4 -fx-background-radius: 0; 5 -fx-text-fill: white; 6 -fx-border-width: 0 2 2 0; 7 -fx-border-color: black; 8 -fx-border-style:solid; 9 -fx-pref-height:40; 10 -fx-pref-width:50; 11 } 12 .button:hover{ 13 -fx-background-color: #77DDFF; 14 } 15 .button:pressed{ 16 -fx-background-color: #77DDFF; 17 -fx-border-color: #CCDDFF; 18 -fx-border-width: 2; 19 } 20 .gridPane{ 21 -fx-background-color: #CCEEFF; 22 -fx-padding:10 0 20 25; 23 } 24 .text{ 25 -fx-background-color: #CCEEFF; 26 -fx-background-radius:5 5 0 0; 27 -fx-pref-height: 50; 28 -fx-border-width: 2 0 0 2; 29 -fx-border-color: black; 30 -fx-border-radius:5 5 0 0; 31 -fx-border-style:solid; 32 -fx-padding:2; 33 } 34 .vbox{ 35 -fx-padding: 20 10 10 10; 36 -fx-background-color:#009FCC; 37 }
--------END--------