Java で簡単な計算機を作成する

この記事ではアイデアを中心に紹介しますが、もちろんソースコードも記事の最後に記載しています。

コードの作成にも数日かかりましたが、理解しておくべき重要なことは、単にコピーして貼り付けて課題を提出するだけではないということです。

転載する場合は出典を明記し、著者の著作物を尊重してください。

目次

インターフェイスのデザイン:

イベントへの応答:

计算

詳細なコードは次のとおりです:

 要約:


単純な電卓を作成するには、最初のステップとしてインターフェイスを設計し、次にその機能を実装します。

イベントの実現は大きく以下のステップに分かれます。

  1. イベント ソースとリスニング ソースを決定する
  2. リスナーインターフェイスを実装する
  3. イベントソースをリスナーに登録する

それでは、一緒にコードを書き始めましょう。関数を書くためにコードをいくつかのディストリビューションに分割しました。最終的に、直接実行できる最終的なコードが完成しました。直接貼り付けると、クラス名とファイル名が表示されないことに注意してください同じでなければなりません。

インターフェイスのデザイン:

上部にテキスト ボックスがあり、中央に多くのボタンがあるはずです。ここの大きなフレームは BorderLayout クラスのレイアウト マネージャーを使用し、その NORTH (コンテナの上部) は FlowLayout クラスのレイアウト マネージャーで追加されています。テキスト ボックス、CENTER (コンテナの中央) が GirdLayout クラス レイアウト マネージャーで追加され、ボタンのグリッド、WEST (コンテナの左側)、EAST (コンテナの右側)、SOUTH (これらは、インターフェイスの見栄えを良くするために空白のラベルを追加することによって取り上げられます。

	//创建显示器面板,采用默认的流布局
	final JPanel viewPanel =new JPanel();
	//创建显示器
	final JTextField textField=new JTextField();
	//创建按钮面板
	final JPanel buttonPanel=new JPanel();
	//创建网络布局管理器对象
	final GridLayout gridLayout=new GridLayout(0,4);
	//按钮里面的内容
	String [][]names= {
			{"**","ln","lg","clear"},
			{"sin","cos","tan","X"},
			{"PI","//","%","/"},
			{"7","8","9","*"},
			{"4","5","6","-"},
			{"1","2","3","+"},
			{"_/``","0",".","="}};

	//创建按钮对象
	JButton[][] buttons=new JButton[names.length][4];
	//创建左侧的占位标签
	final JLabel leftLabel=new JLabel();
	//创建右侧的占位标签
	final JLabel rightLabel=new JLabel();
	//创建下侧的占位标签
	final JLabel bottomLabel=new JLabel();
//初始化组件
	public void initModule() {
		//初始化显示器相关数据
		textField.setEditable(false);//设置显示器不可编辑
		textField.setHorizontalAlignment(SwingConstants.RIGHT);
		textField.setColumns(35);//调节文本框的宽度
		textField.setPreferredSize(new Dimension(500,40));
	
		//初始化面板按钮
		gridLayout.setVgap(10);//设置组件的水平间距
		gridLayout.setHgap(10);//设置组件的垂直间距
		//初始化按钮对象
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				buttons[row][col]=new JButton(names[row][col]);//创建按钮
			}
		}
		
		//设置左侧标签的宽度
		leftLabel.setPreferredSize(new Dimension(10,0));
		//设置右侧标签的宽度
		rightLabel.setPreferredSize(new Dimension(10,0));
		//设置底部标签的宽度,组件的有高度,可以没宽度,和两边相反
		bottomLabel.setPreferredSize(new Dimension(0,10));
	}
//初始化面板
	public void initPanel() {
		//初始化组件
		initModule();
		
		viewPanel.add(textField);
		viewPanel.setPreferredSize(new Dimension(100,80));
		this.getContentPane().add(viewPanel,BorderLayout.NORTH);
		
		
		buttonPanel.setLayout(gridLayout);//按钮面板采用网络布局
		this.getContentPane().add(buttonPanel,BorderLayout.CENTER);//将按钮面板添加到窗体中间
		//把按钮添加到按钮面板中,虽然可以和初始化按钮写一起,但是便于理解还是把他们分开写了
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				buttonPanel.add(buttons[row][col]);
			}
		}
		this.getContentPane().add(leftLabel,BorderLayout.WEST);
		this.getContentPane().add(rightLabel,BorderLayout.EAST);
		this.getContentPane().add(bottomLabel,BorderLayout.SOUTH);
	}
	
    //初始化窗体
	public void initFrame() {
		//设置窗体的标题
		this.setTitle("计算器");
		//设置窗体大小不可改变
		this.setResizable(false);
		//设置界面置顶(就是页面不会别其他页面覆盖,界面始终在最上面)
        this.setAlwaysOnTop(true);
        //设置窗体的位置和大小,位置应该失效了,因为设置了居中
		//this.setBounds(300,150,400,500);
        //那还是改成setSize吧,设置窗体的大小就行了
        this.setSize(400,500);
		//居中
		this.setLocationRelativeTo(null);
		//设置窗体关闭按钮的动作作为退出
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//将显示器面板添加到窗体顶部
		this.getContentPane().add(viewPanel,BorderLayout.NORTH);
	}

発生した問題:

質問 1: 上部のテキスト ボックスのサイズと幅が設定できず、変更されないままになります。

解決策: setColumns(); を変更することで調整は成功しました。原理はまだわかりません。ご存知の方がいらっしゃいましたら、教えていただければ幸いです。以前 setPreferredSize(); を変更していましたが、その後は応答がありませんでした。フロー レイアウト マネージャーは空白を変更しただけです。さらに多くの場所があります。

質問 2: 下部の幅bottomLabel.setPreferredSize(new Dimension(10,0)); は、この変更に応答しません。

解決策: もちろんこれではうまくいきません。下の幅を10、高さを0に足してください。当然結果は表示されません。左右を直接コピーするのが面倒で表示されませんでした。したがって、bottomLabel.setPreferredSize(new Dimension(0, 10)); となるはずです。

イベント応答:

Java |スイング JTextField のコンテンツをクリアする方法_jtextfield のデータをクリアする方法_Huang Jiajun のブログ - CSDN ブログ状況の説明: クリアするボタンを使用して、JTextField にデータが入力されています。内部のデータ、それを達成する方法!まず最初に言いたいのは、JTextField のコンテンツを空に設定できるようなメソッドは存在しませんが、これは賢く行うことができます: jTextField.setText(""); を使用してコンテンツを次のように置き換えます。 JTextField をクリアするための空の文字列。内容...https://blog.csdn.net/weixin_48419914/article/details/121470250解決策Java で JButton を追加/クリックするとキーボード監視が無効になる問題 問題_QASWINE のブログ - CSDN ブログ問題: JButton をクリックした後、使用できる本来のキーボード操作が使用できなくなります。理由: JButton をクリックすると、フォーカスはボタン上にあり、キーボード リスナーがあります。コンポーネント (JFrame、-JPanel) はフォーカスを失います。解決策: キーボード リスナーがフレーム上にある場合は、frame.requestFocus() を追加してフォーカスを取り戻します。以下に例を示します。 button.addActionListener(new ActionListener() { ...https://blog.csdn.net/qq_33831360/article/details/103280448Java キーボード イベントが無効であるいくつかの理由_mapcontrol.addkeylistener(_imonkeyi のブログ - CSDN ブログ..https://blog.csdn.net /imonkeyi/記事/詳細/86177348

 具体的な方法はメソッド内の呼び出しに依存します 書くためのメソッドはあるはずです 次はイベントソースと監視ソースを決定します キーボードで文字を入力してマウスでボタンをクリックする予定です

