Thứ Ba, 28 tháng 5, 2024

Calculator




Mục lục:

1. Code ban đầu

2.  Muốn textField sẽ hiển thị phép tính.

Ví dụ: ấn 4+2 thì khi ấn bằng textField hiển thị 4+2 = , còn display hiển thị kết quả là 6.

3. Sửa TextField hiển thị phép tính liên tiếp

Ví dụ: 2 + 3 = + 2 = + 2 = 9.0 thì nó sẽ hiển thị là 2 + 3 = 5; 5+ 2 = 7; 7+ 2 = 9.0

4. Lỗi dấu hiển thị nhiều lần

Ví dụ: 2 --- thì nó hiển thị là 2 - = 0.0 - = 0.0 - = 0.0 - trong khi tôi muốn nó hiển thị là 2-

5. Lỗi thực hiện phép tính liên tiếp

Ví dụ: Khi thực hiện xong 21.0 - 2 = 19.0, nhấn thêm phím 3 để thực hiện phép tính mới thì textField hiển thị là 21.0 - 2 = 19.03, tôi muốn textField chỉ hiển thị số 3 thôi.

6. Xử lí nút bấm √ và log


1.Code ban đầu :

package test;


import java.awt.EventQueue;

import javax.swing.JFrame;

import javax.swing.JButton;

import java.awt.BorderLayout;

import java.awt.Font;

import javax.swing.DropMode;

import javax.swing.SwingConstants;

import java.awt.event.ActionListener;

import java.awt.event.ActionEvent;

import javax.swing.JPanel;

import java.awt.GridLayout;

import javax.swing.JTextField;


public class Calculator {


private JFrame frame;

private JTextField display;


// Biến để lưu trữ giá trị phép tính

private double tempFirst = 0.0;

private String operator = "";

private boolean startNewNumber = true;

private JTextField textField;


/**

* Launch the application.

*/

public static void main(String[] args) {

EventQueue.invokeLater(new Runnable() {

public void run() {

try {

Calculator window = new Calculator();

window.frame.setVisible(true);

} catch (Exception e) {

e.printStackTrace();

}

}

});

}


/**

* Create the application.

*/

public Calculator() {

initialize();

}


/**

* Initialize the contents of the frame.

*/

private void initialize() {

frame = new JFrame();

frame.setBounds(100, 100, 400, 500);

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.getContentPane().setLayout(new BorderLayout(0, 0));

JPanel panel = new JPanel();

frame.getContentPane().add(panel, BorderLayout.NORTH);

panel.setLayout(new BorderLayout(0, 0));

display = new JTextField();

display.setHorizontalAlignment(SwingConstants.RIGHT);

display.setFont(new Font("Tahoma", Font.BOLD, 20));

display.setText("0");

panel.add(display, BorderLayout.CENTER);

display.setColumns(10);

textField = new JTextField();

panel.add(textField, BorderLayout.NORTH);

textField.setColumns(10);

JPanel panel_1 = new JPanel();

frame.getContentPane().add(panel_1, BorderLayout.CENTER);

panel_1.setLayout(new GridLayout(5, 4, 5, 5));


// Helper method to create buttons

String[] buttonLabels = {"7", "8", "9", "/",

"4", "5", "6", "*",

"1", "2", "3", "-",

"0", ".", "=", "+",

"C", "DEL"};

for (String label : buttonLabels) {

JButton button = new JButton(label);

button.setFont(new Font("Tahoma", Font.PLAIN, 20));

button.addActionListener(new ActionListener() {

@Override

public void actionPerformed(ActionEvent e) {

String cmd = e.getActionCommand();

if (cmd.matches("\\d") || cmd.equals(".")) {

if (startNewNumber) {

display.setText(cmd);

startNewNumber = false;

} else {

display.setText(display.getText() + cmd);

}

} else if (cmd.equals("C")) {

display.setText("0");

tempFirst = 0.0;

operator = "";

startNewNumber = true;

} else if (cmd.equals("DEL")) {

String currentText = display.getText();

if (currentText.length() > 0) {

display.setText(currentText.substring(0, currentText.length() - 1));

}

if (display.getText().isEmpty()) {

display.setText("0");

}

} else if (cmd.equals("=")) {

if (!operator.isEmpty()) {

double tempSecond = Double.parseDouble(display.getText());

double result = calculate(tempFirst, tempSecond, operator);

display.setText(String.valueOf(result));

tempFirst = result;

operator = "";

}

startNewNumber = true;

} else {

tempFirst = Double.parseDouble(display.getText());

operator = cmd;

startNewNumber = true;

}

}

});

panel_1.add(button);

}

}


private double calculate(double a, double b, String operator) {

switch (operator) {

case "+": return a + b;

case "-": return a - b;

case "*": return a * b;

case "/":

if (b == 0) {

return 0; // Handle division by zero

}

return a / b;

default: return 0;

}

}

}


2.  Muốn textField sẽ hiển thị phép tính.


Dưới đây là cách thực hiện:


1. Khi một số hoặc một phép tính được nhập, cập nhật textField để hiển thị phép tính hiện tại.


2. Khi kết quả được tính toán, cập nhật textField để hiển thị phép tính và kết quả.




3. Sửa TextField hiển thị phép tính liên tiếp

Dưới đây là cách thực hiện:


1. Thêm biến điều kiện newCalculation được sử dụng để xác định khi nào bắt đầu một phép toán mới.


2. Khi bắt đầu một phép toán mới sau dấu =, phép toán mới sẽ bắt đầu từ kết quả của phép toán trước đó.



4. Lỗi dấu hiển thị nhiều lần


4.1. Tại sao lại bị lỗi này?


Để hiểu rõ hơn về cách hoạt động của code này và tại sao nó lại hiển thị như vậy, chúng ta cần xem xét kỹ từng phần của mã nguồn và cách các sự kiện được xử lý. Dưới đây là giải thích từng bước của mã:

  1. Giao diện người dùng (UI):

    • display là một JTextField để hiển thị số hiện tại mà người dùng nhập.
    • textField là một JTextField khác để hiển thị lịch sử của các phép tính.
  2. Biến toàn cục:

    • tempFirst: lưu trữ số đầu tiên trong phép tính.
    • operator: lưu trữ toán tử hiện tại (ví dụ: "+", "-", "*", "/").
    • startNewNumber: đánh dấu khi nào bắt đầu nhập một số mới.
    • newCalculation: đánh dấu khi nào bắt đầu một phép tính mới.
  3. Hành vi của các nút:

    • Số và dấu chấm ("."): Khi nhấn một số hoặc dấu chấm, nếu startNewNumbertrue, nó sẽ đặt số đó vào display. Nếu không, nó sẽ nối số đó vào cuối chuỗi hiện tại.
    • "C" (Clear): Đặt lại tất cả các biến và giao diện người dùng về trạng thái ban đầu.
    • "DEL" (Delete): Xóa ký tự cuối cùng của displaytextField.
    • "=": Khi nhấn nút "=":
      • Nếu operator không trống, nó sẽ tính toán kết quả giữa tempFirst và số hiện tại trong display, sau đó hiển thị kết quả.
    • Toán tử: Khi nhấn một toán tử (ví dụ: "+", "-", "*", "/"):
      • Nếu newCalculationtrue, nó lưu giá trị hiện tại trong display vào tempFirst.
      • Nếu newCalculationfalse, nó tính toán kết quả giữa tempFirst và số hiện tại trong display, sau đó hiển thị kết quả và lưu kết quả đó vào tempFirst.

Lỗi khi nhấn "2 ---": Khi bạn nhấn "2 ---", đây là các bước mà mã thực hiện:

  1. Nhấn "2":

    • display hiển thị "2".
    • textField thêm "2".
  2. Nhấn "-" lần đầu tiên:

    • tempFirst được gán giá trị 2 (giá trị hiện tại của display).
    • operator được gán "-".
    • textField thêm " - ".
    • (*) newCalculationtrue, tempFirst được đặt là giá trị của display ("2"), operator được đặt thành "-", và textField được thêm "2 - ".
    • (*) operator được đặt thành "-", startNewNumber được đặt thành true, và newCalculation được đặt thành false.
  3. Nhấn "-" lần thứ hai:

    • tempSecond được gán giá trị 2 (giá trị hiện tại của display).
    • Tính toán kết quả: tempFirst - tempSecond = 2 - 2 = 0.
    • textField hiển thị "2 - 2 = 0.0 - ".
    • display hiển thị "0.0".
    • tempFirst được gán giá trị 0.0.
    • operator được gán "-".
    • (*) newCalculationfalse, tempSecond được đặt là giá trị của display ("2"), result được tính bằng calculate(tempFirst, tempSecond, operator):
    • (*) Phương thức calculate được gọi, thực hiện phép trừ: 2.0 - 2.0 = 0.0.
  4. Nhấn "-" lần thứ ba:

    • tempSecond được gán giá trị 0.0 (giá trị hiện tại của display).
    • Tính toán kết quả: tempFirst - tempSecond = 0.0 - 0.0 = 0.
    • textField hiển thị "2 - 2 = 0.0 - 0.0 = 0.0 - ".
    • display hiển thị "0.0".
    • tempFirst được gán giá trị 0.0.
    • operator được gán "-".

