Today is my first time working with GUI, so I'm really interested in the best ways of handling various events to get the best habits from the jump. Most of the GUI-related code for this project was generated by Netbeans's layout manager, although I tried to rip out as many of the meta tags that I could, did imports where it helped cut down on code, and put the heavily auto-generated code at the bottom.
My biggest question is with the tempsComboBoxItemStateChanged
method. Is there a better way of having the JComboBox
change the program around? Right now I have a separate "logic class" handle everything, and this just creates a brand new object initialized with the updated type it'll be converting from.
Also, is there a better way of having multiple events cause the same action than factoring out and re-using a standalone method? When the user hits Enter on the textbox or button, or clicks the Convert button, I use the convertTemp
method so I don't have duplicate code. It seems like there must be a better way.
TempConverterGUI.java:
import java.awt.*;
import java.awt.event.*;
import java.util.Scanner;
import javax.swing.*;
public class TempConverterGUI extends JFrame {
private TempConverter converter;
public TempConverterGUI() {
converter = new TempConverter(TempConverter.TEMP_TYPE.Celsius);
initComponents();
}
private void convertButtonActionPerformed(ActionEvent evt) {
convertTemp();
}
private void tempTextFieldMouseClicked(MouseEvent evt) {
tempTextField.setText("");
}
private void tempTextFieldKeyReleased(KeyEvent evt) {
if (evt.getKeyCode() == KeyEvent.VK_ENTER) {
convertTemp();
}
}
private void convertButtonKeyReleased(KeyEvent evt) {
if (evt.getKeyCode() == KeyEvent.VK_ENTER) {
convertTemp();
}
}
private void tempsComboBoxItemStateChanged(ItemEvent evt) {
String tempStr = tempsComboBox.getSelectedItem().toString();
tempTextField.setText("Temperature");
if (tempStr.equals("Convert Celsius to Fahrenheit")) {
converter = new TempConverter(TempConverter.TEMP_TYPE.Celsius);
}
else if (tempStr.equals("Convert Fahrenheit to Celsius")) {
converter = new TempConverter(TempConverter.TEMP_TYPE.Fahrenheit);
}
else {
throw new TempConverter.TempTypeDoesntExistException("Temperature type from combo box isn't supported.");
}
convertFromLabel.setText(converter.fromTempTypeStr());
convertToLabel.setText(converter.toTempTypeStr());
tempTextField.setToolTipText("Enter a temperature in degrees " + converter.fromTempTypeStr());
}
private void convertTemp() {
double fromTemp = 0.0;
int toTemp = 0;
boolean validInput = false;
// Parse degrees Celsius asa double and convert to Fahrenheit.
try {
fromTemp = new Scanner(tempTextField.getText()).nextDouble();
validInput = true;
}
catch (java.util.InputMismatchException e) {
System.out.println("**ERROR**: Entered temperature isn't valid.");
}
catch (java.util.NoSuchElementException e) {
System.out.println("**ERROR**: No temperature entered.");
}
if (validInput) {
toTemp = converter.convertTemp(fromTemp);
convertToLabel.setText(toTemp + " " + converter.toTempTypeStr());
}
else {
convertToLabel.setText(converter.toTempTypeStr());
}
pack();
}
/**
* This method is called from within the constructor to initialize the Netbeans form.
*/
private void initComponents() {
convertFromLabel = new JLabel();
convertToLabel = new JLabel();
convertButton = new JButton();
tempTextField = new JTextField();
tempsComboBox = new JComboBox();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setTitle("Celsius Converter");
convertFromLabel.setLabelFor(convertFromLabel);
convertFromLabel.setText("Celsius");
convertToLabel.setText("Fahrenheit");
convertButton.setText("Convert");
convertButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
convertButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
convertButtonActionPerformed(evt);
}
});
convertButton.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent evt) {
convertButtonKeyReleased(evt);
}
});
tempTextField.setText("Temperature");
tempTextField.setToolTipText("Enter a temperature in degrees Celsius");
tempTextField.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
tempTextFieldMouseClicked(evt);
}
});
tempTextField.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent evt) {
tempTextFieldKeyReleased(evt);
}
});
tempsComboBox.setMaximumRowCount(2);
tempsComboBox.setModel(new DefaultComboBoxModel(new String[] { "Convert Celsius to Fahrenheit", "Convert Fahrenheit to Celsius" }));
tempsComboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
tempsComboBoxItemStateChanged(evt);
}
});
GroupLayout layout = new GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(convertButton)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(convertToLabel)
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(tempTextField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(convertFromLabel))
.addComponent(tempsComboBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
);
layout.linkSize(SwingConstants.HORIZONTAL, new Component[] {convertButton, tempTextField});
layout.setVerticalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addComponent(tempsComboBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(tempTextField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(convertFromLabel))
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(convertButton)
.addComponent(convertToLabel))
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}
/**
* @param args Command-line arguments aren't currently supported
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (UIManager.LookAndFeelInfo info
: UIManager.getInstalledLookAndFeels())
{
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
| UnsupportedLookAndFeelException ex)
{
java.util.logging.Logger.getLogger(TempConverterGUI.class.getName())
.log(java.util.logging.Level.SEVERE, null, ex);
}
/* Create and display the form */
EventQueue.invokeLater(() -> {
new TempConverterGUI().setVisible(true);
});
}
// Variables declaration - do not modify
private JButton convertButton;
private JLabel convertFromLabel;
private JLabel convertToLabel;
private JTextField tempTextField;
private JComboBox tempsComboBox;
// End of variables declaration
}
TempConverter.java:
public class TempConverter {
public static enum TEMP_TYPE {
Celsius, Fahrenheit;
}
private final static TEMP_TYPE DEFAULT_TEMP_TYPE = TEMP_TYPE.Celsius;
private final TEMP_TYPE convertingFrom, convertingTo;
public TempConverter(TEMP_TYPE convertFrom) {
convertingFrom = convertFrom;
if (convertFrom == TEMP_TYPE.Celsius) {
convertingTo = TEMP_TYPE.Fahrenheit;
}
else if (convertFrom == TEMP_TYPE.Fahrenheit) {
convertingTo = TEMP_TYPE.Celsius;
}
else {
convertingTo = DEFAULT_TEMP_TYPE;
}
}
public int convertTemp(double fromTemp) {
int toTemp = 0;
if (convertingFrom == TEMP_TYPE.Fahrenheit) {
toTemp = (int)(Math.round((fromTemp - 32) * (5.0 / 9.0)));
}
else if (convertingFrom == TEMP_TYPE.Celsius) {
toTemp = (int)(Math.round(fromTemp * 1.8 + 32));
}
else {
throw new TempTypeDoesntExistException("Temperature type isn't supported.");
}
return toTemp;
}
public TEMP_TYPE fromTempType() {
return convertingFrom;
}
public TEMP_TYPE toTempType() {
return convertingTo;
}
public String fromTempTypeStr() {
return convertingFrom.toString();
}
public String toTempTypeStr() {
return convertingTo.toString();
}
public static class TempTypeDoesntExistException extends IndexOutOfBoundsException {
public TempTypeDoesntExistException() { }
public TempTypeDoesntExistException(String message) {
super(message);
}
}
}