1. イベントソースとリスニングソースを決定する

イベント ソース: JButton[][] button=new JButton[names.length][4]; ボタンとその独自のフレーム

リスニングソース: ActionListener、KeyListener

2. リスナーインターフェイスを実装する

//重写鼠标点击事件
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		JButton button =(JButton)e.getSource();//获得触发此次动作事件的按钮对象
		String buttonName =e.getActionCommand();//获得触发此次动作事件的按钮的标签文本
		
	
		if(buttonName.equals("X")) {
			//没有字符串之后就不能删除了
			if(sb.length()!=0) {
				sb.deleteCharAt(sb.length()-1);
				//textField.setText(output);//删除之后还需要立即显示一次,不然没有反应
			}
		}else if(buttonName.equals("R")){
			//就是把[0,length)的内容删除即可
			sb.delete(0, sb.length());
			//删除之后还需要立即显示一次,不然没有反应
			//textField.setText(output);
		}else if(buttonName.equals("=")) {
			//计算结果
			result();
		}else {
			sb.append(buttonName);
			//textField.setText(output);
		}
		//反正每次响应事件之后都要更新,干脆直接放在最后
		outPut();
		//要重新使框架获得焦点,这要写呢,不写就按下按钮之后键盘就没反应了
		if(buttonName.equals("=")) {
			//就是把[0,length)的内容删除即可
			sb.delete(0, sb.length());//结果出来之后就是重新输入计算下一个
		}
		this.requestFocus();
	}
            @Override
        	public void keyTyped(KeyEvent e) {
        		// TODO Auto-generated method stub
        		
        	}
        	//按着按键不松时调用
        	@Override
        	public void keyPressed(KeyEvent e) {
        		// TODO Auto-generated method stub
        	}
        	//按键松开后执行
        	@Override
        	public void keyReleased(KeyEvent e) {
        		// TODO Auto-generated method stub
        		//System.out.println("我被调用了啦");
        		int code = e.getKeyCode();
        		//输出每次按下的键盘按钮对应的code
        		//System.out.println(code);
        		//用键盘添加数字
        		//单纯输入数字,shift键没有被按下,不然就加减乘除无法被响应了
        		if(code>=48 && code<=57 && !e.isShiftDown()) {
        			sb.append((char)code);
        			//outPut();
        		}else if(code==56 && e.isShiftDown()) {
        			sb.append("*");
        			//outPut();
        		}else if(code==47 && !e.isShiftDown()) {
        			sb.append("/");
        		}else if(code==8) {//Backspace键
        			//删除最后的一个字符
        			sb.deleteCharAt(sb.length()-1);
        		}else if(code==53 && e.isShiftDown()) {
        			sb.append("%");
        		}else if(code==61 && e.isShiftDown()) {
        			sb.append("+");
        		}else if(code==61 && !e.isShiftDown()) {//"="
        			//计算结果
        			result();
        		}else if(code==45 && !e.isShiftDown()) {
        			sb.append("-");
        		}else if(code==46 && !e.isShiftDown()) {
        			sb.append(".");
        		}else if(code==10) {//Enter键
        			//计算结果
        			result();
        		}
        		//每次键盘输入之后都要更新,所以干脆就直接放判断最后
        		outPut();
        		//"="和"Enter"键
        		if(code==61 && !e.isShiftDown()||code==10) {
        			//就是把[0,length)的内容删除即可
        			sb.delete(0, sb.length());//结果出来之后就是重新输入计算下一个
        		}
        	}
        }

3. イベントソースをリスナーに登録する

public void buttonAction() {
		//按钮绑定动作事件,和自己绑定,自己实现的监听的方法
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				(buttons[row][col]).addActionListener(this);
			}
		}	
		//给整个界面添加键盘监听事件
        this.addKeyListener(new KeyListener() {
        	
        	@Override
        	public void keyTyped(KeyEvent e) {
        		// TODO Auto-generated method stub
        		
        	}
        	//按着按键不松时调用
        	@Override
        	public void keyPressed(KeyEvent e) {
        		// TODO Auto-generated method stub
        	}
        	//按键松开后执行
        	@Override
        	public void keyReleased(KeyEvent e) {
        		// TODO Auto-generated method stub
        		//System.out.println("我被调用了啦");
        		int code = e.getKeyCode();
        		//输出每次按下的键盘按钮对应的code
        		//System.out.println(code);
        		//用键盘添加数字
        		//单纯输入数字,shift键没有被按下,不然就加减乘除无法被响应了
        		if(code>=48 && code<=57 && !e.isShiftDown()) {
        			sb.append((char)code);
        			//outPut();
        		}else if(code==56 && e.isShiftDown()) {
        			sb.append("*");
        			//outPut();
        		}else if(code==47 && !e.isShiftDown()) {
        			sb.append("/");
        		}else if(code==8) {//Backspace键
        			//删除最后的一个字符
        			sb.deleteCharAt(sb.length()-1);
        		}else if(code==53 && e.isShiftDown()) {
        			sb.append("%");
        		}else if(code==61 && e.isShiftDown()) {
        			sb.append("+");
        		}else if(code==61 && !e.isShiftDown()) {//"="
        			//计算结果
        			result();
        		}else if(code==45 && !e.isShiftDown()) {
        			sb.append("-");
        		}else if(code==46 && !e.isShiftDown()) {
        			sb.append(".");
        		}else if(code==10) {//Enter键
        			//计算结果
        			result();
        		}
        		//每次键盘输入之后都要更新,所以干脆就直接放判断最后
        		outPut();
        		//"="和"Enter"键
        		if(code==61 && !e.isShiftDown()||code==10) {
        			//就是把[0,length)的内容删除即可
        			sb.delete(0, sb.length());//结果出来之后就是重新输入计算下一个
        		}
        	}
        });
	}public void buttonAction() {
		//按钮绑定动作事件,和自己绑定,自己实现的监听的方法
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				(buttons[row][col]).addActionListener(this);
			}
		}	
		//给整个界面添加键盘监听事件
        this.addKeyListener(new KeyListener() {
        	
        	@Override
        	public void keyTyped(KeyEvent e) {
        		// TODO Auto-generated method stub
        		
        	}
        	//按着按键不松时调用
        	@Override
        	public void keyPressed(KeyEvent e) {
        		// TODO Auto-generated method stub
        	}
        	//按键松开后执行
        	@Override
        	public void keyReleased(KeyEvent e) {
        		// TODO Auto-generated method stub
        		//System.out.println("我被调用了啦");
        		int code = e.getKeyCode();
        		//输出每次按下的键盘按钮对应的code
        		//System.out.println(code);
        		//用键盘添加数字
        		//单纯输入数字,shift键没有被按下,不然就加减乘除无法被响应了
        		if(code>=48 && code<=57 && !e.isShiftDown()) {
        			sb.append((char)code);
        			//outPut();
        		}else if(code==56 && e.isShiftDown()) {
        			sb.append("*");
        			//outPut();
        		}else if(code==47 && !e.isShiftDown()) {
        			sb.append("/");
        		}else if(code==8) {//Backspace键
        			//删除最后的一个字符
        			sb.deleteCharAt(sb.length()-1);
        		}else if(code==53 && e.isShiftDown()) {
        			sb.append("%");
        		}else if(code==61 && e.isShiftDown()) {
        			sb.append("+");
        		}else if(code==61 && !e.isShiftDown()) {//"="
        			//计算结果
        			result();
        		}else if(code==45 && !e.isShiftDown()) {
        			sb.append("-");
        		}else if(code==46 && !e.isShiftDown()) {
        			sb.append(".");
        		}else if(code==10) {//Enter键
        			//计算结果
        			result();
        		}
        		//每次键盘输入之后都要更新,所以干脆就直接放判断最后
        		outPut();
        		//"="和"Enter"键
        		if(code==61 && !e.isShiftDown()||code==10) {
        			//就是把[0,length)的内容删除即可
        			sb.delete(0, sb.length());//结果出来之后就是重新输入计算下一个
        		}
        	}
        });
	}

