Building a Calculator Based On Java Swing
Introduction
In the digital age, graphical user interfaces (GUIs) are essential. Java Swing, a prominent framework, facilitates interactive and visually appealing applications. A fundamental and instructive example is the web-based calculator. Building it from scratch enhances GUI development and highlights software engineering principles. This article explores Java Swing, emphasizing its significance in creating a functional web-based calculator while briefly addressing software engineering practices for code maintainability and scalability. It offers insights for both novice and experienced developers, bridging Java Swing GUI development and software engineering.
Information Table
内容 | 链接 |
---|---|
课程班级链接 | https://bbs.csdn.net/forums/ssynkqtd-04 |
本次作业要求链接 | https://bbs.csdn.net/topics/617332156 |
本次作业目标 | 可视化计算器 |
梅努斯(MU)学号 和 福州大学(FZU)学号 | 21144257(MU)/832102128(FZU) |
Link to Github: https://github.com/Saiph77/Software-Enginer
Project Process
PSP Form
Personal Software Process Stages | Estimated Time (minutes) | Actual Time (minutes) |
---|---|---|
Planning | ||
• Estimate | 60 | 60 |
Development | ||
• Analysis | 30 | 60 |
• Design Spec | 30 | 30 |
• Design Review | 30 | 30 |
• Coding Standard | 15 | 15 |
• Design | 60 | 120 |
• Coding | 90 | 120 |
• Code Review | 30 | 30 |
• Test | 30 | 30 |
Reporting | ||
• Test Report | 15 | 15 |
• Size Measurement | 15 | 15 |
• Postmortem & Process Improvement Plan | 60 | 60 |
Sum | 465 | 585 |
Description of Problem-Solving Ideas
Layout Issues
When developing user interface applications with Java Swing, you may encounter challenges in arranging and sizing Swing components, especially in complex layouts.
Solution: Utilize layout managers such as BorderLayout, FlowLayout, and GridLayout to automate component positioning. Choose an appropriate layout manager that suits your specific UI design requirements.
Thread Safety Concerns:
Swing components should be accessed and manipulated on the Event Dispatch Thread (EDT). Modifying UI components on non-EDT threads can lead to unpredictable issues.
Solution: Ensure that UI operations are executed on the EDT using methods like SwingUtilities.invokeLater() or SwingUtilities.invokeAndWait() to maintain thread safety.
Performance Problems:
Complex Swing interfaces can result in performance degradation, leading to slower responsiveness or increased memory usage.
Solution: Implement Swing’s lightweight components, reduce unnecessary rendering operations, and apply techniques like double buffering to enhance performance.
Cross-Platform Look and Feel:
Swing interfaces may look different on various platforms, causing UI inconsistencies across different operating systems.
Solution: Select and set a Swing Look and Feel (L&F) manager to maintain a consistent appearance across platforms. Options include Metal, Nimbus, and others.
Event Handling Challenges:
Managing user input and events can become complex, especially when dealing with multiple components and interactions.
Solution: Use appropriate design patterns such as the Observer pattern to manage and handle events effectively. Break down related code into smaller, reusable methods and classes to improve code readability and maintainability.
Focus Management Issues:
Managing the focus control within your application, especially in scenarios with multiple components, can be challenging.
Solution: Use methods like requestFocus() or employ FocusTraversalPolicy to define the focus traversal order for components, ensuring an organized focus management approach.
Custom Drawing Challenges:
If you need to perform custom drawing on Swing components, you may need to address drawing logic and performance optimization.
Solution: Extend Swing components and override the paintComponent() method for custom drawing. Implement double buffering and other performance-enhancing techniques to achieve smooth custom rendering.
Design and Implementation Process
Design
The design of the calculator focused on creating a clean and user-friendly interface.
Java Swing is well-suited for building basic calculator graphical user interfaces (GUIs) due to its cross-platform compatibility, user-friendliness, built-in layout managers, event handling capabilities, extensive documentation, and scalability for more advanced GUI applications.
flowchart for Java Swing code:
+-------------------+
| Start Program |
+-------------------+
|
v
+-------------------+
| Create JFrame |
+-------------------+
|
v
+-------------------+
| Create Components |
+-------------------+
|
v
+-------------------+
| Set Layout Manager |
+-------------------+
|
v
+-------------------+
| Add Event Listeners |
+-------------------+
|
v
+-------------------+
| Implement Logic |
+-------------------+
|
v
+-------------------+
| Display JFrame |
+-------------------+
|
v
+-------------------+
| End Program |
+-------------------+
flowchart for calculator:
Code Description
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
class Calculator extends JFrame {
private JTextField textfield;
private boolean number = true;
private String equalOp = "=";
private CalculatorOp op = new CalculatorOp();
private final Font BIGGER_FONT = new Font("monspaced", Font.PLAIN, 20);
public Calculator() {
// Create a textfield for displaying input and results
textfield = new JTextField("", 12);
textfield.setHorizontalAlignment(JTextField.RIGHT);
textfield.setFont(BIGGER_FONT);
// Create an ActionListener for handling number button clicks
ActionListener numberListener = new NumberListener();
// Define the order of buttons for numbers and a space
String buttonOrder = "1234567890 ";
// Create a JPanel for the number buttons
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(4, 4, 4, 4));
// Loop through the buttonOrder string to create buttons
for (int i = 0; i < buttonOrder.length(); i++) {
String key = buttonOrder.substring(i, i + 1);
if (key.equals(" ")) {
buttonPanel.add(new JLabel(""));
} else {
JButton button = new JButton(key);
button.addActionListener(numberListener);
button.setFont(BIGGER_FONT);
buttonPanel.add(button);
}
}
// Create an ActionListener for handling operator button clicks
ActionListener operatorListener = new OperatorListener();
// Create a JPanel for the operator buttons
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(4, 4, 4, 4));
// Define the order of operator buttons
String[] opOrder = {"+", "-", "*", "/", "=", "C", "sin", "cos", "log"};
// Loop through the opOrder array to create operator buttons
for (int i = 0; i < opOrder.length; i++) {
JButton button = new JButton(opOrder[i]);
button.addActionListener(operatorListener);
button.setFont(BIGGER_FONT);
panel.add(button);
}
// Create a main JPanel to organize the components
JPanel pan = new JPanel();
pan.setLayout(new BorderLayout(4, 4));
// Add the textfield to the top of the main panel
pan.add(textfield, BorderLayout.NORTH);
// Add the number buttons panel to the center of the main panel
pan.add(buttonPanel, BorderLayout.CENTER);
// Add the operator buttons panel to the right of the main panel
pan.add(panel, BorderLayout.EAST);
// Set the main panel as the content pane of the calculator frame
this.setContentPane(pan);
// Set frame properties
this.pack();
this.setTitle("Calculator");
this.setResizable(false);
}
private void action() {
// Set the "number" flag to true, indicating that a number input is expected.
number = true;
// Clear the textfield.
textfield.setText("");
// Set the "equalOp" variable to "=" to prepare for a new operation.
equalOp = "=";
// Reset the operator object's total value.
op.setTotal("");
}
class OperatorListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
// Get the current text from the textfield.
String displayText = textfield.getText();
// Check if the clicked button is the "sin" operator.
if (e.getActionCommand().equals("sin")) {
// Calculate the sine of the input value and display it.
textfield.setText("" + Math.sin(Double.valueOf(displayText).doubleValue()));
} else if (e.getActionCommand().equals("cos")) {
// Calculate the cosine of the input value and display it.
textfield.setText("" + Math.cos(Double.valueOf(displayText).doubleValue()));
} else if (e.getActionCommand().equals("log")) {
// Calculate the natural logarithm of the input value and display it.
textfield.setText("" + Math.log(Double.valueOf(displayText).doubleValue()));
} else if (e.getActionCommand().equals("C")) {
// Clear the textfield when the "C" (Clear) button is clicked.
textfield.setText("");
} else {
if (number) {
// If a number is expected, perform necessary actions and clear the textfield.
action();
textfield.setText("");
} else {
number = true;
// Handle different operators based on the previous operator ("equalOp").
if (equalOp.equals("=")) {
op.setTotal(displayText);
} else if (equalOp.equals("+")) {
op.add(displayText);
} else if (equalOp.equals("-")) {
op.subtract(displayText);
} else if (equalOp.equals("*")) {
op.multiply(displayText);
} else if (equalOp.equals("/")) {
op.divide(displayText);
}
// Display the result of the operation in the textfield.
textfield.setText("" + op.getTotalString());
// Update the "equalOp" variable with the current operator.
equalOp = e.getActionCommand();
}
}
}
}
class NumberListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
// Get the digit (button label) that triggered the event.
String digit = event.getActionCommand();
// If a number is expected, set the textfield to the digit and mark that a number has been entered.
if (number) {
textfield.setText(digit);
number = false;
} else {
// If there is already content in the textfield, append the digit to it.
textfield.setText(textfield.getText() + digit);
}
}
}
public class CalculatorOp {
private int total;
// Set the total to the converted value of the provided string.
public void setTotal(String n) {
total = convertToNumber(n);
}
// Add the converted value of the provided string to the total.
public void add(String n) {
total += convertToNumber(n);
}
// Subtract the converted value of the provided string from the total.
public void subtract(String n) {
total -= convertToNumber(n);
}
// Multiply the total by the converted value of the provided string.
public void multiply(String n) {
total *= convertToNumber(n);
}
// Divide the total by the converted value of the provided string.
public void divide(String n) {
total /= convertToNumber(n);
}
// Convert a string to an integer.
private int convertToNumber(String n) {
return Integer.parseInt(n);
}
// Initialize the total to 0 when an instance of CalculatorOp is created.
public CalculatorOp() {
total = 0;
}
// Get the current total as a string.
public String getTotalString() {
return "" + total;
}
}
}
class SwingCalculator {
public static void main(String[] args) {
// Create a JFrame using the Calculator class, set it to be visible, and define the close operation.
JFrame frame = new Calculator();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Displaying Result Functions
软工实践作业1
The video above shows the calculator’s user interface. Users can input mathematical expressions, trigonometric functions, and perform calculations. The display area shows both input and results.
Summary
In this assignment, we successfully designed and implemented a feature-rich calculator using Java Swing components. It supports basic arithmetic operations as well as advanced functions like trigonometry and degrees-to-radians conversion. We followed a structured development process, including planning, design, coding, and testing.
Building this calculator helped solidify key Java graphical user interface (GUI) development skills. It also emphasized problem-solving abilities and the importance of effective planning and documentation in software development.
This project serves as a valuable example of creating interactive Java applications, showcasing the powerful capabilities of Java in GUI programming.