in this code the first three buttons appear on the text area, how can I make these buttons start from below the header? before adding the button the buttonarea started below the header, but once I added the button it appeared on the header
public Design ()
{
header = new JPanel ();
header.setBounds(0, 0, 300, 100);
header.setBackground(Color.WHITE);
header.setLayout (null);
buttonarea = new JPanel ();
buttonarea.setBounds (0,0, 300, 300);
buttonarea.setBackground(Color.BLACK);
buttonarea.setLayout(new GridLayout (6,3));
add (header);
add (buttonarea);
zero = new JButton ("0");
zero.setBackground(Color.PINK);
one = new JButton ("1");
one.setBackground(Color.PINK);
two = new JButton ("2");
two.setBackground(Color.PINK);
three = new JButton ("3");
three.setBackground(Color.PINK);
four = new JButton ("4");
four.setBackground(Color.PINK);
five = new JButton ("5");
five.setBackground(Color.PINK);
six = new JButton ("6");
six.setBackground(Color.PINK);
seven = new JButton ("7");
seven.setBackground(Color.PINK);
eight = new JButton ("8");
eight.setBackground(Color.PINK);
nine = new JButton ("9");
nine.setBackground(Color.PINK);
add = new JButton ("+");
add.setBackground(Color.PINK);
subtract = new JButton ("-");
subtract.setBackground(Color.PINK);
divide = new JButton ("*");
divide.setBackground(Color.PINK);
multiply = new JButton ("/");
multiply.setBackground(Color.PINK);
square = new JButton ("x^2");
square.setBackground(Color.PINK);
equal = new JButton ("=");
equal.setBackground(Color.PINK);
c = new JButton ("C");
c.setBackground(Color.PINK);
clear = new JButton ("delete");
clear.setBackground(Color.PINK);
dot = new JButton (".");
dot.setBackground(Color.PINK);
written = new JTextArea ();
written.setBackground(Color.WHITE);
header.add (written);
buttonarea.add (c);
buttonarea.add (clear);
buttonarea.add (equal);
buttonarea.add (zero);
buttonarea.add (one);
buttonarea.add (add);
buttonarea.add (two);
buttonarea.add (three);
buttonarea.add (subtract);
buttonarea.add (four);
buttonarea.add (five);
buttonarea.add (multiply);
buttonarea.add (six);
buttonarea.add (seven);
buttonarea.add (square);
buttonarea.add (eight);
buttonarea.add (nine);
buttonarea.add (dot);
}
While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
Use a BorderLayout for the main GUI, placing the JTextField BorderLayout.PAGE_START. Place the JButtons within a GridLayout using JPanel, and place this JPanel in the BorderLayout.CENTER position of the main GUI.
For example this GUI:
Can be made with this GUI:
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class SimpleCalc extends JPanel {
private static final String[][] BTN_TEXTS = {
{"C", "Del", "X^2", "+"},
{"7", "8", "9", "-"},
{"4", "5", "6", "*"},
{"1", "2", "3", "/"},
{"0", ".", "", "="}
};
private static final int COLS = 12;
private static final int GAP = 3;
private static final char[] NUMBER_ARRAY = "0123456789".toCharArray();
private static final List<Character> NUMBER_LIST = new ArrayList<>();
private static final float FONT_SIZE = 36f;
private JTextField display = new JTextField(COLS);
static {
for (char c : NUMBER_ARRAY) {
NUMBER_LIST.add(c);
}
}
public SimpleCalc() {
display.setFont(display.getFont().deriveFont(FONT_SIZE));
display.setFocusable(false);
int rows = BTN_TEXTS.length;
int cols = BTN_TEXTS[0].length;
JPanel buttonPanel = new JPanel(new GridLayout(rows, cols, GAP, GAP));
for (String[] btnTextRow : BTN_TEXTS) {
for (String btnText : btnTextRow) {
if (btnText.isEmpty()) {
buttonPanel.add(new JLabel());
} else {
Action action = null;
if (NUMBER_LIST.contains(btnText.charAt(0))) {
action = new NumericAction(btnText);
} else if (".".equals(btnText)) {
action = new DotAction(btnText);
} else {
action = new OperationAction(btnText);
}
JButton button = new JButton(action);
button.setFont(button.getFont().deriveFont(Font.BOLD, FONT_SIZE));
buttonPanel.add(button);
}
}
}
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setLayout(new BorderLayout(GAP, GAP));
add(display, BorderLayout.PAGE_START);
add(buttonPanel, BorderLayout.CENTER);
}
private class NumericAction extends AbstractAction {
public NumericAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
String text = display.getText();
text += e.getActionCommand();
display.setText(text);
}
}
private class DotAction extends AbstractAction {
public DotAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
String text = display.getText();
if (text.contains(".")) {
return; // only one dot allowed
}
text += e.getActionCommand();
display.setText(text);
}
}
private class OperationAction extends AbstractAction {
public OperationAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO write code for operations buttons
}
}
private static void createAndShowGui() {
SimpleCalc mainPanel = new SimpleCalc();
JFrame frame = new JFrame("SimpleCalc");
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(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
add (header);
add (buttonarea);
I'm guess you are using a JFrame which uses a BorderLayout. The above code is adding two compenents to the CENTER of the BorderLayout which is not allowed.
Instead you should specify the appropriate constraint:
add (header, BorderLayout.PAGE_NORTH);
add (buttonarea, BorderLayout.CENTER);
And if you are not using a BorderLayout on your frame then you should. Read the section from the Swing tutorial on How to Use BorderLayout for more information and examples.
Also, when creating a JTextAra you should use:
written = new JTextArea (row, columns);
to give the text area an appropriate size. In this case you can probably just add the text area directly to the frame:
//add (header, BorderLayout.PAGE_NORTH);
add (written, BorderLayout.PAGE_NORTH);
There is no need for the wrapper panel.
Related
i have 10 jcheckbox and only 5 should be selected. i already did all the coding for this one, but i don't know how to display the selected 5 into a jlabel. i tried doing it by this code:
JCheckBox check;
JPanel panel=new JPanel();
for(int i=0; i<10; i++){
check=new JCheckBox();
check.addActionListener(listener);
check.setName("Select"+i);
panel.add(check);
}
this is the listener
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
check = (JCheckBox) e.getSource();
name=check.getName();
}
};
and this is the panel where it should be displayed into jlabel
panel2=new JPanel(new GridLayout(5,1));
for(int i=0; i<5; i++){
txtVote=new JLabel(name);
panel2.add(txtVote);
}
but using this code, it doesn't display anything on the jlabel. if i change the listener into this:
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
check = (JCheckBox) e.getSource();
txtVote.setText(check.getName());
}
};
it will only display into the last label. other jlabels would be blank. please help thank you so much
EDIT
here is the code that is runnable
public class JCheckBoxtoLabel{
JCheckBox check;
String name;
JLabel txtVote;
public JCheckBoxtoLabel() {
JFrame frame = new JFrame();
JPanel panel = createPanel();
JPanel panel2 = panel2();
frame.setLayout(new GridLayout(1,2));
frame.add(panel); frame.add(panel2);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JPanel createPanel() {
JPanel panel=new JPanel(new GridLayout(10,1));
for(int i=0; i<10; i++){
check=new JCheckBox();
check.addActionListener(listener);
check.setName("Select"+i);
panel.add(check);
}
return panel;
}
private JPanel panel2(){
JPanel panel2=new JPanel(new GridLayout(5,1));
for(int i=0; i<5; i++){
txtVote=new JLabel();
txtVote.setBorder(BorderFactory.createLineBorder(Color.RED));
panel2.add(txtVote);
}
return panel2;
}
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
check = (JCheckBox) e.getSource();
txtVote.setText(check.getName());
}
};
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JCheckBoxtoLabel();
}
});
}
}
Consider changing what you're doing and displaying the text in a JList and not in JLabels. This can help you consolidate your information. You can also give your JCheckBoxes or JRadioButtons and ItemListener that only allows 5 of the buttons to be selected at a time -- unselecting the oldest one currently selected. For instance:
import java.awt.GridLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class FiveNames extends JPanel {
private static final String[] ALL_NAMES = {"Bob", "Bill", "Frank", "Helen",
"Erica", "Mickey", "Donald", "Hillary", "Michael", "Peter", "Roger"};
private static final int ALLOWED_SELECTIONS_COUNT = 5;
private DefaultListModel<String> displayListModel = new DefaultListModel<>();
private JList<String> list = new JList<>(displayListModel);
public FiveNames() {
JPanel namePanel = new JPanel(new GridLayout(0, 1, 0, 5));
RButtonItemListener rButtonListener = new RButtonItemListener();
for (String name : ALL_NAMES) {
JRadioButton rButton = new JRadioButton(name);
rButton.setActionCommand(name);
rButton.addItemListener(rButtonListener);
namePanel.add(rButton);
}
list.setVisibleRowCount(ALLOWED_SELECTIONS_COUNT);
list.setPrototypeCellValue(" ");
list.setBackground(null);
setLayout(new GridLayout(1, 0));
add(namePanel);
add(list);
}
// listener to only allow the last 5 radiobuttons to be selected
private class RButtonItemListener implements ItemListener {
private List<ButtonModel> buttonModelList = new ArrayList<>();
#Override
public void itemStateChanged(ItemEvent e) {
JRadioButton rBtn = (JRadioButton) e.getSource();
ButtonModel model = rBtn.getModel();
if (e.getStateChange() == ItemEvent.SELECTED) {
buttonModelList.add(model);
if (buttonModelList.size() > ALLOWED_SELECTIONS_COUNT) {
for (int i = 0; i < buttonModelList.size() - ALLOWED_SELECTIONS_COUNT; i++) {
ButtonModel removedModel = buttonModelList.remove(0);
removedModel.setSelected(false);
}
}
} else {
buttonModelList.remove(model);
}
displayListModel.clear();
for (ButtonModel buttonModel : buttonModelList) {
displayListModel.addElement(buttonModel.getActionCommand());
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("FiveNames");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new FiveNames());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
The problem is that txtVote is only a single Jlabel and you are trying to use it for all 5. Since the fifth jlabel was the last to be created it is the one being used. My suggestion is that you create an arraylist field and inside panel12 add each label to the arraylist. Then inside the listener it would iterate through each jlabel in the arraylist check if has text set to it, if so check the next one until it finds one with no text, then sets the text to that. The problem with this at the moment is that in your code you are never defining what happens when they uncheck the box.
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class JCheckBoxtoLabel{
JCheckBox check;
String name;
JLabel txtVote;
ArrayList<JLabel> boxLabels;
public JCheckBoxtoLabel() {
boxLabels = new ArrayList<JLabel>();
JFrame frame = new JFrame();
JPanel panel = createPanel();
JPanel panel2 = panel2();
frame.setLayout(new GridLayout(1,2));
frame.add(panel); frame.add(panel2);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JPanel createPanel() {
JPanel panel=new JPanel(new GridLayout(10,1));
for(int i=0; i<10; i++){
check=new JCheckBox();
check.addActionListener(listener);
check.setName("Select"+i);
panel.add(check);
}
return panel;
}
private JPanel panel2(){
JPanel panel2=new JPanel(new GridLayout(5,1));
for(int i=0; i<5; i++){
txtVote=new JLabel();
txtVote.setBorder(BorderFactory.createLineBorder(Color.RED));
panel2.add(txtVote);
boxLabels.add(txtVote);
}
return panel2;
}
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
check = (JCheckBox) e.getSource();
if(!check.isSelected()){
for(JLabel label: boxLabels){
if(label.getText().equals(check.getName())) label.setText("");
}
}else{
for(JLabel label: boxLabels){
if(label.getText().isEmpty()){
label.setText(check.getName());
return;
}
}
}
}
};
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JCheckBoxtoLabel();
}
});
}
}
Your variable JLabel txtVote is a single JLabel object, not an array.
In your panel2() function you assign 5 new JLabels to txtVote. Since you assign 5 in a row, it gets overriden each time so it only ever contains the final JLabel.
private JPanel panel2(){
JPanel panel2=new JPanel(new GridLayout(5,1));
for(int i=0; i<5; i++){
txtVote=new JLabel();
txtVote.setBorder(BorderFactory.createLineBorder(Color.RED));
panel2.add(txtVote);
}
return panel2;
}
So when you call getText on voteTxt in the action listener, you are only getting the last labels text.
To fix this, you need to make txtVote an array of JLabels, and in your action listener iterate a second time through your JLabels and call get text on each in turn.
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
check = (JCheckBox) e.getSource();
for (int i = 0; i < txtVotes.length; i++) {
txtVotes[i].getText(check.getName());
}
}
};
I don't know if you realise or want to, but each label is being set to the same value, if you don't want this you will need to store an array of check names somewhere and iterate through these as well.
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.
I'm having trouble getting a JPanel inside a BorderLayout to work.
I defined the layout of the Panel as a Grid Layout, and then added a bunch of buttons I had made before hand to the JPanel. However, when I run the program, the JFrame loads but nothing within the frame loads. Here's the code:
import java.awt.*;
import javax.swing.*;
public class Phone extends JFrame {
private JTextField PhoneText;
private JPanel ButtonPanel;
private JButton bttn1;
private JButton bttn2;
private JButton bttn3;
private JButton bttn4;
private JButton bttn5;
private JButton bttn6;
private JButton bttn7;
private JButton bttn8;
private JButton bttn9;
private JButton bttn10;
private JButton bttn11;
private JButton bttn12;
public Phone(){
setTitle("Phone - Agustin Ferreira");
Container ContentPane = getContentPane();
ContentPane.setLayout(new BorderLayout());
setSize(300, 400);
setVisible(true);
setBackground(Color.DARK_GRAY);
PhoneText = new JTextField("(317)188-8566");
bttn1 = new JButton ("1");
bttn2 = new JButton ("2");
bttn3 = new JButton ("3");
bttn4 = new JButton ("4");
bttn5 = new JButton ("5");
bttn6 = new JButton ("6");
bttn7 = new JButton ("7");
bttn8 = new JButton ("8");
bttn9 = new JButton ("9");
bttn10 = new JButton ("*");
bttn11 = new JButton ("0");
bttn12 = new JButton ("#");
ButtonPanel = new JPanel(new GridLayout(4,3,0,0));
ButtonPanel.add(bttn1);
ButtonPanel.add(bttn2);
ButtonPanel.add(bttn3);
ButtonPanel.add(bttn4);
ButtonPanel.add(bttn5);
ButtonPanel.add(bttn6);
ButtonPanel.add(bttn7);
ButtonPanel.add(bttn8);
ButtonPanel.add(bttn9);
ButtonPanel.add(bttn10);
ButtonPanel.add(bttn11);
ButtonPanel.add(bttn12);
ContentPane.add(PhoneText, BorderLayout.NORTH);
ContentPane.add(ButtonPanel, BorderLayout.CENTER);
}
}
Additionally, I have another class that calls the Phone class. Here's the code for that, just in case:
package ProgrammingAssignment11;
import javax.swing.JFrame;
public class GUI_Driver {
public static void main(String[] args) {
Phone Nokia;
Nokia = new Phone();
Nokia.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
}
Any Help?
Much appreciated, M3tal T1ger
Your main problem:
You should only call setVisible(true) after adding components to your GUI. You don't do this and so the GUI gets drawn without its components.
Also:
You should avoid setting the sizes or preferred sizes of anything. Instead let the components and layout managers size themselves.
And don't forget to call pack() after adding all components and before making the GUI visible.
Learn and follow Java naming conventions, including giving all variables and methods names that begin with a lower case letter, and all classes with names that start with an upper-case letter.
For example:
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class Phone2 extends JPanel {
private static final String[][] BTN_TEXTS = {
{"1", "2", "3"},
{"4", "5", "6"},
{"7", "8", "9"},
{"*", "0", "#"}
};
private static final float BTN_POINTS = 48f;
private static final float TEXT_POINTS = 24f;
private static final int DISPLAY_COLUMNS = 12;
private JButton[][] buttons = new JButton[BTN_TEXTS.length][BTN_TEXTS[0].length];
private JTextField display = new JTextField(DISPLAY_COLUMNS);
public Phone2() {
display.setFocusable(false);
display.setFont(display.getFont().deriveFont(TEXT_POINTS));
GridLayout gridLayout = new GridLayout(BTN_TEXTS.length, BTN_TEXTS[0].length);
JPanel btnPanel = new JPanel(gridLayout);
for (int i = 0; i < BTN_TEXTS.length; i++) {
for (int j = 0; j < BTN_TEXTS[i].length; j++) {
String text = BTN_TEXTS[i][j];
JButton btn = new JButton(new BtnAction(text));
btn.setFont(btn.getFont().deriveFont(Font.BOLD, BTN_POINTS));
btnPanel.add(btn);
buttons[i][j] = btn;
}
}
setLayout(new BorderLayout());
add(display, BorderLayout.NORTH);
add(btnPanel, BorderLayout.CENTER);
}
private class BtnAction extends AbstractAction {
public BtnAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent evt) {
String text = evt.getActionCommand();
display.setText(display.getText() + text);
}
}
private static void createAndShowGui() {
Phone2 mainPanel = new Phone2();
JFrame frame = new JFrame("Phone");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I've been trying for hours, different things and searching everywhere for a solution, but I can not get my table in addScoreCardUpper() to show up. I get an horizontal scrollbar, but no content, just 2 pixels worth of border.
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
public class YahtzeeGUI extends JFrame{
/**
*
*/
private static final long serialVersionUID = 3255683022699487295L;
private JFrame frame;
private JPanel panel;
private JPanel dicePanel;
private JScrollPane scrollPane;
private JButton btnRoll;
private JButton[] btnDice = new JButton[5];
private JTable table;
private Yahtzee y = new Yahtzee();
public YahtzeeGUI(){
createWindow();
addButtonRoll();
addButtonDice();
addScoreCardUpper();
//addScoreCardLower();
frame.add(panel);
frame.setVisible(true);
}
public void createWindow(){
frame = new JFrame();
frame.setTitle("Yahtzee");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1000,700);
frame.setVisible(true);
panel = new JPanel(new BorderLayout());
dicePanel = new JPanel();
scrollPane = new JScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
}
public void addButtonRoll(){
btnRoll = new JButton ("Roll the Dice");
btnRoll.addActionListener(new RollHandler());
dicePanel.add (btnRoll);
panel.add(dicePanel, BorderLayout.SOUTH);
}
public void addButtonDice(){
for (int i = 0; i < btnDice.length; i++){
btnDice[i] = new JButton(String.valueOf(y.dice[i].getFaceValue()));
btnDice[i].addActionListener(new HoldHandler());
dicePanel.add (btnDice[i]);
}
panel.add(dicePanel, BorderLayout.SOUTH);
}
public void addScoreCardUpper(){
String tableHeader[] = {"Upper Section", "How to score", "Score" };
String tableValues[][] = {
{"ONES", "Total of all Ones",""},
{"TWOS", "Total of all Twos",""},
{"THREES", "Total of all Threes",""},
{"FOURS", "Total of all Fours",""},
{"FIVES", "Total of all Fives",""},
{"SIXES", "Total of all Sixes",""},
{"TOTAL SCORE", "",""},
{"BONUS", "",""},
{"TOTAL + BONUS", "",""}
};
table = new JTable(tableValues, tableHeader);
table.setEnabled(false);
setColumnWidths();
scrollPane.add(table); // Here is the offender
panel.add(scrollPane, BorderLayout.EAST);
}
/*public void addScoreCardLower(){
String tableHeader[] = {"Lower S", "How to score", "Score" };
String tableValues[][] = {
{"ONES", "Total of all Ones",""},
{"TWOS", "Total of all Twos",""},
{"THREES", "Total of all Threes",""},
{"FOURS", "Total of all Fours",""},
{"FIVES", "Total of all Fives",""},
{"SIXES", "Total of all Sixes",""},
{"TOTAL SCORE", "",""},
{"BONUS", "",""},
{"TOTAL + BONUS", "",""}
};
table = new JTable(tableValues, tableHeader);
table.setEnabled(false);
setColumnWidths();
scoreSubPanel.add(table);
panel.add(scoreSubPanel, BorderLayout.WEST);
}*/
public void setColumnWidths(){
TableColumn a = table.getColumnModel().getColumn(0);
TableColumn b = table.getColumnModel().getColumn(1);
a.setPreferredWidth(100);
b.setPreferredWidth(100);
}
class RollHandler implements ActionListener {
public void actionPerformed(ActionEvent event) {
for(int i = 0; i < y.dice.length; i++){
if (y.dice[i].getHoldState() != true){
y.dice[i].roll();
btnDice[i].setText(String.valueOf(y.dice[i].getFaceValue()));
}
}
}
}
class HoldHandler implements ActionListener {
public void actionPerformed(ActionEvent event) {
for (int i = 0; i < btnDice.length; i++){
if (event.getSource()== btnDice[i]){ // Picks the pressed button after running through them all.
if (y.dice[i].getHoldState() == false){
y.dice[i].setHoldState(true);
} else if (y.dice[i].getHoldState() == true){
y.dice[i].setHoldState(false);
}
}
}
}
}
}
This is your problem:
scrollPane.add(table);
This does not add the JTable to the JScrollPane's viewport's view which is where you want it, but rather completely replaces the JScrollPane's viewport with the JTable, making the JScrollPane completely nonfunctional. Instead set the table as the JScrollPane's viewportview:
scrollPane.setViewportView(table);
Do either this or pass the table into the JScrollPane's constructor which does pretty much the same thing:
JScrollPane scrollPane = new JScrollPane(table,
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
This is all well explained in the JScrollPane API, and you will want to give it a look for the important details.
Edit
Your code also calls setVisible(true) on the JFrame before adding all components which can lead to trouble. You'll want to avoid doing this.
Try any one
scrollPane = new JScrollPane(table);
or
scrollPane = new JScrollPane(table,ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
or
scrollPane.getViewport().add(table);
I am trying to make a simple calculator to practice Graphics (i am a complete GUI noob). I am having some problems with having unneeded spaces after Polyashenkos Calulator and the text area and the space between the text area and the buttons. Also how do i keep that layout but eliminate the space and also make the bottom 3 buttons smaller. Any tips about what im doing or how i can do it better would be much appreciated. Thank you.
import javax.swing.*;
import java.awt.*;
public class calculator {
public static void main(String[] args) {
// creates the JFrame(a window with decorations)
JFrame frame = new JFrame("Calculator");
// stops the program when window is closed
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(377, 350);
// the main panel of the JFrame,
// remembet you cant add content directly to JFrame
JPanel content = new JPanel(new GridLayout(4, 0));
// panel for the text field
JPanel textarea = new JPanel(new GridLayout(4, 0));
// panel for the buttons,
// GridLayout(int rows, int cols, int horiz_gap, int vert_gap)
JPanel buttonarea = new JPanel(new GridLayout(4, 5, 2, 2));
// the panel for the bigger bottom buttons
JPanel secondbuttonarea = new JPanel(new GridLayout(1, 1, 2, 2));
// the panel for the text on top
JPanel label = new JPanel();
content.add(label);
content.add(textarea);
content.add(buttonarea);
content.add(secondbuttonarea);
JLabel words = new JLabel("Polyashenko's Calculator", JLabel.CENTER);
label.add(words);
JTextField enterhere = new JTextField("0.", JTextField.CENTER);
// will set the curser of the text bar on right side
enterhere.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
textarea.add(enterhere);
// makes a button called b1 with text in it
JButton b1 = new JButton("BkSP");
// adds the backspace button to the buttonarea panel
buttonarea.add(b1);
JButton b2 = new JButton("CE");
buttonarea.add(b2);
JButton b3 = new JButton("C");
buttonarea.add(b3);
JButton b4 = new JButton("/");
buttonarea.add(b4);
JButton b5 = new JButton("sqrt");
buttonarea.add(b5);
JButton b6 = new JButton("7");
buttonarea.add(b6);
JButton b7 = new JButton("8");
buttonarea.add(b7);
JButton b8 = new JButton("9");
buttonarea.add(b8);
JButton b9 = new JButton("*");
buttonarea.add(b9);
JButton b10 = new JButton("%");
buttonarea.add(b10);
JButton b11 = new JButton("4");
buttonarea.add(b11);
JButton b12 = new JButton("5");
buttonarea.add(b12);
JButton b13 = new JButton("6");
buttonarea.add(b13);
JButton b14 = new JButton("-");
buttonarea.add(b14);
JButton b15 = new JButton("1/x");
buttonarea.add(b15);
JButton b16 = new JButton("1");
buttonarea.add(b16);
JButton b17 = new JButton("2");
buttonarea.add(b17);
JButton b18 = new JButton("3");
buttonarea.add(b18);
JButton b19 = new JButton("+");
buttonarea.add(b19);
JButton b20 = new JButton("+/-");
buttonarea.add(b20);
JButton b21 = new JButton("0");
secondbuttonarea.add(b21);
JButton b22 = new JButton(".");
secondbuttonarea.add(b22);
JButton b23 = new JButton("=");
secondbuttonarea.add(b23);
// adds the buttonarea panel to the main panel
frame.getContentPane().add(content);
// makes the window visible, put at end of program
frame.setVisible(true);
}
}
one of lessons by Hovercraft Full Of Eels (-: forums.sun.com :-)
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.*;
import javax.swing.*;
public class SciCalc {
private static void createAndShowUI() {
SciCalcGui gui = new SciCalcGui();
SciCalcMenu menu = new SciCalcMenu(gui);
JFrame frame = new JFrame("Calculator");
frame.getContentPane().add(gui.getMainPanel());
frame.setJMenuBar(menu.getJMenuBar());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowUI();
}
});
}
private SciCalc() {
}
}
class SciCalcGui {
private static final String[][] STANDARD_BTN_TEXTS = {
{"7", "8", "9", "/"}, {"4", "5", "6", "*"},
{"1", "2", "3", "-"}, {"0", ".", "=", "+"}};
private static final String[][] SCIENTIFIC_BTN_TEXTS = {
{"sqrt", "1/x", "sin"}, {"%", "Exp", "cos"},
{"x^y", "ln", "tan"}, {"x^2", "n!", "sec"}};
private static final int GAP = 5;
private static final Font BTN_FONT = new Font(Font.DIALOG, Font.BOLD, 20);
private JPanel mainPanel = new JPanel();
private JPanel sciPanel;
private JTextField display = new JTextField();
SciCalcGui() {
display.setFont(BTN_FONT);
JPanel standardPanel = createBtnPanel(STANDARD_BTN_TEXTS, "Standard");
sciPanel = createBtnPanel(SCIENTIFIC_BTN_TEXTS, "Scientific");
mainPanel.setLayout(new BorderLayout());
mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
mainPanel.add(standardPanel, BorderLayout.CENTER);
mainPanel.add(sciPanel, BorderLayout.WEST);
mainPanel.add(display, BorderLayout.NORTH);
sciPanel.setVisible(false);
}
public void sciPanelSetVisible(boolean visible) {
sciPanel.setVisible(visible);
Window win = SwingUtilities.getWindowAncestor(mainPanel);
win.pack();
}
public JPanel getMainPanel() {
return mainPanel;
}
private JPanel createBtnPanel(String[][] texts, String title) {
JPanel btnPanel = new JPanel();
int rows = texts.length;
int cols = texts[0].length;
btnPanel.setLayout(new GridLayout(rows, cols, GAP, GAP));
for (int row = 0; row < texts.length; row++) {
for (int col = 0; col < texts[row].length; col++) {
JButton btn = new JButton(texts[row][col]);
btn.setFont(BTN_FONT);
btnPanel.add(btn);
}
}
btnPanel.setBorder(BorderFactory.createTitledBorder(title));
return btnPanel;
}
}
class SciCalcMenu {
private static final String STANDARD = "Standard";
private static final String SCIENTIFIC = "Scientific";
private SciCalcGui gui;
private JMenuBar menuBar = new JMenuBar();
private JMenuItem standardView;
private JMenuItem scientificView;
SciCalcMenu(SciCalcGui gui) {
this.gui = gui;
standardView = new JMenuItem(STANDARD, KeyEvent.VK_T);
scientificView = new JMenuItem(SCIENTIFIC, KeyEvent.VK_S);
ViewAction viewAction = new ViewAction();
standardView.addActionListener(viewAction);
scientificView.addActionListener(viewAction);
standardView.setEnabled(false);
JMenu viewMenu = new JMenu("View");
viewMenu.setMnemonic(KeyEvent.VK_V);
viewMenu.add(standardView);
viewMenu.add(scientificView);
menuBar.add(new JMenu("Edit"));
menuBar.add(viewMenu);
menuBar.add(new JMenu("Help"));
}
public JMenuBar getJMenuBar() {
return menuBar;
}
private class ViewAction implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals(STANDARD)) {
gui.sciPanelSetVisible(false);
standardView.setEnabled(false);
scientificView.setEnabled(true);
} else if (command.equals(SCIENTIFIC)) {
gui.sciPanelSetVisible(true);
standardView.setEnabled(true);
scientificView.setEnabled(false);
}
}
}
}
A GridLayout won't ever look very good in cases like this.
The content expands to fill the box in the grid. You only have minimal control over the spacing between rows and columns.
You may have to change layouts to make it look the way you want. GridBagLayout has all that control but is much harder to configure.
Sometimes you can nest panels with BorderLayout and GridLayout to make it look reasonable. But it is Swing and that means its usable but it becomes very hard to make it look slick.
I always like to use a FlowLayout for OK/Cancel buttons. They look best to me that way and you can push them all left, right or centered. Your calculator buttons should work well with a GridLayout but you can't easily have a tall "Enter" button or a wide "0" button.
For example, try using a vertical BoxLayout instead of a grid that is 4 high by 1 wide.