30天Lua重拾笔记33】Java + Lua计算机

这是我前几年作为学习/练习的例子。

看过与C交互後,接着来看看一个更实际应用的例子。不过不用C,来用Java。

为甚麽呢?Java自带一个跨平台的视窗开发套组,本身也有丰富的函式库可用,第三方函式库也众多,作为宿主语言是蛮好的标的。不过不直接使用原本的Lua,需要使用LuaJ

其实最初只是因为Android App使用Java开发。而当时Android Studio编译APK实在太慢,才会有为啥不能先用其他方式写逻辑、开发,为啥不先嵌入一个脚本语言?才去做的一个练习,之後我使用的套件也确实有用於Android App开发上。
是的,如果你是正在开发Android,不管是以前主要用Java还是後来的Kotlin,今天应该都还是可以使用LuaJ。

LuaJ已经停滞好一段时间了,本次范例的为GitHub上另一个分支。基本上遵循Lua 5.2的规则,也就是本系列有部份是Lua 5.3、5.4的语法并不能使用於之。

目标

本次范例主要目标:一个含有GUI的简易计算机。其包含:

  • Java提供GUI界面,和部份功能。
  • Lua处理逻辑。
  • 一个扩展方法,能够改变成品行为。

使用Lua撰写逻辑

使用Lua的好处之一,在不确定要以和总平台开发前,是可以先使Lua撰写逻辑,最後在嵌入到某个平台或框架。

使用的全局变数

first_number = 0 -- 累积数字(上个结果)
input_number = 0 -- 当前将处理数字
op           = "" -- 运算操作子(+-*/)

处理数值输入

最简单的处理数值输入的方式,就是当前数字乘十,在加上输入数字:

function on_number_click(number)
   input_number = input_number*10 + number
end

运算处理

function on_op_click(set_op)
   ------------------------
   -- 处理运算输入,保存状态
   ------------------------
   op = set_op  -- 设置运算处理
   first_number = input_number -- 保留数字
   input_number = 0  -- 等待新数字
end

function on_EQ_click()
   ------------------
   -- 处理实际运算
   -- 可以处理 +, -, *, /
   ------------------
   if(op == "+")then
      input_number = first_number + input_number
   elseif(op == "-") then
      input_number = first_number - input_number
   elseif(op == "*") then
      input_number = first_number * input_number
   elseif(op == "/") then
      input_number = first_number / input_number
   else
      error("op is "..op..[[, but want get "*", "+", "-" or "/"]])
   end

   first_number = 0
   op = ""
end

提供扩展性

pcall(dofile,"extend.txt")

Java界面

※ 注意!本文程序内容是拆分说明的,你可能无法分段执行,你可以参考最後附上的完整示例。

GUI.java

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class GUI{
    public static void main(String[] args){
        cal c = new cal();
        c.main();
    }
}

class cal {
    JFrame demo = new JFrame("计算机");

    // JButton exitBtn = new JButton("Exit");
    JPanel panel = new JPanel(new FlowLayout());
    JLabel display = new JLabel("显示器", SwingConstants.RIGHT);
    JButton[] number = {
        new JButton("1"),
        new JButton("2"),
        new JButton("3"),
        new JButton("4"),
        new JButton("5"),
        new JButton("6"),
        new JButton("7"),
        new JButton("8"),
        new JButton("9"),
        new JButton("0")
    };

    JButton eqBtn   = new JButton("=");
    JButton cBtn    = new JButton("C");
    JButton acBtn   = new JButton("AC");
    JButton addBtn  = new JButton("+");
    JButton minBtn  = new JButton("-");
    JButton divBtn  = new JButton("/");
    JButton douBtn  = new JButton("*");
    JButton backBtn = new JButton("←");
    JButton[] opBtn = {addBtn, minBtn, divBtn, douBtn};