質問3: 無応答の後に対応する応答がある必要があるため、出力する必要がある場合がありますが、入力ボタンの一部に複数の文字からなる文字列が含まれており、計算および削除の際、文字列全体ではなく単一の文字が削除されます。たとえば、sin 入力が「sin」の場合、削除では最後の「n」のみを削除できます。

解決策: ここでは HashMap を使用して問題を解決しましたが、プログラムでは単一の文字であり、出力は出力文字で表される文字列になるため、削除や計算などの操作が便利になります。

質問4: *、+などの文字のキーボード入力が得られません。

解決策: キーボードから入力されたコードを取得するために e.getKeyCode(); を使用しましたが、* と 8 は同じコードであり、どちらも 56 です。違いはシフト キーが押されているかどうかです。以前は keyPressed で記述したかったのです。と応答するようにしましたが、実装できないと感じました。後で、Shift キーが押されたかどうかを判断する e.isShiftDown(); を見て、実際に試してみたかったのですが、実際に機能することがわかったので、 e.isShiftDown( ); の判定を追加しました。これにより、'*' と '8' が同じコードを持つ状況が解決されます。

	//按钮里面的内容
	String [][]names= {
			{"**","ln","lg","clear"},
			{"sin","cos","tan","X"},
			{"PI","//","%","/"},
			{"7","8","9","*"},
			{"4","5","6","-"},
			{"1","2","3","+"},
			{"_/``","0",".","="}};
	//程序里面的内容
	String [][]target= {
			{"A","N","G","R"},
			{"S","C","T","X"},
			{"P","B","%","/"},
			{"7","8","9","*"},
			{"4","5","6","-"},
			{"1","2","3","+"},
			{"D","0",".","="}};    
    //用来对应文本框的输出,还是选择用HashMap来存储
	Map<String ,String>map=new HashMap<String,String>();
    //通过哈希表实现输出字符串和里面的字符串的不同标识
	public void Stringbind() {
		
		//map.put(getWarningString(), getName())
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				map.put(target[row][col], names[row][col]);
				//System.out.println("执行成功");
			}
		}
		//用来判断值有没有填写进去
		//System.out.println(map.size());
	}

質問 5: 検索すると、出力はターゲット文字列ではなく null になります。

解決策: 長い間これを探していました。最後に、HashMap に要素がいくつあるか調べたところ、要素が保存されていることがわかりました。問題は、文字列 "A" と 'A' ; は同じものではなかったため、ハッシュ テーブルが見つかりませんでした。

出力は関数を通じて実現されます

    //用来更新文本框输出的字符串
	StringBuffer sb=new StringBuffer();
	//用来对应文本框的输出,还是选择用HashMap来存储
	Map<String ,String>map=new HashMap<String,String>();
	//输出的字符串放这个里面,每次使用都需要清零哈
	String output="";
    //记录每次将输出的字符串
	public void outPut() {
		output="";
		for(int i=0;i<sb.length();i++) {
		//这我可能知道原因了,字符串"A"和'A'不一样
			output= output+map.get(String.valueOf(sb.charAt(i)));
		}
		//每次更新都要输出,我直接写到方法里面算了
		textField.setText(output);
	}

問題 6: キーボード入力が失敗する。

解決策: これは、フォーカスすることによってのみ実現できます。 this.setFocusable(true); を呼び出します。

質問7: 最初はキーボードから入力が出力されるのですが、パネル内のボタンを押した後キーボードから入力できなくなります。

解決策: ボタンを押すたびに this.requestFocus() を再フォーカスします。フレームを再フォーカスするには、これを記述する必要があります。書き込まずにボタンを押すと、キーボードが応答しなくなります。

最後の部分は電卓関数の実装ですが、最も簡単に実装できるのは、'=' 記号を除いたボタンを文字列に直接追加し、最後に出力することです。ここでは StringBuffer を追加して更新する必要があるので使用します。

削除ボタンは文字列の最後の文字を削除し、クリアボタンは文字列のすべての文字を削除します。

//删除最后一个字符
if(sb.length()!=0) {
	sb.deleteCharAt(sb.length()-1);
	//textField.setText(output);//删除之后还需要立即显示一次,不然没有反应
}
//删除所有的字符,确定是范围是[0,length)
sb.delete(0, sb.length());

質問8: ボタンを押しても削除が表示されません。

解決策: これは、プログラム内で削除されて表示されないためですが、ユーザーには削除されていないことがわかるため、出力を更新する必要があります。

計算します:

