Ojouk Ojouk - 2 months ago 7
Java Question

How do I put label under radio button within a panel with Java Swing/awt

enter image description here

There is 3 panels which I created as seen in the image. The first panel is the "From" panel, second is "To" panel, and third is the buttons panel. So the question is, how can I put a new line for the "Enter Temperature: [ ]" so that it will be under neath the radio buttons? I am very new to Java swing/awt please bear with me.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import java.awt.*;

public class TemperatureConversion extends JFrame{

// component
JTextField txtFromTemp, txtToTemp;
JLabel lblFromTemp, lblToTemp;
JRadioButton radFromCelsius, radFromFahrenheit, radFromKelvin;
JRadioButton radToCelsius, radToFahrenheit, radToKelvin;
JPanel pnlFromRadioButton, pnlToRadioButton, pnlFromTemp, pnlButton;
ButtonGroup bgFrom, bgTo;
JButton btnConvert, btnExit;

// constructor
public TemperatureConversion(){
super("Temperature");

// assign objects
radFromCelsius = new JRadioButton("Celsius", true);
radFromFahrenheit = new JRadioButton("Fahrenheit");
radFromKelvin = new JRadioButton("Kelvin");
lblFromTemp = new JLabel("Enter Temperature: ");
pnlFromTemp = new JPanel();
btnConvert = new JButton("Convert");
btnExit = new JButton("Exit");
pnlButton = new JPanel();
txtFromTemp = new JTextField(3);
lblToTemp = new JLabel("Comparable Temperature: ");
txtToTemp = new JTextField(3);


// register the button to a listener
btnExit.addActionListener(new MyButtonListener());
btnConvert.addActionListener(new MyButtonListener());


// make the multiple choice exclusive but not a container
bgFrom = new ButtonGroup();
bgFrom.add(radFromCelsius);
bgFrom.add(radFromFahrenheit);
bgFrom.add(radFromKelvin);

// radio buttons
radToCelsius = new JRadioButton("Celsius");
radToFahrenheit = new JRadioButton("Fahrenheit", true);
radToKelvin = new JRadioButton("Kelvin");

// make the multiple choice exclusive
bgTo = new ButtonGroup();
bgTo.add(radToCelsius);
bgTo.add(radToFahrenheit);
bgTo.add(radToKelvin);


pnlFromRadioButton = new JPanel();
pnlToRadioButton = new JPanel();

// decorate the panel
pnlFromRadioButton.setBorder(BorderFactory.createTitledBorder("From"));
pnlToRadioButton.setBorder(BorderFactory.createTitledBorder("To"));

// add radiobutton to panel
pnlFromRadioButton.add(radFromCelsius);
pnlFromRadioButton.add(radFromFahrenheit);
pnlFromRadioButton.add(radFromKelvin);
pnlToRadioButton.add(radToCelsius);
pnlToRadioButton.add(radToFahrenheit);
pnlToRadioButton.add(radToKelvin);

// add button to panel
pnlButton.add(btnConvert);
pnlButton.add(btnExit);

// add label and txt field to panel
pnlFromRadioButton.add(lblFromTemp);
pnlFromRadioButton.add(txtFromTemp);
pnlToRadioButton.add(lblToTemp);
txtToTemp.setEditable(false);
pnlToRadioButton.add(txtToTemp);


// add panels to the frame
add(pnlFromRadioButton, BorderLayout.NORTH);
add(pnlToRadioButton, BorderLayout.CENTER);
add(pnlButton, BorderLayout.SOUTH);


setVisible(true);
setSize(400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
}


// private inner class to handle button event
private class MyButtonListener implements ActionListener {
// must override actionPerformed method
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == btnConvert) {
if (radFromCelsius.isSelected())
System.out.print("exit");
} else if (e.getSource() == btnExit) {
System.exit(0);
}
}
}


public static void main(String[] args) {
new TemperatureConversion();
}

}

Answer

Nest more JPanels and use layout managers

For instance, in the JPanel where you want two lines, give it a BoxLayout oriented along the BoxLayout.PAGE_AXIS, and then add two more JPanels to this BoxLayout-using, a top JPanel with the radio buttons and bottom JPanel with the JLabel and JTextField (or whatever else you want in it).

Side note: this would be a great place to use an enum one called TempScale that had three values: CELSIUS, FAHRENHEIT, KELVIN. You could even give the enum the formulas for conversion to and from Kelvin.

For example:

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

@SuppressWarnings("serial")
public class TempConversion2 extends JPanel {
    private ToFromPanel fromPanel = new ToFromPanel("From", true);
    private ToFromPanel toPanel = new ToFromPanel("To", false);
    private ButtonPanel buttonPanel = new ButtonPanel(fromPanel, toPanel);

    public TempConversion2() {
        setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
        add(fromPanel);
        add(toPanel);
        add(buttonPanel);
    }