    public void main() {
        demo.setSize(400, 300);
        demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        GridBagLayout GBLayout = new GridBagLayout();
        panel.setLayout(new GridBagLayout());

        demo.getContentPane().add(BorderLayout.NORTH, display);
        demo.add(panel);
        int x = 0,y = 1;
        for(JButton btn:number){
            int width = 1,height = 1;
            if (btn.getText().equals("0")){
                x++;
            }
            GridBagConstraints c = new GridBagConstraints();
            c.gridx = x;
            c.gridy = y;
            c.gridwidth = width;
            c.gridheight = height;
            c.weightx = 0.003;
            c.weighty = 0.003;
            c.fill = GridBagConstraints.NONE;
            c.anchor = GridBagConstraints.CENTER;
            panel.add(btn, c);
            x++;
            if (x%3 == 0){
                x = 0;
                y++;
            }
        }
        x = 4;
        y = 1;
        for(JButton btn:opBtn){
            int width = 1,height = 1;
            GridBagConstraints c = new GridBagConstraints();
            c.gridx = x;
            c.gridy = y;
            c.gridwidth = width;
            c.gridheight = height;
            c.weightx = 0.003;
            c.weighty = 0.003;
            c.fill = GridBagConstraints.NONE;
            c.anchor = GridBagConstraints.CENTER;
            panel.add(btn, c);
            y++;
        }
        GridBagConstraints c = new GridBagConstraints();
        c.gridx = 2;
        c.gridy = 4;
        c.gridwidth = 1;
        c.gridheight = 1;
        c.weightx = 0.003;
        c.weighty = 0.003;
        c.fill = GridBagConstraints.NONE;
        c.anchor = GridBagConstraints.CENTER;
        panel.add(eqBtn,c);
        c.gridx = 3;
        c.gridy = 0;
        panel.add(cBtn,c);
        c.gridx = 4;
        c.gridy = 0;
        panel.add(acBtn,c);
        c.gridx = 0;
        c.gridy = 4;
        panel.add(backBtn,c);

        //
        demo.setVisible(true);
    }
}

在Java载入LuaJ并绑定事件处理

/****************
  import LuaJ
******************/
import org.luaj.vm2.*;
import org.luaj.vm2.lib.jse.*;

/*******************************/

public void main() {
    /*Loading lua evn*/
    _G.get("require").call(LuaValue.valueOf("cal"));

    for(JButton btn:number){
        final String num = btn.getText();
        btn.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent e){
                    _G.get("on_number_click").call(LuaValue.valueOf(num));
                    updateScreen();
                }
            });
    }

    for(JButton btn:opBtn){
        final String op = btn.getText();
        btn.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent e){
                    _G.get("on_op_click").call(LuaValue.valueOf(op));
                    updateScreen();
                }
            });
    }

    eqBtn.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                _G.get("on_EQ_click").call();
                updateScreen();
            }
        });

    acBtn.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                _G.get("on_AC_click").call();
                updateScreen();
            }
        });

    cBtn.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                _G.get("on_C_click").call();
                updateScreen();
            }
        });

    backBtn.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                _G.get("on_back_click").call();
                //JOptionPane.showMessageDialog(null, "test");
                updateScreen();
            }
        });
}

void updateScreen(){
    LuaValue result = _G.get("input_number");
    display.setText(result.toString());
}

完整示例

JAVA-calculator可以看到完整示例,你也可以直接从Release页面下载来使用看看。

完整示例包含一些开发测试比较方便的函数,还有让Lua呼叫Java函数的能力的示例。

在後来,我将Lua逻辑移植到Kotlin+JavaFX里,可以於我的GitHub页面看到。

本文同步发表於个人网站


<<:  【Day 30】铁人赛後心得

>>:  第43篇-IT邦 的 DNS 、凭证都快过期了?!

D22 Django-bootstrap 网站美化工程 - fontawesomefree icon

为了Google的icon还有未来应该会需要加入一些icon所以安装个好用的python包 cons...

【Day 18】while 回圈 / do...while 回圈

今天我们来看看 while 回圈吧~ while 回圈的基本语法: while(test_Expre...

Day 20 什麽是「长尾关键字」?

我们提到设置关键字有些方法,让搜寻者可以更快找到他要的资源,而在关键字设定时,也会找些常委关键字来搭...

Day 13 文字人脸效果

文字人脸效果 教学原文参考:文字人脸效果 这篇文章会介绍使用 GIMP 的图层混合功能,搭配文字输入...

DevFest'21 Hsinchu & Taichung 议程录影上线啦!

今年的 DevFest Hsinchu & Taichung 已经在上周六顺利结束了!感谢 ...