Java による文字列計算の実現 Calculation_Duan 593405572 のブログ - CSDN ブログ文字列 (数値、小数点、加算、減算、パーセンテージの乗算、除算を含む) を入力し、計算をシミュレートします。計算を実行するための電卓。アイデア: パーセント、乗算、除算、加算、減算を演算子の優先順位に従って順番に演算します。文字列をスキャンし、演算子の前後の数値を double に変換して計算し、元の文字列の部分計算を計算結果に置き換えます。 import java.util.Scanner;public class Main{public static double f(String s){double p = 0;//パーセント計算 for(int i = 0; i &...https://blog.csdn.net/d593405572/article/details/106713937

Java での角度とラジアンの変換、三角関数、逆三角関数_java 角度からラジアンへの変換-CSDN ブログJava での角度とラジアンの変換、三角関数、逆三角関数 a>https://blog.csdn.net/senxu_/article/details/126025606

次に、最後の計算ステップが始まります。

まず計算の優先順位を決めますが、ここでは括弧を導入していないので、lg、ln、sin、cos、tan、ルート符号を右側のオペランドと合わせて全体としてみなします。

文字列の演算は、オペランドを見つけて演算を実行し、演算結果の文字列を演算前の文字列に置き換えることにより、文字列を演算子で分割することです。

    //计算每次的结果
	public void result() {
		
		//对应关系
		//**--->A  ln--->N  lg--->G  sin--->S   cos--->C
		//tan--->T  PI--->P  //--->B  /``--->D
		//计算是按照优先级来的
		//PI不算运算,直接填进去吧
		//也不行,本来就是用一个符号来表示,这突然变成一长串数字,那还是运算的时候展开吧
		//展开PI
		try {
			pi();
			//ln,lg,sin,cos,tan,开根号的运算
			special();
			//乘方运算
			power();
			//乘除,整除,求余运算
			multiplyDivide();
			//加减计算
			addAndSubtract();
		}catch(Exception e) {
			//弹出警告的弹窗
			warning();
		}finally {
			System.out.println("今天又是元气满满的一天");
		}
	}

 PI は置き換えです。計算するときに PI を Math.PI に置き換えるだけです。ハッシュ テーブルを使用する本来の目的は、プログラム内の文字列を表すために 1 文字を使用することなので、計算するときのみ PI を使用します。展開します。

    //展开PI
	public void pi() {
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='P') {
				double res=Math.PI;
				String resString=res+"";
				//更新字符串
				sb=sb.replace(i, i+1, resString);
				i=resString.length()-1;
				continue;
			}
		}
	}

 これらには名前を付けず、単にこれで表しますが、オペランドが 1 つだけ必要なことが特徴です。

したがって、右側のオペランドを探し、オペランドの長さを数え、見つかった数値をそれに応じて変更して置き換えるだけで済みます。

質問 9: Sin と Tan は使いにくく、PI を使用するとエラーが直接報告されます。

解決策: このラジアン系は範囲外のようです。括弧を追加しなかったので、Math.toRadians(num) を使用して角度系をラジアン系に変換して計算しましょう。