    private static void createAndShowGui() {
        TempConversion2 mainPanel = new TempConversion2();

        JFrame frame = new JFrame("Temp Convert");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

@SuppressWarnings("serial")
class ButtonPanel extends JPanel {

    public ButtonPanel(ToFromPanel fromPanel, ToFromPanel toPanel) {
        add(new JButton(new ConvertAction("Convert", fromPanel, toPanel)));
        add(new JButton(new ExitAction("Exit", KeyEvent.VK_X)));
    }

}

@SuppressWarnings("serial")
class ConvertAction extends AbstractAction {
    private ToFromPanel fromPanel;
    private ToFromPanel toPanel;

    public ConvertAction(String name, ToFromPanel fromPanel, ToFromPanel toPanel) {
        super(name);
        int mnemonic = (int) name.charAt(0);
        putValue(MNEMONIC_KEY, mnemonic);
        this.fromPanel = fromPanel;
        this.toPanel = toPanel;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String text = fromPanel.getText();
        try {
            double fromTemp = Double.parseDouble(text.trim());
            TempScale fromScale = fromPanel.getTempScalesPanel().getSelectedTempScale();
            double kelvinValue = fromScale.convertToKelvin(fromTemp);

            TempScale toScale = toPanel.getTempScalesPanel().getSelectedTempScale();
            double toValue = toScale.convertFromKelvin(kelvinValue);

            String toValueString = String.format("%.2f", toValue);
            toPanel.setText(toValueString);
        } catch (NumberFormatException e1) {
            Component parentComponent = fromPanel;
            String message = "Text must be a valid number: " + text;
            String title = "Invalid Text Entered";
            int messageType = JOptionPane.ERROR_MESSAGE;
            JOptionPane.showMessageDialog(parentComponent, message, title, messageType);
            fromPanel.setText("");
        }
    }
}

@SuppressWarnings("serial")
class ExitAction extends AbstractAction {
    public ExitAction(String name, int mnemonic) {
        super(name);
        putValue(MNEMONIC_KEY, mnemonic);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        System.exit(0);
    }
}

@SuppressWarnings("serial")
class ToFromPanel extends JPanel {
    private String title;
    private TempScalesPanel tempScalesPanel = new TempScalesPanel();
    private JTextField tempTextField = new JTextField(3);

    public ToFromPanel(String title, boolean textFieldEnabled) {
        this.title = title;
        tempTextField.setFocusable(textFieldEnabled);

        JPanel bottomPanel = new JPanel();
        bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.LINE_AXIS));
        bottomPanel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
        bottomPanel.add(new JLabel("Temperature:"));
        bottomPanel.add(Box.createHorizontalStrut(8));
        bottomPanel.add(tempTextField);

        setBorder(BorderFactory.createTitledBorder(title));
        setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
        add(tempScalesPanel);
        add(bottomPanel);
    }

    public String getTitle() {
        return title;
    }

    public TempScalesPanel getTempScalesPanel() {
        return tempScalesPanel;
    }

    public String getText() {
        return tempTextField.getText();
    }

    public void setText(String text) {
        tempTextField.setText(text);
    }
}

@SuppressWarnings("serial")
class TempScalesPanel extends JPanel {
    private ButtonGroup buttonGroup = new ButtonGroup();
    private Map<ButtonModel, TempScale> buttonTempMap = new HashMap<>();

    public TempScalesPanel() {
        for (TempScale tempScale : TempScale.values()) {
            JRadioButton radioButton = new JRadioButton(tempScale.getName());
            add(radioButton);
            buttonGroup.add(radioButton);
            buttonTempMap.put(radioButton.getModel(), tempScale);
            // set first button as selected by default
            if (buttonGroup.getSelection() == null) {
                buttonGroup.setSelected(radioButton.getModel(), true);
            }
        }
    }

    public TempScale getSelectedTempScale() {
        ButtonModel model = buttonGroup.getSelection();
        return buttonTempMap.get(model);
    }
}

public enum TempScale {
    CELSIUS("Celsius", 1.0, -273.15), 
    FAHRENHEIT("Fahrenheit", 5.0 / 9.0, -459.67), 
    KELVIN("Kelvin", 1.0, 0.0);

    private TempScale(String name, double ratioToKelvin, double absZero) {
        this.name = name;
        this.ratioToKelvin = ratioToKelvin;
        this.absZero = absZero;
    }

    private String name;
    private double ratioToKelvin;
    private double absZero;

    public String getName() {
        return name;
    }

    public double getRatioToKelvin() {
        return ratioToKelvin;
    }

    public double getAbsZero() {
        return absZero;
    }

    public double convertToKelvin(double value) {
        return (value - absZero) * ratioToKelvin;
    }

    public double convertFromKelvin(double kelvinValue) {
        return (kelvinValue / ratioToKelvin) + absZero;
    }

}