赞
踩
本文我们利用JFrame容器实现简单计算器功能。
其实如果有java的一些基础是可以直接跳到完整代码那一部分去看的。我的注释基本算是全面的。
有些部分没有注释到的我也会在本文章中为你一一道来。
讲代码之前还是先看看效果吧!
首先要实现这个页面很简单 我们可以利用JFrame的网格布局方式然后逐步添加按钮标签等元素就行了,当然过程中肯定要添加事件喽。
或者我们可以利用swt插件直接利用鼠标拖动来进行排版。
但是我认为前者将控制权交个了电脑,后者充满了随意性都不是很好。所以我没有给布局,直接设置的null,这样就可以手动设置其大小和位置了。
我将函数主体删掉,这样你们很容易看清这个代码的结构。
如上图大家可以看到
核心方法
,功能就是给init中初始化出来的窗口中添加按钮标签和相关事件的。private void init() {
setBounds(300, 300, 500, 700);
getContentPane().setLayout(null);
setTitle("P&p calculator v5.0");
}
这里就三行代码。
第一行是设置第一次显示的时候,窗体的位置和大小。官方API是这样写的。
public void setBounds(int x , int y , int width , int height)。其中x y 是以屏幕左上角为原点建立坐标系,向右为x正方向,向下为y正方向。如下图为上面的参数的示意图。(尺寸不一定成比例)
第二行中getContentPane().setLayout(null);得到正在操作的窗体的contentPane 对象(类似于句柄)并将其布局方式设置为null。你可以理解为将所有元素都设置为相对于窗体的绝对位置,如果你设置一个布局方式之后,后续就不能通过上面的setBounds方法设置其位置了。
上面讲原理的时候已经讲过了,这样将布局方式设置为null之后你就可以用setBounds随心所欲的设置元素的大小和位置了。
这里要注意:如果是窗体,那么相对位置的原点是屏幕的左上角,而如果是窗体中的元素,那么相对的原点就是窗体的左上角(如果有标题栏那么就是相对于标题栏的左下角,正文的左上角,如下图)
这里还要注意的一点是:从上面可以看出,原点在窗口的左上角偏下的位置,我们这边设置的高为700,但是实际绘图区域的高可能只有650左右(减去了标题栏的高),这一点需要注意,(如下图)。还有一个宽也存在同样的问题,实际绘图区域比给的少,这个情况我目前还不知道是什么原因,估计最可能是我电脑屏幕小了分辨率高了,我就将缩放与布局设置成了125%,这样就导致了宽度与设置的大小不符合吧。
第三行不必多说,见名之意,就是设置标题,一般是软件名字及版本号,我把自己的别名也加上了。
因为中间的方法是核心方法,且比较多,我们放到最后讲,
我们先说收尾方法。就二行比较简单。
private void display() {
setVisible(1 < 2);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
第一行的方法为继承自java.awt.Window 的方法。
官方API是这样提供的
public void setVisible(boolean b)。
见名之意,设置此窗体对象的可见性 这里我用了一个表达式 (我是能偷懒绝对会偷懒的,少一个字符(1<2三个字符 true四个字符,以前设计excel公式时候养成的习惯))
第二行的方法官方API解释如下
public void setDefaultCloseOperation(int operation)
就是用户关闭窗体时候默认执行的操作。
本代码中执行的是用户关闭窗体后关闭程序,如果不设置,则会出现有趣的效果,各位可以试试。
如上图先添加的当然是”显示屏幕”。
这两组(四种元素)的添加基本一致,就是位置不一样,我们拿一组出来说即可。
// 计算式标签
JLabel jisuan = new JLabel("计算式");
jisuan.setFont(new Font("华文楷体", Font.CENTER_BASELINE, 25));
jisuan.setBounds(0, 0, 100, 80);
getContentPane().add(jisuan);
// 计算式显示框
JTextField jisuan_text = new JTextField();
jisuan_text.setBounds(100, 15, 360, 50);
jisuan_text.setHorizontalAlignment(JTextField.LEFT);
jisuan_text.setFont(new Font("华文楷体", Font.PLAIN, 20));
getContentPane().add(jisuan_text);
首先是是计算式这三个字、
因为不需要改变,也不用添加任何事件,我们就用JLabel。
然后是计算式右边的计算式显示框
退格按钮
// 退格按钮
final JButton celan = new JButton();
celan.addActionListener(e -> jisuan_text.setText(jisuan_text.getText().length() != 0
? jisuan_text.getText().substring(0, jisuan_text.getText().length() - 1) : ""));
celan.setFont(new Font("华文楷体", Font.PLAIN, 42));
celan.setText("退 格");
celan.setBounds(50, 150, 180, 80);
getContentPane().add(celan);
这里就是普通的添加按钮操作然后设置字体、设置按钮文字、大小位置等最后添加到当前窗体。
唯独需要注意的是事件,也就是第二行,这里面我加了个点击事件,并利用Lambda表达式实现效果,如果不懂的请自行学习。这里我讲下Lambda表达式内部代码,这个就是一个三目表达式加上几个函数的嵌套。
首先,我们通过上面定义的计算式显示框的对象得到计算式的文本,然后判断其长度是否为0,也就说其是否为空。
是的话就直接返回空文本,然后结合外面的setText将计算式的值设置为空。
否的话就通过getText得到文本然后利用substring截取去掉最后一个字符,并将新字符串传递给setText参数进而实现退格效果。
清除按钮
// 清除按钮
final JButton celan_all = new JButton();
celan_all.addActionListener(e -> jisuan_text.setText(""));
celan_all.setFont(new Font("华文楷体", Font.PLAIN, 42));
celan_all.setText("清 除");
celan_all.setBounds(250, 150, 180, 80);
getContentPane().add(celan_all);
和退格如出一辙,就是最后的lambda表达式有所区别,这里直接设置为空值,不用那么多判断。
这一组数字的按钮的添加最简单,不需要那么多判断,就是利用getText得到目前的字符串,然后追加一个上对应的数字,组成的新字符串作为setText的参数即可。比如数字1的代码如下。
// 数字1按钮
final JButton num_1 = new JButton();
num_1.addActionListener(e -> jisuan_text.setText(jisuan_text.getText() + 1));
num_1.setFont(new Font("华文楷体", Font.PLAIN, 42));
num_1.setText("1");
num_1.setBounds(50, 250, 80, 80);
getContentPane().add(num_1);
因为加减乘除事件的添加中要用到这个方法,所以我就先讲这个
/**
* 当按下运算符相关按钮时候 <br>
* 检测计算式是否以运算符等相关文本结尾 <br>
* 是则返回空值 否则返回对应运算符的文本
* @param jisuan_text 显示计算式的文本框对象
* @param string 要追加的运算符 (/*-+.)
* @return 返回要追加的字符串 等待调用相关函数追加到计算式的末尾
*/
private String m1(JTextField jisuan_text, String string) {
String Str = jisuan_text.getText() + ((jisuan_text.getText().endsWith("+")
|| (jisuan_text.getText().endsWith("-")) || (jisuan_text.getText().endsWith("*"))
|| (jisuan_text.getText().endsWith("/")) || (jisuan_text.getText().endsWith("."))) ? "" : string);
return Str;
}
这个方法应该很好懂,就是参数中传入计算式的对象,然后通过getText方法得到其文本,然后判断他是不是以加减乘除点任意一个符号结尾的,如果是,则返回空否则返回你要添加的符号(加减乘除点按钮点哪个加哪个)将这个作为一个字符创追加到getText的后面,然后将这个新字符串返回出去。
我们以加号为例作以说明吧。
// 加号按钮
final JButton clc_add = new JButton();
clc_add.addActionListener(e -> jisuan_text.setText(m1(jisuan_text, "+")));
clc_add.setFont(new Font("华文楷体", Font.PLAIN, 42));
clc_add.setText("+");
clc_add.setBounds(350, 250, 80, 80);
getContentPane().add(clc_add);
其中大部分和前面类似的代码,就是事件稍有不同,我们这里加以说明。
就是调用m1()方法,判断他是不是不是以数字结尾的,如果是则返回当前计算式加上加号组成一个新字符串,并以其为参数调用setText将其设置为新计算式即可。其他的符号的事件的添加就是一个字符串之差而已,这里就不用重复说了。
/** * 获取字符串计算式转化为结果 * * @param se2 * ScriptEngine 对象 * @param text * 要转化的字符串 * @return 返回转化后的结果 * @see https://blog.csdn.net/m0_38000828/article/details/80975530 具体请参看这篇文章 */ private String clc(ScriptEngine se2, String text) { Object obj = null; try { obj = se.eval(text); } catch (ScriptException e) { e.printStackTrace(); } return obj.toString(); }
以上方法实际上是参考如下博文,感谢(憨笑)。
具体作用就是将由纯计算式组成的字符串转化成计算结果。
这里的两个参数第一个貌似是具体的引擎对象,就是我们类的唯一一个成员变量。第二个参数就是待计算的文本。由于文本可能是逻辑不正确的计算式(比如1+++2,这个明显不正确。)所以需要捕捉异常,这里使用的是try catch代码块。
try catch中我们调用eval方法得到一个对象,return的时候 ,我们调用其tostring方法获得文本并将其返回即可。
// 等于按钮
final JButton num_equ = new JButton();
num_equ.addActionListener(e -> answer_text.setText(clc(this.se, jisuan_text.getText())));
num_equ.setFont(new Font("华文楷体", Font.PLAIN, 42));
num_equ.setText("=");
num_equ.setBounds(250, 550, 80, 80);
getContentPane().add(num_equ);
同样的,这里其他部分不用多说,就是把添加事件部分拎出来说下。
answer_text.setText(clc(this.se, jisuan_text.getText()))
就是将计算式文本取出来和当前对象的唯一成员变量se对象一起传入clc。这样就得到当前计算式的结果,然后调用结果显示框的setText方法将其设置为结果即可。
//我的包名 原本准备去除的 后来想了还是留着吧 //各位如果想直接用本代码 最好把这个删除了 package com.company.windows; //这三个是实现文本型计算式到计算结果的三个包的导入 import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import java.awt.Font; //按钮 import javax.swing.JButton; //顶层容器 import javax.swing.JFrame; //标签 单纯的文本显示用 import javax.swing.JLabel; //输入框 用以显示计算式和结果 import javax.swing.JTextField; /** * @author P&p * @category 计算器 可实现基本计算功能 * @version 5.0 * @date 2020年9月6日 */ // 新建类继承自JFrame类 public class Calculator4 extends JFrame { // 创建一个 ScriptEngine对象 用于将字符串计算式转化为结果 ScriptEngine se = new ScriptEngineManager().getEngineByName("JavaScript"); /** * 函数的主入口 */ public static void main(String[] args) { new Calculator4(); } /** * 构造函数 用三个过度函数<br> * 进行初始化,元素添加及最终的显示界面和收尾 */ public Calculator4() { // 初始化相关操作,创建窗口,设置背景颜色标题等 init(); // 添加按钮和标签 button_add(); // 界面的显示及收尾工作 display(); } private void init() { setBounds(300, 300, 500, 700); getContentPane().setLayout(null); setTitle("P&p calculator v5.0"); } private void button_add() { // 计算式标签 JLabel jisuan = new JLabel("计算式"); jisuan.setFont(new Font("华文楷体", Font.CENTER_BASELINE, 25)); jisuan.setBounds(0, 0, 100, 80); getContentPane().add(jisuan); // 计算式显示框 JTextField jisuan_text = new JTextField(); jisuan_text.setBounds(100, 15, 360, 50); jisuan_text.setHorizontalAlignment(JTextField.LEFT); jisuan_text.setFont(new Font("华文楷体", Font.PLAIN, 20)); getContentPane().add(jisuan_text); // 结果标签 JLabel answer = new JLabel("结 果"); answer.setFont(new Font("华文楷体", Font.CENTER_BASELINE, 25)); answer.setBounds(0, 55, 100, 80); getContentPane().add(answer); // 结果显示框 JTextField answer_text = new JTextField(); answer_text.setBounds(100, 70, 360, 50); answer_text.setHorizontalAlignment(JTextField.LEFT); answer_text.setFont(new Font("华文楷体", Font.PLAIN, 20)); getContentPane().add(answer_text); // 退格按钮 final JButton celan = new JButton(); celan.addActionListener(e -> jisuan_text.setText(jisuan_text.getText().length() != 0 ? jisuan_text.getText().substring(0, jisuan_text.getText().length() - 1) : "")); celan.setFont(new Font("华文楷体", Font.PLAIN, 42)); celan.setText("退 格"); celan.setBounds(50, 150, 180, 80); getContentPane().add(celan); // 清除按钮 final JButton celan_all = new JButton(); celan_all.addActionListener(e -> jisuan_text.setText("")); celan_all.setFont(new Font("华文楷体", Font.PLAIN, 42)); celan_all.setText("清 除"); celan_all.setBounds(250, 150, 180, 80); getContentPane().add(celan_all); // 数字1按钮 final JButton num_1 = new JButton(); num_1.addActionListener(e -> jisuan_text.setText(jisuan_text.getText() + 1)); num_1.setFont(new Font("华文楷体", Font.PLAIN, 42)); num_1.setText("1"); num_1.setBounds(50, 250, 80, 80); getContentPane().add(num_1); // 数字2按钮 final JButton num_2 = new JButton(); num_2.addActionListener(e -> jisuan_text.setText(jisuan_text.getText() + 2)); num_2.setFont(new Font("华文楷体", Font.PLAIN, 42)); num_2.setText("2"); num_2.setBounds(150, 250, 80, 80); getContentPane().add(num_2); // 数字3按钮 final JButton num_3 = new JButton(); num_3.addActionListener(e -> jisuan_text.setText(jisuan_text.getText() + 3)); num_3.setFont(new Font("华文楷体", Font.PLAIN, 42)); num_3.setText("3"); num_3.setBounds(250, 250, 80, 80); getContentPane().add(num_3); // 加号按钮 final JButton clc_add = new JButton(); clc_add.addActionListener(e -> jisuan_text.setText(m1(jisuan_text, "+"))); clc_add.setFont(new Font("华文楷体", Font.PLAIN, 42)); clc_add.setText("+"); clc_add.setBounds(350, 250, 80, 80); getContentPane().add(clc_add); // 数字4按钮 final JButton num_4 = new JButton(); num_4.addActionListener(e -> jisuan_text.setText(jisuan_text.getText() + 4)); num_4.setFont(new Font("华文楷体", Font.PLAIN, 42)); num_4.setText("4"); num_4.setBounds(50, 350, 80, 80); getContentPane().add(num_4); // 数字5按钮 final JButton num_5 = new JButton(); num_5.addActionListener(e -> jisuan_text.setText(jisuan_text.getText() + 5)); num_5.setFont(new Font("华文楷体", Font.PLAIN, 42)); num_5.setText("5"); num_5.setBounds(150, 350, 80, 80); getContentPane().add(num_5); // 数字6按钮 final JButton num_6 = new JButton(); num_6.addActionListener(e -> jisuan_text.setText(jisuan_text.getText() + 6)); num_6.setFont(new Font("华文楷体", Font.PLAIN, 42)); num_6.setText("6"); num_6.setBounds(250, 350, 80, 80); getContentPane().add(num_6); // 减号按钮 final JButton clc_sub = new JButton(); clc_sub.addActionListener(e -> jisuan_text.setText(m1(jisuan_text, "-"))); clc_sub.setFont(new Font("华文楷体", Font.PLAIN, 42)); clc_sub.setText("-"); clc_sub.setBounds(350, 350, 80, 80); getContentPane().add(clc_sub); // 数字7按钮 final JButton num_7 = new JButton(); num_7.addActionListener(e -> jisuan_text.setText(jisuan_text.getText() + 7)); num_7.setFont(new Font("华文楷体", Font.PLAIN, 42)); num_7.setText("7"); num_7.setBounds(50, 450, 80, 80); getContentPane().add(num_7); // 数字8按钮 final JButton num_8 = new JButton(); num_8.addActionListener(e -> jisuan_text.setText(jisuan_text.getText() + 8)); num_8.setFont(new Font("华文楷体", Font.PLAIN, 42)); num_8.setText("8"); num_8.setBounds(150, 450, 80, 80); getContentPane().add(num_8); // 数字9按钮 final JButton num_9 = new JButton(); num_9.addActionListener(e -> jisuan_text.setText(jisuan_text.getText() + 9)); num_9.setFont(new Font("华文楷体", Font.PLAIN, 42)); num_9.setText("9"); num_9.setBounds(250, 450, 80, 80); getContentPane().add(num_9); // 乘号按钮 final JButton clc_mun = new JButton(); clc_mun.addActionListener(e -> jisuan_text.setText(m1(jisuan_text, "*"))); clc_mun.setFont(new Font("华文楷体", Font.PLAIN, 42)); clc_mun.setText("*"); clc_mun.setBounds(350, 450, 80, 80); getContentPane().add(clc_mun); // 小数点按钮 final JButton num_point = new JButton(); num_point.addActionListener(e -> jisuan_text.setText(m1(jisuan_text, "."))); num_point.setFont(new Font("华文楷体", Font.PLAIN, 42)); num_point.setText("."); num_point.setBounds(50, 550, 80, 80); getContentPane().add(num_point); // 数字0按钮 final JButton num_0 = new JButton(); num_0.addActionListener(e -> jisuan_text.setText(jisuan_text.getText() + 0)); num_0.setFont(new Font("华文楷体", Font.PLAIN, 42)); num_0.setText("0"); num_0.setBounds(150, 550, 80, 80); getContentPane().add(num_0); // 等于按钮 final JButton num_equ = new JButton(); num_equ.addActionListener(e -> answer_text.setText(clc(this.se, jisuan_text.getText()))); num_equ.setFont(new Font("华文楷体", Font.PLAIN, 42)); num_equ.setText("="); num_equ.setBounds(250, 550, 80, 80); getContentPane().add(num_equ); // 除以按钮 final JButton clc_div = new JButton(); clc_div.addActionListener(e -> jisuan_text.setText(m1(jisuan_text, "/"))); clc_div.setFont(new Font("华文楷体", Font.PLAIN, 42)); clc_div.setText("/"); clc_div.setBounds(350, 550, 80, 80); getContentPane().add(clc_div); } /** * 获取字符串计算式转化为结果 * * @param se2 * ScriptEngine 对象 * @param text * 要转化的字符串 * @return 返回转化后的结果 * @see https://blog.csdn.net/m0_38000828/article/details/80975530 具体请参看这篇文章 */ private String clc(ScriptEngine se2, String text) { Object obj = null; try { obj = se.eval(text); } catch (ScriptException e) { e.printStackTrace(); } return obj.toString(); } /** * 当按下运算符相关按钮时候 <br> * 检测计算式是否以运算符等相关文本结尾 <br> * 是则返回空值 否则返回对应运算符的文本 * @param jisuan_text 显示计算式的文本框对象 * @param string 要追加的运算符 (/*-+.) * @return 返回要追加的字符串 等待调用相关函数追加到计算式的末尾 */ private String m1(JTextField jisuan_text, String string) { String Str = jisuan_text.getText() + ((jisuan_text.getText().endsWith("+") || (jisuan_text.getText().endsWith("-")) || (jisuan_text.getText().endsWith("*")) || (jisuan_text.getText().endsWith("/")) || (jisuan_text.getText().endsWith("."))) ? "" : string); return Str; } /** * 收尾工作 设置显示 和 当关闭了窗口时候关闭该程序。<br> * 注意:如果不设置则会在后台运行浪费内存资源。 */ private void display() { setVisible(1 < 2); setDefaultCloseOperation(EXIT_ON_CLOSE); } }
终于完成了。下面又到了总结时间了。
好了就啰嗦这么多,还是那句话,有任何问题,欢迎私信,评论。可能我第一时间没看到(报了个java班为期五个月,已经49天啦,手机上课时候上交了),我看到了,在我能力范围的,肯定会帮你解决的。
Title:the 9th blog
By:P&p
Time:2020-09-06 (学JAVA的第49天)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。