//ln,lg,sin,cos,tan,开根号的运算
	public void special() {
		//都是用右边一个操作数的运算
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='N'||sb.charAt(i)=='G'||
					sb.charAt(i)=='S'||sb.charAt(i)=='C'||
					sb.charAt(i)=='T'||sb.charAt(i)=='D') {
				double num=0;
				int len=0;//记录字符串长度,之后还要进行字符串的替换呢
				//只需要应该一边的数字即可
				for(int j=i+1;j<sb.length();j++) {
					//是j不是i,咋又错在这里了
					if(sb.charAt(j)=='*'||sb.charAt(j)=='/'||
							sb.charAt(j)=='%'||sb.charAt(j)=='B'||
							sb.charAt(j)=='+'||sb.charAt(j)=='-'||
							sb.charAt(j)=='A'||
							sb.charAt(j)=='N'||sb.charAt(j)=='G'||
							sb.charAt(j)=='S'||sb.charAt(j)=='C'||
							sb.charAt(j)=='T'||sb.charAt(j)=='D') {
						String s1=sb.substring(i+1,j);
						num=Double.parseDouble(s1);
						len=s1.length();
						break;
					}
					//找到最右边咯,中间没有运算符那也要停止了
					if(j==sb.length()-1) {
						//这边是到j+1哈,找错误找了半天
						//如果右边是一位的数字,就会导致运算是数是空
						//如果右边是多位的数字,那么最右边的数不会参与运算,所以需要[i+1,j+1)
						String s1=sb.substring(i+1,j+1);
						num=Double.parseDouble(s1);
						len=s1.length();
						break;
					}
				}
				//进行运算
				//ln运算
				if(sb.charAt(i)=='N') {
					double res=Math.log(num);
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//lg运算
				if(sb.charAt(i)=='G') {
					//换底公式
					double res=Math.log(num)/Math.log(10);
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//sin运算
				if(sb.charAt(i)=='S') {
					//还是采用角度制吧,弧度制取值用PI越界了,如果要除的话要加入括号的机制
					//偷懒一下就用角度值吧,不用加入括号
					double res=Math.sin(Math.toRadians(num));
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//cos运算
				if(sb.charAt(i)=='C') {
					//还是采用角度制吧,弧度制取值用PI越界了,如果要除的话要加入括号的机制
					//偷懒一下就用角度值吧,不用加入括号
					double res=Math.cos(Math.toRadians(num));
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//tan运算
				if(sb.charAt(i)=='T') {
					//还是采用角度制吧,弧度制取值用PI越界了,如果要除的话要加入括号的机制
					//偷懒一下就用角度值吧,不用加入括号
					double res=Math.tan(Math.toRadians(num));
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//开根号运算
				if(sb.charAt(i)=='D') {
					double res=Math.sqrt(num);
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
			}
		}
	}

次に 2 つのオペランドが続きます。べき乗を例に考えてみましょう。

左右のオペランドを探します。左側では優先度の低い演算文字と文字列の範囲外の状況を考慮する必要がありますが、右側ではこれだけでなく文字自体も考慮する必要があります。

は左に判断します (sb.charAt(j)=='*'||sb.charAt(j)=='/'|| sb .charAt(j)=='%'||sb.charAt(j)=='B'||sb.charAt(j)=='+ '||sb.charAt(j)=='-')、右側の判定は (sb.charAt(j)=='*' ||sb.charAt(j)=='/'||sb.charAt(j)=='%'||sb.charAt(j)== 39;B 39;||sb.charAt(j)=='+'||sb.charAt(j)=='-'|| sb.charAt(j)=='A')、文字列のトラバーサルは左から右に行われるため、これを理解する必要があります。右側の「A」はまだ判定されていませんが、左側の判定は終了しています。

    //乘方运算
	public void power(){
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='A') {
				double num1=0,num2=0;
				int len1=0,len2=0;//记录字符串长度,之后还要进行字符串的替换呢
				for(int j=i-1;j>=0;j--) {
					//得到第一个操作数,遇到加减乘除就停止了,相当于分隔了操作数
					if(sb.charAt(j)=='*'||sb.charAt(j)=='/'||
							sb.charAt(j)=='%'||sb.charAt(j)=='B'||
							sb.charAt(j)=='+'||sb.charAt(j)=='-') {
						String s1=sb.substring(j+1,i);
						num1=Double.parseDouble(s1);
						len1=s1.length();
						break;
					}
					//找到边界了,只能停止了咯
					if(j==0) {
						String s1=sb.substring(j,i);
						num1=Double.parseDouble(s1);
						len1=s1.length();
						break;
					}
				}
				//往右边找第二个操作数,第二个操作数的话遇到乘除也需要提前终止,第一个不需要
				//因为如果第一个操作数有乘除这种符号,就已经提前终止了,只有第二个操作数才需要考虑
				for(int j=i+1;j<sb.length();j++) {
					if(sb.charAt(j)=='*'||sb.charAt(j)=='/'||
							sb.charAt(j)=='%'||sb.charAt(j)=='B'||
							sb.charAt(j)=='+'||sb.charAt(j)=='-'||sb.charAt(j)=='A') {
						String s1=sb.substring(i+1,j);
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
					//找到最右边咯,中间没有运算符那也要停止了
					if(j==sb.length()-1) {
						//这边是到j+1哈,找错误找了半天
						//如果右边是一位的数字,就会导致运算是数是空
						//如果右边是多位的数字,那么最右边的数不会参与运算,所以需要[i+1,j+1)
						String s1=sb.substring(i+1,j+1);
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
				}
				//进行运算
				double res=Math.pow(num1, num2);
				String resString=res+"";
				//更新字符串
				sb=sb.replace(i-len1, i+len2+1, resString);
				i=i-len1-1+resString.length();
				continue;
			}
		}
	}

足し算、引き算、掛け算、割り算もこれと同じです。

質問 10: 複数の例外がスローされる場合があります。

答え: ループ内のオペランドを判断する場合、 sb.charAt(j) は sb.charAt(i) と記述されます。2 つ目は、2 番目のオペランドの境界を判断する場合です。 String s1=sb.substring(i+1 , j+1); String s1=sb.substring(i+1,j); として書き込まれます; これも、演算子に遭遇したときに前の停止が停止したため、境界判定は行われないため、前の結果の直接コピーです。 j+ を考慮する必要があります 1. しかし、これで終わりです。 ポインタは数値を指します。 右側が 1 桁の数値の場合、この演算により数値は空になります。 右側が複数の場合、桁番号の場合、右端の番号は操作に参加しないため、[i+1,j+1) が必要です。

操作が解決されたら、例外を処理します。前のコードは、例外がスローされる場所を追加したことを示しています。エラーがある場合は、ポップアップ ウィンドウが表示されます。また、プログラムの堅牢性をテストするために、finally も使用します。本来は除数が0の場合の判定を追加しました。浮動小数点数なので0の判定条件をMath.abs(num2)<=1e-6としているのですが、反応しませんでした。と思ったので単純に止めましたが、異常と判断したらポップアップウィンドウを投げるだけです。これでさらに便利になりました。

注: ここにはバグがあります。最初にオペランドを 0 に設定したためです。これは、数値が 1 つしかない場合でも演算できることを意味します。たとえば、num1 は次のとおりであるため、「*1」は実行できます。 0 に等しい。興味があれば、これを自分で改善できます

	//警告标签,放在弹窗里面
	final JLabel warningLabel=new JLabel();

    //警告,输入不合法的时候弹出
	public void warning() {
		JDialog jDialog=new JDialog();//创建弹窗对象
		jDialog.setTitle("警告");//设置弹窗标题,和Frame差不多,可能还要通过标签来提示
		jDialog.setSize(500,600);//设置弹窗的大小
		jDialog.setAlwaysOnTop(true);//让弹窗置顶
		jDialog.setLocationRelativeTo(null);//让弹窗居中
		jDialog.setModal(true);//弹窗不关闭则无法操作下面的界面
		
		//设置字体的类型,加粗,和大小
		warningLabel.setFont(new Font("Microsoft YaHei",Font.BOLD,30));
		//输出警告提示符
		warningLabel.setText("就是你小子在搞乱的是吧!!!");
		//标签的位置和大小
		warningLabel.setBounds(60,180,500,100);
		
		//这个也要取消布局管理器才行
		jDialog.getContentPane().setLayout(null);
		//往弹窗中添加标签
		jDialog.getContentPane().add(warningLabel);
		jDialog.setVisible(true);//让弹窗显示出来
		
	}

 ポップアップウィンドウと警告の内容はすべて私がデザインしたもので、ポップアップウィンドウはフレームのようなもので、中にパネルもありますが、レイアウトをキャンセルして、X、Y 座標メソッドで移動させました。以下のようなポップアップウィンドウが表示されます。

質問 11: ボタンを印刷するときに配列が範囲外になる

配列全体が行列ではないため、メモリループと外側のループの境界値は同じではなく、内側のループの制限は外側のループに対応する1次元配列の長さを境界値として使用します。

詳細なコードは次のとおりです。



import java.awt.*;
import java.awt.event.*;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;


public class CalculatorFrame extends JFrame implements ActionListener{
	//主方法
	public static void main(String[] args) {
		CalculatorFrame cf=new CalculatorFrame();
	}
	//创建显示器面板,采用默认的流布局
	final JPanel viewPanel =new JPanel();
	//创建显示器
	final JTextField textField=new JTextField();
	//创建按钮面板
	final JPanel buttonPanel=new JPanel();
	//创建网络布局管理器对象
	final GridLayout gridLayout=new GridLayout(0,4);
	//按钮里面的内容
	String [][]names= {
			{"**","ln","lg","clear"},
			{"sin","cos","tan","X"},
			{"PI","//","%","/"},
			{"7","8","9","*"},
			{"4","5","6","-"},
			{"1","2","3","+"},
			{"_/``","0",".","="}};
	//程序里面的内容
	String [][]target= {
			{"A","N","G","R"},
			{"S","C","T","X"},
			{"P","B","%","/"},
			{"7","8","9","*"},
			{"4","5","6","-"},
			{"1","2","3","+"},
			{"D","0",".","="}};
	//创建按钮对象
	JButton[][] buttons=new JButton[names.length][4];
	//创建左侧的占位标签
	final JLabel leftLabel=new JLabel();
	//创建右侧的占位标签
	final JLabel rightLabel=new JLabel();
	//创建下侧的占位标签
	final JLabel bottomLabel=new JLabel();
	//存储计算结果
	double result=0;
	//用来更新文本框输出的字符串
	StringBuffer sb=new StringBuffer();
	//用来对应文本框的输出,还是选择用HashMap来存储
	Map<String ,String>map=new HashMap<String,String>();
	//输出的字符串放这个里面,每次使用都需要清零哈
	String output="";
	//警告标签,放在弹窗里面
	final JLabel warningLabel=new JLabel();
	
	public CalculatorFrame(){
		//初始化窗体
		initFrame();
		//初始化面板
		initPanel();
		//初始化哈希表里面的数据
		Stringbind();
		//绑定事件.键盘绑定也放在里面
		buttonAction();
		//窗体可见,放最后吧,不然里面的东西不会显示呢
		this.setVisible(true);
	}
	//初始化窗体
	public void initFrame() {
		//设置窗体的标题
		this.setTitle("计算器");
		//设置窗体大小不可改变
		this.setResizable(false);
		//设置界面置顶(就是页面不会别其他页面覆盖,界面始终在最上面)
        this.setAlwaysOnTop(true);
        //设置窗体的位置和大小,位置应该失效了,因为设置了居中
		//this.setBounds(300,150,400,500);
        //那还是改成setSize吧,设置窗体的大小就行了
        this.setSize(400,500);
		//居中
		this.setLocationRelativeTo(null);
		//设置窗体关闭按钮的动作作为退出
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//将显示器面板添加到窗体顶部
		this.getContentPane().add(viewPanel,BorderLayout.NORTH);
		//添加屏幕焦点,没有这个用键盘输入没反应埃
		this.setFocusable(true);
	}
	//初始化面板
	public void initPanel() {
		//初始化组件
		initModule();
		
		viewPanel.add(textField);
		viewPanel.setPreferredSize(new Dimension(100,80));
		this.getContentPane().add(viewPanel,BorderLayout.NORTH);
		
		
		buttonPanel.setLayout(gridLayout);//按钮面板采用网络布局
		this.getContentPane().add(buttonPanel,BorderLayout.CENTER);//将按钮面板添加到窗体中间
		//把按钮添加到按钮面板中,虽然可以和初始化按钮写一起,但是便于理解还是把他们分开写了
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				buttonPanel.add(buttons[row][col]);
			}
		}
		this.getContentPane().add(leftLabel,BorderLayout.WEST);
		this.getContentPane().add(rightLabel,BorderLayout.EAST);
		this.getContentPane().add(bottomLabel,BorderLayout.SOUTH);
	}
	
	//初始化组件
	public void initModule() {
		//初始化显示器相关数据
		textField.setEditable(false);//设置显示器不可编辑
		textField.setHorizontalAlignment(SwingConstants.RIGHT);
		textField.setColumns(35);//调节文本框的宽度
		textField.setPreferredSize(new Dimension(500,40));
	
		//初始化面板按钮
		gridLayout.setVgap(10);//设置组件的水平间距
		gridLayout.setHgap(10);//设置组件的垂直间距
		//初始化按钮对象
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				buttons[row][col]=new JButton(names[row][col]);//创建按钮
			}
		}
		//静态的初始化设置一些,把多个单词的给标识起来
		/*buttons[0][0].setActionCommand("A");//"**"
		buttons[0][1].setActionCommand("N");//"ln"
		buttons[0][2].setActionCommand("G");//"lg"
		buttons[0][3].setActionCommand("R");//clear
		buttons[1][0].setActionCommand("S");//sin
		buttons[1][1].setActionCommand("C");//cos
		buttons[1][2].setActionCommand("T");//tan
		buttons[2][0].setActionCommand("P");//PT
		buttons[2][1].setActionCommand("B");//"//"
		buttons[6][0].setActionCommand("D");//"+/-"
		*/
		//还是用循环全部绑定吧,自己一个一个绑代码灵活性不高
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				buttons[row][col].setActionCommand(target[row][col]);
			}
		}
		
		//设置左侧标签的宽度
		leftLabel.setPreferredSize(new Dimension(10,0));
		//设置右侧标签的宽度
		rightLabel.setPreferredSize(new Dimension(10,0));
		//设置底部标签的宽度,组件的有高度,可以没宽度,和两边相反
		bottomLabel.setPreferredSize(new Dimension(0,10));
	}
	//通过哈希表实现输出字符串和里面的字符串的不同标识
	public void Stringbind() {
		
		//map.put(getWarningString(), getName())
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				map.put(target[row][col], names[row][col]);
				//System.out.println("执行成功");
			}
		}
		//用来判断值有没有填写进去
		//System.out.println(map.size());
	}
	
	public void buttonAction() {
		//按钮绑定动作事件,和自己绑定,自己实现的监听的方法
		for(int row=0;row<names.length;row++) {
			for(int col=0;col<names[row].length;col++) {
				(buttons[row][col]).addActionListener(this);
			}
		}	
		//给整个界面添加键盘监听事件
        this.addKeyListener(new KeyListener() {
        	
        	@Override
        	public void keyTyped(KeyEvent e) {
        		// TODO Auto-generated method stub
        		
        	}
        	//按着按键不松时调用
        	@Override
        	public void keyPressed(KeyEvent e) {
        		// TODO Auto-generated method stub
        	}
        	//按键松开后执行
        	@Override
        	public void keyReleased(KeyEvent e) {
        		// TODO Auto-generated method stub
        		//System.out.println("我被调用了啦");
        		int code = e.getKeyCode();
        		//输出每次按下的键盘按钮对应的code
        		//System.out.println(code);
        		//用键盘添加数字
        		//单纯输入数字,shift键没有被按下,不然就加减乘除无法被响应了
        		if(code>=48 && code<=57 && !e.isShiftDown()) {
        			sb.append((char)code);
        			//outPut();
        		}else if(code==56 && e.isShiftDown()) {
        			sb.append("*");
        			//outPut();
        		}else if(code==47 && !e.isShiftDown()) {
        			sb.append("/");
        		}else if(code==8) {//Backspace键
        			//删除最后的一个字符
        			sb.deleteCharAt(sb.length()-1);
        		}else if(code==53 && e.isShiftDown()) {
        			sb.append("%");
        		}else if(code==61 && e.isShiftDown()) {
        			sb.append("+");
        		}else if(code==61 && !e.isShiftDown()) {//"="
        			//计算结果
        			result();
        		}else if(code==45 && !e.isShiftDown()) {
        			sb.append("-");
        		}else if(code==46 && !e.isShiftDown()) {
        			sb.append(".");
        		}else if(code==10) {//Enter键
        			//计算结果
        			result();
        		}
        		//每次键盘输入之后都要更新,所以干脆就直接放判断最后
        		outPut();
        		//"="和"Enter"键
        		if(code==61 && !e.isShiftDown()||code==10) {
        			//就是把[0,length)的内容删除即可
        			sb.delete(0, sb.length());//结果出来之后就是重新输入计算下一个
        		}
        	}
        });
	}
	//重写鼠标点击事件
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		JButton button =(JButton)e.getSource();//获得触发此次动作事件的按钮对象
		String buttonName =e.getActionCommand();//获得触发此次动作事件的按钮的标签文本
		
	
		if(buttonName.equals("X")) {
			//没有字符串之后就不能删除了
			if(sb.length()!=0) {
				sb.deleteCharAt(sb.length()-1);
				//textField.setText(output);//删除之后还需要立即显示一次,不然没有反应
			}
		}else if(buttonName.equals("R")){
			//就是把[0,length)的内容删除即可
			sb.delete(0, sb.length());
			//删除之后还需要立即显示一次,不然没有反应
			//textField.setText(output);
		}else if(buttonName.equals("=")) {
			//计算结果
			result();
		}else {
			sb.append(buttonName);
			//textField.setText(output);
		}
		//反正每次响应事件之后都要更新,干脆直接放在最后
		outPut();
		//要重新使框架获得焦点,这要写呢,不写就按下按钮之后键盘就没反应了
		if(buttonName.equals("=")) {
			//就是把[0,length)的内容删除即可
			sb.delete(0, sb.length());//结果出来之后就是重新输入计算下一个
		}
		this.requestFocus();
	}
	//记录每次将输出的字符串
	public void outPut() {
		output="";
		for(int i=0;i<sb.length();i++) {
		//这我可能知道原因了,字符串"A"和'A'不一样
			output= output+map.get(String.valueOf(sb.charAt(i)));
		}
		//每次更新都要输出,我直接写到方法里面算了
		textField.setText(output);
	}
	//计算每次的结果
	public void result() {
		
		//对应关系
		//**--->A  ln--->N  lg--->G  sin--->S   cos--->C
		//tan--->T  PI--->P  //--->B  /``--->D
		//计算是按照优先级来的
		//PI不算运算,直接填进去吧
		//也不行,本来就是用一个符号来表示,这突然变成一长串数字,那还是运算的时候展开吧
		//展开PI
		try {
			pi();
			//ln,lg,sin,cos,tan,开根号的运算
			special();
			//乘方运算
			power();
			//乘除,整除,求余运算
			multiplyDivide();
			//加减计算
			addAndSubtract();
		}catch(Exception e) {
			//弹出警告的弹窗
			warning();
		}finally {
			System.out.println("今天又是元气满满的一天");
		}
	}
	//展开PI
	public void pi() {
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='P') {
				double res=Math.PI;
				String resString=res+"";
				//更新字符串
				sb=sb.replace(i, i+1, resString);
				i=resString.length()-1;
				continue;
			}
		}
	}
	//ln,lg,sin,cos,tan,开根号的运算
	public void special() {
		//都是用右边一个操作数的运算
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='N'||sb.charAt(i)=='G'||
					sb.charAt(i)=='S'||sb.charAt(i)=='C'||
					sb.charAt(i)=='T'||sb.charAt(i)=='D') {
				double num=0;
				int len=0;//记录字符串长度,之后还要进行字符串的替换呢
				//只需要应该一边的数字即可
				for(int j=i+1;j<sb.length();j++) {
					//是j不是i,咋又错在这里了
					if(sb.charAt(j)=='*'||sb.charAt(j)=='/'||
							sb.charAt(j)=='%'||sb.charAt(j)=='B'||
							sb.charAt(j)=='+'||sb.charAt(j)=='-'||
							sb.charAt(j)=='A'||
							sb.charAt(j)=='N'||sb.charAt(j)=='G'||
							sb.charAt(j)=='S'||sb.charAt(j)=='C'||
							sb.charAt(j)=='T'||sb.charAt(j)=='D') {
						String s1=sb.substring(i+1,j);
						num=Double.parseDouble(s1);
						len=s1.length();
						break;
					}
					//找到最右边咯,中间没有运算符那也要停止了
					if(j==sb.length()-1) {
						//这边是到j+1哈,找错误找了半天
						//如果右边是一位的数字,就会导致运算是数是空
						//如果右边是多位的数字,那么最右边的数不会参与运算,所以需要[i+1,j+1)
						String s1=sb.substring(i+1,j+1);
						num=Double.parseDouble(s1);
						len=s1.length();
						break;
					}
				}
				//进行运算
				//ln运算
				if(sb.charAt(i)=='N') {
					double res=Math.log(num);
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//lg运算
				if(sb.charAt(i)=='G') {
					//换底公式
					double res=Math.log(num)/Math.log(10);
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//sin运算
				if(sb.charAt(i)=='S') {
					//还是采用角度制吧,弧度制取值用PI越界了,如果要除的话要加入括号的机制
					//偷懒一下就用角度值吧,不用加入括号
					double res=Math.sin(Math.toRadians(num));
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//cos运算
				if(sb.charAt(i)=='C') {
					//还是采用角度制吧,弧度制取值用PI越界了,如果要除的话要加入括号的机制
					//偷懒一下就用角度值吧,不用加入括号
					double res=Math.cos(Math.toRadians(num));
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//tan运算
				if(sb.charAt(i)=='T') {
					//还是采用角度制吧,弧度制取值用PI越界了,如果要除的话要加入括号的机制
					//偷懒一下就用角度值吧,不用加入括号
					double res=Math.tan(Math.toRadians(num));
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
				//开根号运算
				if(sb.charAt(i)=='D') {
					double res=Math.sqrt(num);
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i, i+len+1, resString);
					i=resString.length()-1;
					continue;
				}
			}
		}
	}
	//乘方运算
	public void power(){
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='A') {
				double num1=0,num2=0;
				int len1=0,len2=0;//记录字符串长度,之后还要进行字符串的替换呢
				for(int j=i-1;j>=0;j--) {
					//得到第一个操作数,遇到加减乘除就停止了,相当于分隔了操作数
					if(sb.charAt(j)=='*'||sb.charAt(j)=='/'||
							sb.charAt(j)=='%'||sb.charAt(j)=='B'||
							sb.charAt(j)=='+'||sb.charAt(j)=='-') {
						String s1=sb.substring(j+1,i);
						num1=Double.parseDouble(s1);
						len1=s1.length();
						break;
					}
					//找到边界了,只能停止了咯
					if(j==0) {
						String s1=sb.substring(j,i);
						num1=Double.parseDouble(s1);
						len1=s1.length();
						break;
					}
				}
				//往右边找第二个操作数,第二个操作数的话遇到乘除也需要提前终止,第一个不需要
				//因为如果第一个操作数有乘除这种符号,就已经提前终止了,只有第二个操作数才需要考虑
				for(int j=i+1;j<sb.length();j++) {
					if(sb.charAt(j)=='*'||sb.charAt(j)=='/'||
							sb.charAt(j)=='%'||sb.charAt(j)=='B'||
							sb.charAt(j)=='+'||sb.charAt(j)=='-'||sb.charAt(j)=='A') {
						String s1=sb.substring(i+1,j);
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
					//找到最右边咯,中间没有运算符那也要停止了
					if(j==sb.length()-1) {
						//这边是到j+1哈,找错误找了半天
						//如果右边是一位的数字,就会导致运算是数是空
						//如果右边是多位的数字,那么最右边的数不会参与运算,所以需要[i+1,j+1)
						String s1=sb.substring(i+1,j+1);
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
				}
				//进行运算
				double res=Math.pow(num1, num2);
				String resString=res+"";
				//更新字符串
				sb=sb.replace(i-len1, i+len2+1, resString);
				i=i-len1-1+resString.length();
				continue;
			}
		}
	}
	//乘除,整除,求余运算
	public void multiplyDivide() {
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='*'||sb.charAt(i)=='/'||
					sb.charAt(i)=='%'||sb.charAt(i)=='B') {
				double num1=0,num2=0;
				int len1=0,len2=0;//记录字符串长度,之后还要进行字符串的替换呢
				for(int j=i-1;j>=0;j--) {
					//得到第一个操作数,遇到加减就停止了,相当于分隔了操作数
					if(sb.charAt(j)=='+'||sb.charAt(j)=='-') {
						String s1=sb.substring(j+1,i);
						num1=Double.parseDouble(s1);
						len1=s1.length();
						break;
					}
					//找到边界了,只能停止了咯
					if(j==0) {
						String s1=sb.substring(j,i);
						num1=Double.parseDouble(s1);
						len1=s1.length();
						break;
					}
				}
				//往右边找第二个操作数,第二个操作数的话遇到乘除也需要提前终止,第一个不需要
				//因为如果第一个操作数有乘除这种符号,就已经提前终止了,只有第二个操作数才需要考虑
				for(int j=i+1;j<sb.length();j++) {
					if(sb.charAt(j)=='*'||sb.charAt(j)=='/'||
							sb.charAt(j)=='%'||sb.charAt(j)=='B'||
							sb.charAt(j)=='+'||sb.charAt(j)=='-') {
						String s1=sb.substring(i+1,j);
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
					//找到最右边咯,中间没有运算符那也要停止了
					if(j==sb.length()-1) {
						//这边是到j+1哈,找错误找了半天
						//如果右边是一位的数字,就会导致运算是数是空
						//如果右边是多位的数字,那么最右边的数不会参与运算,所以需要[i+1,j+1)
						String s1=sb.substring(i+1,j+1);
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
				}
				//进行运算
				if(sb.charAt(i)=='*') {
					double res=num1*num2;
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i-len1, i+len2+1, resString);
					i=i-len1-1+resString.length();
					continue;
				}
				if(sb.charAt(i)=='/') {
					//除数不能为0,有异常抛出的弹窗了,就去掉这个了
					/*if(Math.abs(num2)<=1e-6) {
						System.out.println("输出警告");
						continue;
					}*/
					double res=num1/num2;
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i-len1, i+len2+1, resString);
					i=i-len1-1+resString.length();
					continue;
				}
				if(sb.charAt(i)=='%') {
					//整数才能求余,第二个操作数也不能为0
					/*if(Math.abs(num2)<=1e-6) {
						System.out.println("输出警告");
						continue;
					}*/
					//是求余%
					double res=(int)num1%(int)num2;
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i-len1, i+len2+1, resString);
					i=i-len1-1+resString.length();
					continue;
				}
				if(sb.charAt(i)=='B') {
					//整数的运算
					//除数不能为0
					/*if(Math.abs(num2)<=1e-6) {
						System.out.println("输出警告");
						continue;
					}*/
					double res=(int)num1/(int)num2;
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i-len1, i+len2+1, resString);
					i=i-len1-1+resString.length();
					continue;
				}
			}
		}
	}
	//加减运算
	public void addAndSubtract() {
		for(int i=0;i<sb.length();i++) {
			if(sb.charAt(i)=='+'||sb.charAt(i)=='-') {
				//运算符两边的操作数
				double num1=0,num2=0;
				//记录两个操作数的字符串长度
				int len1=0,len2=0;
				//寻找第一个操作数
				for(int j=i-1;j>=0;j--) {
					if(j==0) {
						String s1=sb.substring(j,i);
						//得到第一个操作数
						num1=Double.parseDouble(s1);
						len1=s1.length();
						break;
					}
				}
				for(int j=i+1;j<sb.length();j++) {
					if(sb.charAt(j)=='+'||sb.charAt(j)=='-') {
						String s1=sb.substring(i+1,j);
						//得到第二个操作数
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
					if(j==sb.length()-1) {
						String s1=sb.substring(i+1,j+1);
						num2=Double.parseDouble(s1);
						len2=s1.length();
						break;
					}
				}
				//进行加运算
				if(sb.charAt(i)=='+') {
					double res=num1+num2;
					//String s2=sb.substring(i-len1,i+len2+1);
					//String s3=res+ "";
					//sb=sb.replace(s2, s3);
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i-len1, i+len2+1, resString);
					
					i=i-len1-1+resString.length();
					continue;
				}
				//进行减运算
				if(sb.charAt(i)=='-') {
					double res=num1-num2;
					String resString=res+"";
					//更新字符串
					sb=sb.replace(i-len1, i+len2+1, resString);
					i=i-len1-1+resString.length();
					continue;
				}
			}
		}
	}
	//警告,输入不合法的时候弹出
	public void warning() {
		JDialog jDialog=new JDialog();//创建弹窗对象
		jDialog.setTitle("警告");//设置弹窗标题,和Frame差不多,可能还要通过标签来提示
		jDialog.setSize(500,600);//设置弹窗的大小
		jDialog.setAlwaysOnTop(true);//让弹窗置顶
		jDialog.setLocationRelativeTo(null);//让弹窗居中
		jDialog.setModal(true);//弹窗不关闭则无法操作下面的界面
		
		//设置字体的类型,加粗,和大小
		warningLabel.setFont(new Font("Microsoft YaHei",Font.BOLD,30));
		//输出警告提示符
		warningLabel.setText("就是你小子在搞乱的是吧!!!");
		//标签的位置和大小
		warningLabel.setBounds(60,180,500,100);
		
		//这个也要取消布局管理器才行
		jDialog.getContentPane().setLayout(null);
		//往弹窗中添加标签
		jDialog.getContentPane().add(warningLabel);
		jDialog.setVisible(true);//让弹窗显示出来
		
	}
}

 要約:

長い時間がかかりましたが、今ではとても満足しています。JAVA 言語を勉強したばかりなので、よくわからないこともたくさんあります。間違いがあればご指摘いただけると幸いです。 。実際、電卓関数の記述には多くの関数を追加したり、Math.E を追加して他の計算を実行したりすることもでき、自分のニーズに応じて記述することができます。これを書いているときの私の気持ちは、ハッシュ テーブル、例外スロー、コントロールについて学んだすべてを活用したということです。それとそれが実現したい機能については比較的明確に理解しています。単純そうに見えますが、多くの点で行き詰まりました。原因を分析するためにあらゆる場所の情報を検索しました。少し大雑把ではありますが、独自の要素もいくつか追加しました。Backspace キーと Enter キーを押すと、対応する応答もありました。これも苦労の結果です。 . 未来がますます良くなることを願っています。

6月14日 ボタンに色を追加

これをどのように行うかによって異なります。パターンがある場合はループを使用できますが、そうでない場合は 1 つずつ調整する必要があります。これを initModule メソッド。これは、コンポーネント情報を設計するために特別に設計されたメソッドです。 (以下はデモンストレーションケースです)

buttons[0][0].setBackground(Color.red);//给第一个按钮添加红色背景的按钮

6月15日、ボタンのフォントサイズを調整しました。

ボタンを作成する際はフォントを統一して設定してください。元のプログラムへの変更は次のとおりです。

 //初始化按钮对象
 for(int row=0;row<names.length;row++) {
     for(int col=0;col<names[row].length;col++) {
        buttons[row][col]=new JButton(names[row][col]);//创建按钮
        //设置字体的类型,是否加粗和字体的大小
        buttons[row][col].setFont(new Font("Microsoft YaHei",Font.BOLD,20));
      }
 }

 

おすすめ

転載: blog.csdn.net/weixin_64066303/article/details/130383385