4.2. Sửa lỗi này như thế nào ?

Chúng ta sẽ thực hiện các thay đổi sau:

  1. Đảm bảo rằng phép tính chỉ được thực hiện khi có hai số (khi nhấn dấu =).
  2. Chỉ cập nhật textField khi nhấn vào các nút phép toán (chứ không phải thực hiện tính toán ngay).

Dưới đây là mã để xử lý vấn đề này:


Giải thích :

Dưới đây là chi tiết từng bước khi nhấn nút "-" hai lần liên tiếp.

Giả sử display hiện tại hiển thị "2":

Lần nhấn nút "-" đầu tiên

  1. Khi nhấn nút "-", điều kiện kiểm tra sẽ là:

    if (!startNewNumber) { if (!operator.isEmpty()) { double tempSecond = Double.parseDouble(display.getText()); double result = calculate(tempFirst, tempSecond, operator); textField.setText(textField.getText() + " = " + result); display.setText(String.valueOf(result)); tempFirst = result; } else { tempFirst = Double.parseDouble(display.getText()); } } else if (newCalculation) { tempFirst = Double.parseDouble(display.getText()); newCalculation = false; } operator = cmd; textField.setText(display.getText() + " " + cmd + " "); startNewNumber = true;
  2. Với startNewNumber ban đầu là true, newCalculation cũng là true, nên đoạn mã:

    else if (newCalculation) { tempFirst = Double.parseDouble(display.getText()); newCalculation = false; }

    sẽ được thực thi:

    • tempFirst sẽ được đặt thành giá trị của display, tức là 2.0.
    • newCalculation được đặt thành false.
  3. Sau đó, các dòng mã:

    operator = cmd; textField.setText(display.getText() + " " + cmd + " "); startNewNumber = true;

    sẽ thực thi:

    • operator được đặt thành "-".
    • textField được cập nhật thành "2 - ".
    • startNewNumber được đặt thành true.

Lần nhấn nút "-" thứ hai

1. Với startNewNumbertrue, nó không thực hiện vào khối if (!startNewNumber)else if (newCalculation). Do đó, chương trình tiếp tục vào khối else.

2. Trong khối else, operator sẽ được cập nhật và textField sẽ được cập nhật để hiển thị toán tử mới:

  1. operator = cmd; textField.setText(display.getText() + " " + cmd + " "); startNewNumber = true;
    • operator được đặt thành "-".
    • textField cập nhật thành "2 - ".
    • startNewNumber được đặt thành true.

Vậy nên, sau khi nhấn nút "-" lần thứ hai, textField sẽ hiển thị "2 - ".

5. Lỗi thực hiện phép tính liên tiếp

Để thực hiện điều này, ta cần textFielddisplay khởi động lại để bắt đầu một phép tính mới sau khi hoàn tất một phép tính trước đó. Để giải quyết vấn đề này, chúng ta cần đảm bảo rằng sau khi nhấn =, khi người dùng nhấn một phím số mới, textField sẽ bắt đầu lại từ đầu.

Chúng ta sẽ thêm một biến trạng thái khác để theo dõi xem kết quả vừa được hiển thị hay không và thiết lập lại textField khi người dùng nhập một số mới sau khi đã nhấn =. Dưới đây là các thay đổi cần thiết trong mã nguồn của bạn:

  1. Thêm một biến boolean resultDisplayed để theo dõi xem kết quả có đang được hiển thị hay không.
  2. Khi một số mới được nhập sau khi đã nhấn =, thiết lập lại textFielddisplay.



6. Xử lí nút bấm √ và log




Phần xử lí được để ngay trong code dẫn tới việc phải ấn số trước khi ấn nút.

Để chỉnh sửa lỗi này, ta sẽ thực hiện như sau:






Không có nhận xét nào:

Đăng nhận xét

code 2

  package ll; public class CalculatorModel { public double calculate ( String expression ) { return evaluateExpression (...