简体   繁体   中英

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

在此处输入图片说明

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();
}

}

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);
    }
}

This is the enum that I was talking about. Note that if you change the enum, and for instance add another temperature scale element, the program will automatically include it in the GUI and in the calculations. God I love Java and OOP.

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;
    }

}

Always consider posting an MCVE . For example you layout can be simplified and demonstrated with :

import java.awt.BorderLayout;
import java.awt.Label;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class TemperatureConversion extends JFrame{

    JPanel pnlFromRadioButton, pnlToRadioButton, pnlFromTemp, pnlButton;

    // constructor
    public TemperatureConversion(){

        pnlFromRadioButton = new JPanel();
        pnlFromRadioButton.add(new Label("From Panel"));

        pnlToRadioButton = new JPanel();
        pnlToRadioButton.add(new Label("To Panel"));

        pnlButton = new JPanel();
        pnlButton.add(new Label("Buttons Panel"));

        // 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);
    }

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

Suppose you want to an "Enter Temperature: [ ]" label to show in a different "line" under From buttons, your constructor will change to :

    public TemperatureConversion(){

        //set a layout manger. You could use grid layout
        //GridLayout gridLayout = new GridLayout(4, 1);
        //Or BoxLayout
        BoxLayout boxLayout = new BoxLayout(getContentPane(), BoxLayout.Y_AXIS); // top to bottom
        setLayout(boxLayout);
        pnlFromRadioButton = new JPanel();
        pnlFromRadioButton.add(new Label("From Panel"));

        //create a panel to hold the desired label
        pnlFromTemp = new JPanel();
        pnlFromTemp.add(new JLabel("Enter Temperature: [ ]"));//add label

        pnlToRadioButton = new JPanel();
        pnlToRadioButton.add(new Label("To Panel"));

        pnlButton = new JPanel();
        pnlButton.add(new Label("Buttons Panel"));

        // add panels to the frame
        //the panel will show in the order added
        add(pnlFromRadioButton);
        add(pnlFromTemp);
        add(pnlToRadioButton);
        add(pnlButton);

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

Sorry I am new to forums and am not familiar with posting etiquette for codes @c0der. But using GridLayout solved my problem and I want to show you what I did, it is a big mess but here it is. Here is my bizarre code but don't know how to reduce it any further. This is how it is suppose to look as I wanted and because now I understand what you mean by "Nest more JPanels and use layout managers" @Hovercraft Full of Eels: my temperature program

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, lblToTempbox;
  JRadioButton radFromCelsius, radFromFahrenheit, radFromKelvin;
  JRadioButton radToCelsius, radToFahrenheit, radToKelvin;
  JPanel pnlFromRadioButton, pnlToRadioButton, pnlFrom, pnlTo, pnlButton;
  JPanel pnlEnterTemp, pnlComparableTemp;
  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: ");
    pnlFrom = 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);
    pnlTo = new JPanel();
    pnlEnterTemp = new JPanel();
    pnlComparableTemp = new JPanel();
    pnlFromRadioButton = new JPanel();
    pnlToRadioButton = new JPanel();

    // 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);

    pnlFrom.setLayout(new GridLayout(2, 1));
    pnlFrom.add(pnlFromRadioButton);
    pnlFrom.add(pnlEnterTemp);

    pnlTo.setLayout(new GridLayout(2, 1));
    pnlTo.add(pnlToRadioButton);
    pnlTo.add(pnlComparableTemp);


    // decorate the panel
    pnlFrom.setBorder(BorderFactory.createTitledBorder("From"));
    pnlTo.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
    pnlEnterTemp.add(lblFromTemp);
    pnlEnterTemp.add(txtFromTemp);
    pnlComparableTemp.add(lblToTemp);
    txtToTemp.setEditable(false);
    pnlComparableTemp.add(txtToTemp);

    // add panels to the frame
    add(pnlFrom, BorderLayout.NORTH);
    add(pnlTo, 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() && radToFahrenheit.isSelected()) {
          int strInput = Integer.parseInt(txtFromTemp.getText());
          int celsius = strInput * 9 / 5 + 32;
          txtToTemp.setText(Integer.toString(celsius));
        } else if (radFromCelsius.isSelected() && radToCelsius.isSelected() ||
            radFromFahrenheit.isSelected() && radToFahrenheit.isSelected() ||
            radFromKelvin.isSelected() && radToKelvin.isSelected()) {
         txtToTemp.setText(txtFromTemp.getText());
        } else if (radToCelsius.isSelected() && radFromFahrenheit.isSelected()) {
          int strInput = Integer.parseInt(txtFromTemp.getText());
          int fahrenheit = (strInput - 32) * 5 / 9;
          txtToTemp.setText(Integer.toString(fahrenheit));
        } else if (radFromKelvin.isSelected() && radToCelsius.isSelected()) {
          double strInput = Integer.parseInt(txtFromTemp.getText());
          double celsius = strInput - 273.15;
          txtToTemp.setText(Double.toString(celsius));
        } else if (radFromKelvin.isSelected() && radToFahrenheit.isSelected()) {
          double strInput = Integer.parseInt(txtFromTemp.getText());
          double fahrenheit = strInput - 459.67;
          txtToTemp.setText(Double.toString(fahrenheit));
        } else if (radFromCelsius.isSelected() && radToKelvin.isSelected()) {
          double strInput = Integer.parseInt(txtFromTemp.getText());
          double celsius = strInput + 273.15;
          txtToTemp.setText(Double.toString(celsius));
        } else if (radFromFahrenheit.isSelected() && radToKelvin.isSelected()) {
          double strInput = Integer.parseInt(txtFromTemp.getText());
          double fahrenheit = strInput + 255.37;
          txtToTemp.setText(Double.toString(fahrenheit));
        }
      } else if (e.getSource() == btnExit) {
        System.exit(0);
      }
    }
  }

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

By the way @Hovercraft Full Of Eels, your solution is way more efficient and advanced than my level of thinking. I am newbie to programming in general so bear with me on my messy code and organization lol. I have barely dipped my feet into OOP. I do have a sense of how you used enum for TempScale and I thank you for your suggestion. I will keep these in my notes as references.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM