最近在利用java进行课程设计,需要实现一个逆波兰表达式操作的计算器。我的java是刚入门水平,通过看各种教程和视频,网上查阅等等途径,虽然过程曲折、代码书写不规范、面向对象的思想不够清晰,但终究还是完成了这次课程设计。
首先,根据课程要求,以MVC的概念对整个程序进行统筹,我将代码分成Interface,Controleur,Accumulateur和Pile四个大class。
Interface主要是用来实现图形界面的编程,其中包括对awt包和swing包的使用,另外为了实现对键盘和按钮的监听,还需引入event包。Interface的整个界面如下:
上面五个文本框是用来显示栈内的前五个值(其实是四个,最低层是用来显示输入的),n键表示对栈顶元素取负,e表示enter。本界面共有三个JPanel,即jp1:12个JButton组成4*3的排列,jp2:右下方的五个JButton,以及jp3:五个文本框。对于JSplitpane,先让jp1和jp2进行分割形成一个jsp1,然后让jsp1和jp3进行分割,得到如上的界面图。
源代码如下:
public class Interface extends JFrame { //对JFrame进行扩展
JPanel jp1, jp2,jp3;
public JTextField[] jtf=new JTextField[5]; //显示的文本框
JSplitPane jsp1, jsp2;
public Interface()
{
jp1= new JPanel();
jp2= new JPanel();
jp3= new JPanel();
for(int i=0;i<5;i++)
{
jtf[i]=new JTextField();
jtf[i].setHorizontalAlignment(JTextField.RIGHT);
}
String s="0123456789.n/*-+e";
//ajouter le button à le panel
for(int i=0;i"));
}*/
if(i<12){
jp1.add(b);
}else if(i<17){
jp2.add(b);
}
b.addActionListener(new Controleur(this)); //注册按钮监听
b.addKeyListener(new Controleur(this)); //注册键盘监听
b.setActionCommand(s.substring(i, i+1)); //按钮监听的command
}
for(int i=0;i<5;i++)
{
jp3.add(jtf[i]);
}
jp1.setLayout(new GridLayout(4,3,2,2));//JButton放入JPanel
jp2.setLayout(new GridLayout(5,1));
jp3.setLayout(new GridLayout(5,1));
//ajouter le panel à le JFrame
jsp1=new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,jp1,jp2);
jsp1.setDividerSize(2);
jsp1.setEnabled(false);
jsp1.setDividerLocation(200);
jsp2=new JSplitPane(JSplitPane.VERTICAL_SPLIT,jp3,jsp1);
jsp2.setDividerLocation(170);
jsp2.setDividerSize(0);
this.add(jsp2);
this.setTitle("Calculatrice");//整个JFrame的属性设置
this.setIconImage(new ImageIcon("image/cc.jpg").getImage());
this.setSize(300, 350);
this.setLocation(520, 100);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
}
Accumulateur源码:
public class Accumulateur {
static Pile p= new Pile(); //此处要设置为静态,不然运行起来会提示栈空指针异常
public Float push(Float f){
return p.push(f);
}
public Float pop()
{
return p.pop();
}
public void drop()
{
p.pop();
}
public void clear()
{
while(!p.empty()){p.pop();}
}
public void Swap(){
float i,j;
i=p.pop();
j=p.pop();
p.push(i);
p.push(j);
}
public float add(){
float i,j;
i=p.pop();
j=p.pop();
p.push(i+j);
return i+j;
}
public float sub(){
float i,j;
i=p.pop();
j=p.pop();
p.push(i-j);
return i-j;
}
public float mult(){
float i,j;
i=p.pop();
j=p.pop();
p.push(i*j);
return i*j;
}
public float div(){
float i,j;
i=p.pop();
j=p.pop();
p.push(i/j);
return i/j;
}
public float neg(){
return p.push(0-p.pop());
}
}
Pile源码:
import java.util.*;
public class Pile extends Stack{
public Float push(Float f)
{
return super.push(f);
}
public Float pop()
{
return super.pop();
}
public void drop()
{
super.pop();
}
public void clear()
{
while(!super.empty()){super.pop();}
}
}
import java.awt.event.*;
import javax.swing.*;
public class Controleur implements ActionListener, KeyListener//此处要实现键盘和按钮的监听
{
JTextField []t; 用来从Interface传递参数
Accumulateur ac=new Accumulateur();
static Controleur ct;
public static void main(String []args)
{
Interface itf=new Interface();
ct=new Controleur(itf);
}
public Controleur(Interface it)//构造函数用来传递参数
{
this.t=it.jtf;
for(int i=0;i<5;i++)
{
t[i]=it.jtf[i];
}
}
//function a pour que le numero est ordonné
public void jtfdisplay()//此处函数是将栈内元素正确的显示在文本框,采取的方法是每次压栈结束,先将栈内的前五个元素pop进文本框内
{ //(栈内不满五个元素,则全部放入),由于pop出了本应该进行运算的数元素后,所以还需要将文本框的内容push回栈
for(int j=0;j<5;j++){
t[j].setText(null);
}
int i=3;
while(!ac.p.empty()&&i>=0){
t[i].setText(String.valueOf(ac.pop()));
i--;
}
do
{
i++;
ac.push(Float.parseFloat(t[i].getText()));
}while(i<3);
}
//actionEven
public void actionPerformed(ActionEvent e)//对按钮事件的操作
{
String sr=e.getActionCommand();
if (sr.charAt(0)>='0'&&sr.charAt(0)<='9'){//按的键是0,9之间,
if(t[4].getText().equals(null)) //若显示的框中无内容,直接加入
{ t[4].setText(sr); }
else
{t[4].setText(t[4].getText()+sr);} //若显示的框中已有内容需要组合
}else if(sr.equals(".")){ //小数点的显示
t[4].setText(t[4].getText()+sr);
}
else if(sr.equals("e"))//按下enter键进行压栈
{
//empiler
ac.push(Float.parseFloat(t[4].getText()));
ct.jtfdisplay();//并正确显示文本
}else{
switch(sr.charAt(0))
{
case '+': ac.add();break;
case '-': ac.sub();break;
case '*': ac.mult();break;
case '/':ac.div();break;
case 'n': ac.neg();break;
}
ct.jtfdisplay(); //在每次运算完,都需执行显示函数
}
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
//keyevent
@Override
public void keyPressed(KeyEvent e) {//对键盘事件的操作,和按钮事件大同小异
// TODO Auto-generated method stub
String sr=String.valueOf(e.getKeyChar());
if(e.getKeyCode()>=KeyEvent.VK_NUMPAD0&&e.getKeyCode()<=KeyEvent.VK_NUMPAD9){
if(t[4].getText().equals(null)){
t[4].setText(sr);
}
else{t[4].setText(t[4].getText()+sr);}
}else if(e.getKeyCode()==KeyEvent.VK_DECIMAL){
t[4].setText(t[4].getText()+sr);
}else if(e.getKeyCode()==KeyEvent.VK_ENTER){
ac.push(Float.parseFloat(t[4].getText()));
ct.jtfdisplay();
}else{
switch(e.getKeyCode())
{
case KeyEvent.VK_ADD: ac.add();break;
case KeyEvent.VK_SUBTRACT: ac.sub();break;
case KeyEvent.VK_MULTIPLY: ac.mult();break;
case KeyEvent.VK_DIVIDE: ac.div();break;
case KeyEvent.VK_N: ac.neg();break;
}
ct.jtfdisplay();
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
至此,设计完成。
(下图分别做了加和减的运算)
由于这是我第一次用java编程,也是第一次图形界面的编程,存在诸多问题,比如面前为止并未加入异常的处理,以及未形成成熟的java逻辑(老师在帮我处理问题时竟然说出了我的代码逻辑horrible),还需提高加强。
2015.02.01于Nîmes