Which layout should I be using? - java

I have created a form with 5 buttons using a GridBagLayout to get this form:
What I want is for The buttons to be bigger and more evenly spaced like this:
Here is my code:
package com.GUI;
import java.awt.Color;
import javax.swing.*;
import com.seaglasslookandfeel.*;
public class JFramePlus extends JFrame{
public JFramePlus(){
super("OmegaBrain");
setSize(1000,800);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
getContentPane().setBackground(Color.black);
setResizable(false);
}
}
This is the superclass of the class in question.
package com.GUI;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import java.util.Stack;
class GamePlay extends JFramePlus implements ActionListener{
//Create Stack
Stack sequence = new Stack();
//Declare Variables
String greekSequence;
int stackCount;
int timeLeft;
static int optionNo;
//Create Constraints
GridBagConstraints c = new GridBagConstraints();
//Defining new objects
JLabel timeDisplay, sequenceViewer;
JButton mainMenu, input1, input2, input3, input4, input5;
JPanel timerPane, centerPane, exitPane;
Timer t;
GamePlay(){
//Create Labels
timeDisplay = new JLabel();
sequenceViewer = new JLabel();
//Create Panels
timerPane = new JPanel();
centerPane = new JPanel();
exitPane = new JPanel();
//Change layout of centerPane
centerPane.setLayout(new GridBagLayout());
//Creates JButtons
mainMenu = new JButton("Main Menu");
input1 = new JButton("Ξ");
c.gridx = 0;
c.gridy = 1;
centerPane.add(input1, c);
input2 = new JButton("Ω");
c.gridx = 2;
c.gridy = 1;
centerPane.add(input2, c);
input3 = new JButton("Ψ");
c.gridx = 4;
c.gridy = 1;
centerPane.add(input3, c);
input4 = new JButton("Φ");
c.gridx = 1;
c.gridy = 2;
centerPane.add(input4, c);
input5 = new JButton("Γ");
c.gridx = 3;
c.gridy = 2;
centerPane.add(input5, c);
//Create Timer
t = new Timer(1000, this);
//Changes the size of the font
timeDisplay.setFont(timeDisplay.getFont().deriveFont(64.0f));
//Generate Sequence
sequenceGenerator();
//Add components to panels
timerPane.add(timeDisplay);
centerPane.add(sequenceViewer, c);
exitPane.add(mainMenu);
//add panels to frame
add(timerPane, BorderLayout.LINE_END);
add(centerPane, BorderLayout.CENTER);
add(exitPane, BorderLayout.SOUTH);
//Change colors to fit theme
timeDisplay.setForeground(Color.WHITE);
sequenceViewer.setForeground(Color.WHITE);
timerPane.setBackground(Color.BLACK);
centerPane.setBackground(Color.BLACK);
exitPane.setBackground(Color.BLACK);
//Add ActionListeners to buttons
mainMenu.addActionListener(this);
input1.addActionListener(this);
input2.addActionListener(this);
input3.addActionListener(this);
input4.addActionListener(this);
input5.addActionListener(this);
}
public void sequenceGenerator(){
sequence.push(1 + (int)(Math.random() * optionNo));
stackCount++;
greekSequence = "";
for(int i = 0; i < stackCount; i++){
if (sequence.get(i) == 1){
greekSequence = greekSequence + 'Ξ';
}
}
sequenceViewer.setText(greekSequence);
}
void startTimer() {
t.start();
}
public void actionPerformed(ActionEvent evt) {
Object source = evt.getSource();
if(source == t){
timeDisplay.setText(String.valueOf(timeLeft));
timeLeft--;
if(timeLeft == -1){
t.stop();
}
}
else if(source == mainMenu){
int yesNo = JOptionPane.showConfirmDialog(
null,
"Are you sure you want to exit? Your current score will be saved as it is." ,
"Exit Game?",
JOptionPane.YES_NO_OPTION);
if(yesNo == JOptionPane.YES_OPTION){
dispose();
mainMenu menu = new mainMenu();
}
else{
}
}
}
}

This is a loaded question. I'll start by saying GridBagLayout is just fine for what you're trying to achieve. I think you should invest some time looking into: How to Use GridBagLayout.
You should also look into "Insets" for spacing options, and utilizing gridwidth, gridheight, and maybe even ipadx and ipady when dealing with GridBagConstraints.

You can also use a BoxLayout. (How to use BoxLayout ).
You would be able to position your components as desired and if you want to add space between components, you can add an empty border to your components or put invisible components between them.
You can see this discussion for more information.

Related

Java Swing - Change number of text fields based on a variable

I'd like to have a GUI that can adapt to user input, rather than making a different panel for each option.
The first panel has a number of buttons to choose from, each will bring you to the next panel that will contain text entry fields.
Option A: Has 2 components and should open a panel with 4 text fields.
Option B: Has 3 components and should open a panel with 6 text fields.
Specifically, option A is a recipe with two components, and option B is a recipe with 3 components. Each component has a lot number and an expiration date. So both panels will have the same two types of fields: lot number and expiration date. The number and names of components is what will change.
Can I have the same panel be able to adapt to a number of components sent to it based on which of the two options was selected? Or do I have to make two separate panels, one with 4 fields and one with 6?
Here's one idea:
Map<String, JTextField> fieldMap = new HashMap<String, JTextField>()
for(int i = 0; i < recipe.length; i++)
{
fieldMap.put("field" + i, new JTextField());
}
Idea derived from Creating a variable name using a String value
The code below addresses specifically your question statement, although I can't help thinking that you probably want something more generic, i.e. where there are more than two options. Also, the below code is only one possible implementation of your stated requirements.
The idea in the below code is to initially create all the required GUI components in a single container and simply change the visibility of the [optional] components depending on the selected option.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerDateModel;
public class Opciones implements ActionListener {
private JFrame frame;
private JLabel expiryThirdLabel;
private JLabel lotThirdLabel;
private JRadioButton twoRadioButton;
private JRadioButton threeRadioButton;
private JSpinner expiryFirstSpinner;
private JSpinner expirySecondSpinner;
private JSpinner expiryThirdSpinner;
private JTextField lotFirstTextField;
private JTextField lotSecondTextField;
private JTextField lotThirdTextField;
public void actionPerformed(ActionEvent event) {
Object src = event.getSource();
boolean flag;
if (twoRadioButton == src) {
flag = false;
}
else if (threeRadioButton == src) {
flag = true;
}
else {
flag = false;
JOptionPane.showMessageDialog(frame,
"Unrecognized source.",
"WARNING",
JOptionPane.WARNING_MESSAGE);
}
expiryThirdLabel.setVisible(flag);
expiryThirdSpinner.setVisible(flag);
lotThirdLabel.setVisible(flag);
lotThirdTextField.setVisible(flag);
frame.pack();
}
private void createAndDisplayGui() {
frame = new JFrame("Options");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createTopPanel(), BorderLayout.PAGE_START);
frame.add(createForm(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createForm() {
JPanel form = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.LINE_START;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets.bottom = 5;
gbc.insets.left = 5;
gbc.insets.right = 5;
gbc.insets.top = 5;
JLabel lotFirstLabel = new JLabel("Lot Number");
form.add(lotFirstLabel, gbc);
gbc.gridx = 1;
lotFirstTextField = new JTextField(6);
form.add(lotFirstTextField, gbc);
gbc.gridx = 2;
JLabel expiryFirstLabel = new JLabel("Expiry");
form.add(expiryFirstLabel, gbc);
gbc.gridx = 3;
expiryFirstSpinner = createSpinner();
form.add(expiryFirstSpinner, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
JLabel lotSecondLabel = new JLabel("Lot Number");
form.add(lotSecondLabel, gbc);
gbc.gridx = 1;
lotSecondTextField = new JTextField(6);
form.add(lotSecondTextField, gbc);
gbc.gridx = 2;
JLabel expirySecondLabel = new JLabel("Expiry");
form.add(expirySecondLabel, gbc);
gbc.gridx = 3;
expirySecondSpinner = createSpinner();
form.add(expirySecondSpinner, gbc);
gbc.gridx = 0;
gbc.gridy = 2;
lotThirdLabel = new JLabel("Lot Number");
lotThirdLabel.setVisible(false);
form.add(lotThirdLabel, gbc);
gbc.gridx = 1;
lotThirdTextField = new JTextField(6);
lotThirdTextField.setVisible(false);
form.add(lotThirdTextField, gbc);
gbc.gridx = 2;
expiryThirdLabel = new JLabel("Expiry");
expiryThirdLabel.setVisible(false);
form.add(expiryThirdLabel, gbc);
gbc.gridx = 3;
expiryThirdSpinner = createSpinner();
expiryThirdSpinner.setVisible(false);
form.add(expiryThirdSpinner, gbc);
return form;
}
private JSpinner createSpinner() {
SpinnerDateModel sdm = new SpinnerDateModel();
JSpinner spinner = new JSpinner(sdm);
spinner.setEditor(new JSpinner.DateEditor(spinner, "MM/dd/yyyy")); // USA format
return spinner;
}
private JPanel createTopPanel() {
JPanel topPanel = new JPanel();
JLabel label = new JLabel("Number of Components");
topPanel.add(label);
ButtonGroup buttonGroup = new ButtonGroup();
twoRadioButton = new JRadioButton("Two");
twoRadioButton.addActionListener(this);
twoRadioButton.setSelected(true);
buttonGroup.add(twoRadioButton);
topPanel.add(twoRadioButton);
threeRadioButton = new JRadioButton("Three");
threeRadioButton.addActionListener(this);
buttonGroup.add(threeRadioButton);
topPanel.add(threeRadioButton);
return topPanel;
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new Opciones().createAndDisplayGui());
}
}
Initially, the GUI looks like this
And after selecting Three radio button
Refer to the following.
How to Use Buttons, Check Boxes, and Radio Buttons
How to Make Frames (Main Windows)
How to Use Spinners
How to Use GridBagLayout
How to Write an Action Listener

Java JScrollpane not visible

I'm trying to display a series of buttons in a JScrollpane. Reading around, I managed to exit with this code, but nothing is displayed. I do not understand a possible mistake. Thank you for help
As suggested I made some changes, I edited but not works
EDITED
or I'm stupid, or here is some other problem. Here is my complete code with the output image
public class Main extends javax.swing.JFrame {
private final JPanel gridPanel;
public Main() {
initComponents();
// EXISTING PANEL
gridPanel = new JPanel();
JScrollPane scrollPane = new JScrollPane(gridPanel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel borderLayoutPanel = new JPanel(new BorderLayout());
borderLayoutPanel.add(scrollPane, BorderLayout.CENTER);
this.Avvio();
}
private void Avvio() {
JPanel pane = new JPanel(new GridBagLayout());
pane.setBorder(BorderFactory.createLineBorder(Color.BLUE));
pane.setLayout(new GridBagLayout());
for (int i = 0; i < 10; i++) {
JButton button;
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.PAGE_START;
button = new JButton("Button 1");
c.weightx = 0.5;
c.gridx = 0;
c.gridy = i;
pane.add(button, c);
button = new JButton("Button 2");
c.gridx = 1;
c.gridy = i;
pane.add(button, c);
button = new JButton("Button 3");
c.gridx = 2;
c.gridy = i;
pane.add(button, c);
}
gridPanel.add(pane);
gridPanel.revalidate();
gridPanel.repaint();
}
}
Alright, from your comments in another answer:
No problem for compile , simply the Jpanel is empty. The buttons does not appear.
After calling this.Avvio(); you must call:
this.add(scrollPane);
this.pack();
This will produce the following outputs (before and after resizing it):
But there's still no JScrollPanel
This at least solves the first problem, however you have more errors in your code, some of which have already been commented in other answers:
You're extending JFrame, this isn't needed as you can create a JFrame instance / object and use it later. You're never changing the JFrame's behavior and that's why it's not needed to extend it. See Extends JFrame vs. creating it inside the program for more information about this.
You're not calling pack() nor setSize(...) this creates a tiny window, which you need to manually resize. Call pack() recommended before making your JFrame visible. (As suggested at the beginning of this answer).
You're calling .invokeLater() method twice. You need to call it just once, I prefer this way:
SwingUtilities.invokeLater(() -> new Main()); //Note there is no call to .setVisible(true); as per point #1. It should go later in the program like: frame.setVisible(true);
You're calling gridPanel.revalidate(); and gridPanel.repaint() while it doesn't affect your program, it's not needed as your GUI is still not visible, and thus those calls have no effect on your program, you can safely remove them.
You're creating a new GridBagConstraints object on each iteration of the for loop, you can just change its properties inside it and declaring it outside the for loop, which will make your program better.
After following the above recommendations, you can end up with a code like this one:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class Main {
private final JPanel gridPanel;
private JFrame frame;
public Main() {
// EXISTING PANEL
gridPanel = new JPanel();
JScrollPane scrollPane = new JScrollPane(gridPanel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel borderLayoutPanel = new JPanel(new BorderLayout());
borderLayoutPanel.add(scrollPane, BorderLayout.CENTER);
this.Avvio();
frame.add(scrollPane);
frame.pack();
frame.setVisible(true);
}
private void Avvio() {
JPanel pane = new JPanel(new GridBagLayout());
pane.setBorder(BorderFactory.createLineBorder(Color.BLUE));
pane.setLayout(new GridBagLayout());
for (int i = 0; i < 10; i++) {
JButton button;
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.PAGE_START;
button = new JButton("Button 1");
c.weightx = 0.5;
c.gridx = 0;
c.gridy = i;
pane.add(button, c);
button = new JButton("Button 2");
c.gridx = 1;
c.gridy = i;
pane.add(button, c);
button = new JButton("Button 3");
c.gridx = 2;
c.gridy = i;
pane.add(button, c);
}
gridPanel.add(pane);
}
public static void main(String args[]) {
/* Create and display the form */
SwingUtilities.invokeLater(() -> {
new Main();
});
}
}
Which still produces this output:
BUT... We still can improve it a little more!
We may have two nested for loops, for the GridBagConstraints properties as well as the generation of the buttons:
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class ScrollablePaneWithButtons {
private static final int ROWS = 10;
private static final int COLS = 3;
private JFrame frame;
private JPanel pane;
private JButton[][] buttons;
private GridBagConstraints gbc;
private JScrollPane scroll;
private JButton[] menuButtons;
private JPanel menuPane;
public static void main(String[] args) {
SwingUtilities.invokeLater(new ScrollablePaneWithButtons()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(this.getClass().getSimpleName());
pane = new JPanel();
pane.setLayout(new GridBagLayout());
menuPane = new JPanel();
menuPane.setLayout(new GridLayout(1, 3));
buttons = new JButton[ROWS][COLS];
menuButtons = new JButton[] {new JButton("Edit"), new JButton("Delete"), new JButton("Sort Fields")};
gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.PAGE_START;
gbc.weightx = 0.5;
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
buttons[i][j] = new JButton("Button " + (j + 1));
gbc.gridx = j;
gbc.gridy = i;
pane.add(buttons[i][j], gbc);
}
}
scroll = new JScrollPane(pane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
for (JButton b : menuButtons) {
menuPane.add(b);
}
frame.add(scroll);
frame.add(menuPane, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
And this example is (in my opinion) easier to read and follow up. And this is the output the above code is generating:
You can still choose which code to use, either doing the modifications at the first part of this answer, the second one following the recommendations above or the last one which is shorter.
Problems noted:
Avvio - the pane layout was reset during each loop. Set it once before the loop.
Avvio - the pane was added to the grid pane in each loop. Add it once after the loop.
Avvio - the constraints place the buttons in the same grid locations. With the previous two issues fixed, only the last three buttons placed appear.
I'm assuming you want three buttons in a row, so I changed the loop to use the counter as a row counter. The code below will create ten rows of three buttons.
What appears:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.WindowConstants;
public class Main extends javax.swing.JFrame {
private JPanel gridPanel;
public Main() {
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setSize(600,400);
//EXISTING PANEL
gridPanel = new JPanel();
JScrollPane scrollPane = new JScrollPane(gridPanel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel borderLayoutPanel = new JPanel(new BorderLayout());
borderLayoutPanel.add(scrollPane, BorderLayout.CENTER);
this.Avvio();
this.add(borderLayoutPanel, BorderLayout.CENTER);
this.setVisible(true);
}
private void Avvio() {
JPanel pane = new JPanel(new GridBagLayout());
pane.setBorder(BorderFactory.createLineBorder(Color.BLUE));
pane.setLayout(new GridBagLayout());
for (int i = 0; i < 10; i++) {
JButton button;
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.PAGE_START;
button = new JButton("Button 1");
c.weightx = 0.5;
c.gridx = 0;
c.gridy = i;
pane.add(button, c);
button = new JButton("Button 2");
c.gridx = 1;
c.gridy = i;
pane.add(button, c);
button = new JButton("Button 3");
c.gridx = 2;
c.gridy = i;
pane.add(button, c);
}
gridPanel.add(pane);
gridPanel.revalidate();
gridPanel.repaint();
}
public static void main(String args[]) {
new Main();
}
}
There are several things to do to make it work:
Add a main method
This main method is the entry point. This makes sure the swing-code runs in the AWT-thread. This is what the SwingUtilities.invokeLater is for
Instantiate, pack and display the frame. The size setting is only for experimenting with the scrollpane
Declare the gridPanel as an instance variable
wrap the gridPanel with the scrollPane
Optionally, wrap the scrollPane with the borderLayoutPanel
Invoke the Avvio method because this is the one that adds the buttons
Add the outmost element to the frame
Here is the fixed code:
public class MyFrame extends javax.swing.JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
MyFrame frame = new MyFrame();
frame.pack();
frame.setSize(600, 300);
frame.setVisible(true);
});
}
private JPanel gridPanel;
public MyFrame() {
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
gridPanel = new JPanel(new GridLayout(0, 1));
JScrollPane scrollPane = new JScrollPane(gridPanel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel borderLayoutPanel = new JPanel(new BorderLayout());
borderLayoutPanel.add(scrollPane, BorderLayout.CENTER);
this.Avvio();
this.add(borderLayoutPanel, BorderLayout.CENTER);
}
private void Avvio() {...}
}
I have simplified the program and removed all the mistakes
and bad practices. (Missing package, unnecessary panels, calling invokeLater() twice and others.)
Here is a working example:
package com.zetcode;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class JavaScrollPaneEx extends JFrame {
public JavaScrollPaneEx() {
initUI();
}
private void initUI() {
JPanel panel = new JPanel(new BorderLayout());
JPanel buttonPanel = createButtonPanel();
JScrollPane scrollPane = new JScrollPane(buttonPanel);
panel.add(scrollPane, BorderLayout.CENTER);
add(panel);
setTitle("Buttons in JScrollBar");
setSize(350, 250);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.PAGE_START;
c.insets = new Insets(5, 5, 5, 5);
for (int i = 0, j = 0; i < 5; i++) {
JButton btn = new JButton("Button " + (j + 1));
c.weightx = 0.5;
c.gridx = i;
c.gridy = 0;
panel.add(btn, c);
btn = new JButton("Button " + (j + 2));
c.gridx = i;
c.gridy = 1;
panel.add(btn, c);
btn = new JButton("Button " + (j + 3));
c.gridx = i;
c.gridy = 2;
panel.add(btn, c);
j += 3;
}
return panel;
}
public static void main(String args[]) {
EventQueue.invokeLater(() -> {
JavaScrollPaneEx ex = new JavaScrollPaneEx();
ex.setVisible(true);
});
}
}
And this is the screenshot.
And since I consider GridBagLayout to be a very bad
layout manager, I have created a similar example with MigLayout
manager.
We need the following Maven dependency for this example:
<dependency>
<groupId>com.miglayout</groupId>
<artifactId>miglayout-swing</artifactId>
<version>5.0</version>
</dependency>
The source:
package com.zetcode;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JButton;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import net.miginfocom.swing.MigLayout;
public class JavaScrollPaneEx2 extends JFrame {
public JavaScrollPaneEx2() {
initUI();
}
private void initUI() {
JPanel panel = new JPanel(new BorderLayout());
JPanel buttonPanel = createButtonPanel();
JScrollPane scrollPane = new JScrollPane(buttonPanel);
panel.add(scrollPane, BorderLayout.CENTER);
add(panel);
setTitle("Buttons in JScrollBar");
setSize(350, 250);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new MigLayout());
for (int i = 0, j = 0; i < 5; i++) {
JButton btn1 = new JButton("Button " + (j + 1));
JButton btn2 = new JButton("Button " + (j + 2));
JButton btn3 = new JButton("Button " + (j + 3));
JButton btn4 = new JButton("Button " + (j + 4));
JButton btn5 = new JButton("Button " + (j + 5));
panel.add(btn1, "sgx");
panel.add(btn2, "sgx");
panel.add(btn3, "sgx");
panel.add(btn4, "sgx");
panel.add(btn5, "sgx, wrap");
j += 5;
}
return panel;
}
public static void main(String args[]) {
EventQueue.invokeLater(() -> {
JavaScrollPaneEx2 ex = new JavaScrollPaneEx2();
ex.setVisible(true);
});
}
}

Replacing component in panel without it going to the end?

I am working on a program that has no errors when I compile, and the logic runs soundly for it's purpose (I'm making a basic Penny Pitch program in GUI). The board is filled with image icons that contain the number of points a player will receive if they land on it, and when they land on a spot the image icon is suppose to switch to a picture of the same spot with a penny on it. However, when the previous icon is removed and the new "occupied" one is assigned, it is assigned at the end of the panel rather than the previous spot the "empty" icon was taken from.
To illustrate:
this is the normal layout,
before "tossing" a penny,
and this is the shifted layout,
after "tossing" a penny.
I can't find any sources explaining how to add a component to a panel in a spot previously occupied by a removed component. If anyone knows how, it would be great help!
-----------------------------------EDIT-----------------------------------------
New pictures:,.
I'm using a GridBagLayout now, and since I'm still not sure what is the cause of the new added component not taking the space of the removed one, I cut down my entire program to illustrate it's aspects:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class PennyPitch extends JFrame implements ItemListener{
//variables
int aa=0, thrown=0, place=0, illit=1, illit2=1;
Random pitch = new Random();
private ImageIcon full = new ImageIcon("pitchFull.png");
//map
private Map tossing;
//jbuttons
private JButton confirm = new JButton (new ImageIcon("pitchPenny.png"));
//map
private Map<Integer, ColorPanel> spot = new HashMap<Integer, ColorPanel>();
//declared icon to use when button is pushed
private ColorPanel rSet = new ColorPanel(Color.white, full);
//panel
private JPanel input = new JPanel(new GridBagLayout ());
private GridBagConstraints c = new GridBagConstraints();
public PennyPitch(){
prepareGUI();
}
public static void main(String[] args){
PennyPitch pitch = new PennyPitch(); }
private void prepareGUI(){
//background
input.setBackground(Color.WHITE);
//button design
confirm.setBorder(BorderFactory.createEmptyBorder());
confirm.setContentAreaFilled(false);
//icon for use
ImageIcon one = new ImageIcon("pitchOne.png");
//components for map
ColorPanel i1 = new ColorPanel(Color.white, one);
ColorPanel i2 = new ColorPanel(Color.white, one);
ColorPanel i3 = new ColorPanel(Color.white, one);
//MAP FOR THE STATS
spot.put(1, i1);
spot.put(2, i2);
spot.put(3, i3);
//PANEL
c.ipady = 50;
c.ipadx = 50;
c.gridx = 1;
c.gridy = 1;
c.gridwidth = 1;
input.add(spot.get(1),c);
c.ipady = 50;
c.ipadx = 50;
c.gridx = 2;
c.gridy = 1;
c.gridwidth = 1;
input.add(spot.get(2),c);
c.ipady = 50;
c.ipadx = 50;
c.gridx = 3;
c.gridy = 1;
c.gridwidth = 1;
input.add(spot.get(3),c);
c.ipady = 50;
c.ipadx = 50;
c.gridx = 4;
c.gridy = 1;
c.gridwidth = 2;
input.add(confirm,c);
//listener for button
confirm.addActionListener (new AddListener());
//CONTAINER
Container container = getContentPane();
container.add(input);
//frame information
Toolkit tk = Toolkit.getDefaultToolkit();
setSize(600, 600);
setTitle("PENNY PITCH");
setMinimumSize(new Dimension(600,600));
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack ();
setVisible(true);
}
private class AddListener implements ActionListener {
public void actionPerformed(ActionEvent a){
if (a.getSource()== confirm) {
//generates number to land on
thrown = pitch.nextInt(3) + 1;
System.out.println(thrown);
place=illit;
spot.put(place, rSet);
Component old = input.getComponent(thrown);
Component newn = input.getComponent(place);
Component[] compSet=input.getComponents();
for(int i=0; i<compSet.length; i++){
if(old.equals(compSet[i])) {
input.remove(old);
c.ipady = 50;
c.ipadx = 50;
c.gridwidth = 1;
input.add(newn, i);
}
}
illit++;
repaint();
}
}
}
public void itemStateChanged(ItemEvent e) {
System.out.println (aa);
}
}
class ImageLabel extends JLabel {
public ImageLabel (String img){
this (new ImageIcon (img));
}
public ImageLabel (ImageIcon icon){
setIcon(icon);
setIconTextGap(0);
setBorder(null);
setText(null);
setSize(icon.getImage().getWidth(null),icon.getImage().getHeight(null));
}
}
Container has a method getComponents(). JPanel is a descendant and will hopefully have it. To check for a given component you do the following:
Component[] cmp=myPanel.getComponents();
for(int i=0; i<cmp.length; i++)
if(myComponent.equals(cmp[i])) {
myPanel.remove(myComponent);
myPanel.add(myNewComponent, i);
}
where myComponent is the component you want to remove and myNewComponent is the component you want to add.
--
Ok your code uses some ColorPanel which I'm not familiar with but lets suppose its something like a JLabel.
I understand that you actually add (in the full code) as many colorpanels as coins in the image.
GridBag is out of my consideration - but maybe you should just skip the ipadx etc and just remove/add. Better yet use some /normal/ layout such as GridLayout or even FlowLayout for testing purposes.
Suggestion: have a JPanel (input) with a GridLayout(5, 5) where you add only the color panels (numbers). Have another JPanel (jp2) where you add the previous JPanel (input) and the button(confirm) - this jp2 is added to the jframe. You should add/remove on the input.
for(i=0; i<25; i++) input.add(new ColorPanel(...));
thrown = pitch.nextInt(25);
System.out.println(thrown);
place=illit;
spot.put(place, rSet);
input.remove(thrown);
Component newn = input.getComponent(place);
input.add(newn, thrown);
Also make sure you call validate after each removal/addition:
input.validate();
In summary, the following is a simplified working program of what you are trying to do:
class T extends Frame {
public T() {
setSize(500, 500);
setLayout(new GridLayout(5, 5));
for(int i=0; i<25; i++) add(new Label(""+i));
setVisible(true);
}
public static void main(String args[]) {
T t=new T();
for(int i=0; i<5; i++) {
int r=(int)(Math.random()*25);
t.remove(r);
t.add(new Label(""+(i+1)), r);
t.validate();
t.repaint();
try { Thread.sleep(5000); } catch(InterruptedException ie) {}
}
}
}

Adding JScrollPane in JTextArea using GridBagLayout

I'm having an issue adding JScrollPane in JTextArea using GridBagLayout. Basically the program runs fine when the scrollbar isn't needed but the layout gets messed up and the content gets cut off when it is. The relevent code is as follows
import java.io.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
public class testGUI extends JFrame
{
public static String name;
static JTextField textfield = new JTextField(30);
static JTextArea textarea = new JTextArea(30,30);
public static void main( String[] args)
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Checkem");
frame.setLocation(500,400);
frame.setSize(800,800);
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JScrollPane scrolltxt = new JScrollPane(textarea,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrolltxt.setWheelScrollingEnabled(true);
scrolltxt.getVerticalScrollBar().isVisible();
panel.add(scrolltxt, c);
JLabel label = new JLabel("Enter the Name of the file:");
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(2,2,2,2);
panel.add(label,c);
c.gridx = 0;
c.gridy = 1;
panel.add(textarea,c);
JButton button = new JButton("Search");
c.gridx = 1;
c.gridy = 1;
panel.add(button,c);
c.gridx = 1;
c.gridy = 0;
panel.add(textfield,c);
frame.getContentPane().add(panel, BorderLayout.NORTH);
frame.pack();
frame.setVisible(true);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
Checkem record = new Checkem();
name = textfield.getText();
String [] print = record.run(name);
for (int i=0;i<print.length;i++)
{
if(print[i] == null || print[i].isEmpty())
{
continue;
}
else
{
textarea.append(print[i] + "\n");
}
}
}
});
}
}
I'm really new to swing and I'm really at a loss where to go from here. Thanks for all your help.
First please learn Java Naming Conventions, that makes it a bit easier for the other person to understand the Java code.
Now to the actual thingy :-)
Why not simply use JTextArea.setLineWrap(true) and
JTextArea.setWrapStyleWord(true) instead of defining JScrollBar policy,
this will even look nice on the view :-)
Moreover, instead of specifying setSize()/setLocation() methods,
simply use frameReference.pack() and
frame.setLocationByPlatform(true), a very wonderful answer
regarding the benefit of the latter is mentioned in this answer, how
to best position Swing GUIs
Do not make so many static fields in a class, this smells like a bad
programming design, and makes your class less extensible.
You are extending JFrame to your TestGUI class and then inside
it's main() method you creating an instance of the same. Actually
again, try to give more weightage to composition over inheritance, since
over here, you not actually trying to modify the already defined
features of JFrame, instead you just using them as is, so there is
no need to extend JFrame in this case atleast :-)
Read about Concurrency in Swing
Here is your modified code :
import java.io.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
public class TestGUI {
private String name;
private JTextField textfield = new JTextField(30);
private JTextArea textarea = new JTextArea(30,30);
private void displayGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Checkem");
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
textarea.setLineWrap(true);
textarea.setWrapStyleWord(true);
JScrollPane scrolltxt = new JScrollPane();
scrolltxt.setViewportView(textarea);
scrolltxt.setWheelScrollingEnabled(true);
JLabel label = new JLabel("Enter the Name of the file:");
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(2,2,2,2);
panel.add(label,c);
c.gridx = 0;
c.gridy = 1;
panel.add(scrolltxt,c);
JButton button = new JButton("Search");
c.gridx = 1;
c.gridy = 1;
panel.add(button,c);
c.gridx = 1;
c.gridy = 0;
panel.add(textfield,c);
frame.getContentPane().add(panel, BorderLayout.NORTH);
//frame.setSize(800,800);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
/*Checkem record = new Checkem();
name = textfield.getText();
String [] print = record.run(name);
for (int i=0;i<print.length;i++)
{
if(print[i] == null || print[i].isEmpty())
{
continue;
}
else
{
textarea.append(print[i] + "\n");
}
}*/
}
});
}
public static void main( String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new TestGUI().displayGUI();
}
};
EventQueue.invokeLater(r);
}
}
You add the JScrollPane, but then you add the JLabel into the same grid position. Then you add the raw JTextArea without the JScrollPane later.
Try this which only adds the JScrollPane that contains your JTextArea. I also moved your GUI creation into a constructor that is called with a SwingUtilities.invokeLater call to ensure it is on the EDT. See Concurrency in Swing for more details on the EDT. This also allows you to not have all your class member variables static, which is not very good practice.
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class TestGUI extends JFrame {
String name;
JTextField textfield = new JTextField(30);
JTextArea textarea = new JTextArea(30, 30);
public TestGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JScrollPane scrolltxt = new JScrollPane(textarea);
JLabel label = new JLabel("Enter the Name of the file:");
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(2, 2, 2, 2);
panel.add(label, c);
c.gridx = 0;
c.gridy = 1;
panel.add(scrolltxt, c);
JButton button = new JButton("Search");
c.gridx = 1;
c.gridy = 1;
panel.add(button, c);
c.gridx = 1;
c.gridy = 0;
panel.add(textfield, c);
frame.getContentPane().add(panel, BorderLayout.NORTH);
frame.pack();
frame.setVisible(true);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
Checkem record = new Checkem();
name = textfield.getText();
String [] print = record.run(name);
for (int i=0;i<print.length;i++) {
if(print[i] == null || print[i].isEmpty()) {
continue;
} else {
textarea.append(print[i] + "\n");
}
}
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestGUI();
}
});
}
}

simple GUI not showing up?

Ok so, when I run it, it works all fine but it just doesn't pop up with the answer.
What did I do wrong?
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class AF implements ActionListener{
double length;
double width;
double answer;
JTextField twidth;
JTextField tlength;
void AFWindow() {
JFrame AFwindow = new JFrame();
JPanel pan2 = new JPanel(new GridBagLayout());
AFwindow.setVisible(true);
AFwindow.setSize(250, 150);
AFwindow.setResizable(false);
GridBagConstraints c = new GridBagConstraints();
AFwindow.add(pan2);
pan2.setBackground(Color.LIGHT_GRAY);
c.gridx = 0;
c.gridy = 5;
tlength = new JTextField();
tlength.setText(" Length ");
pan2.add(tlength, c);
c.gridx = 0;
c.gridy = 0;
twidth = new JTextField();
twidth.setText(" Width ");
pan2.add(twidth, c);
JButton Find = new JButton("Ok");
c.gridx = 0;
c.gridy = -5;
pan2.add(Find);
Find.addActionListener(this);
Find.setActionCommand("ok");
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equalsIgnoreCase("ok")){
try {
this.length = Double.parseDouble(tlength.getText());
this.width = Double.parseDouble(twidth.getText());
}
catch(NumberFormatException ex){
System.out.println("There was an issue!");
}
}
}
int area = (int) (length * width);
public void answer(){
JFrame answer = new JFrame();
answer.setVisible(true);
answer.setBackground(Color.yellow);
JPanel pan2 = new JPanel();
JLabel howanswer = new JLabel("Your answer is" + area + "We got this by multiplying the length and width");
pan2.add(howanswer);
}
}
That code has multiple issues. Forgot to document them, but look at this code for the beginnings of the fixes.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class AF implements ActionListener{
double length;
double width;
JTextField twidth;
JTextField tlength;
JFrame AFwindow;
void AFWindow() {
AFwindow = new JFrame();
JPanel pan2 = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
AFwindow.add(pan2);
pan2.setBackground(Color.LIGHT_GRAY);
pan2.setBorder(new EmptyBorder(100,100,100,100));
c.gridx = 0;
c.gridy = 5;
tlength = new JTextField();
tlength.setText(" Length ");
pan2.add(tlength, c);
c.gridx = 0;
c.gridy = 0;
twidth = new JTextField();
twidth.setText(" Width ");
pan2.add(twidth, c);
JButton Find = new JButton("Ok");
c.gridx = 0;
c.gridy = -5;
pan2.add(Find);
Find.addActionListener(this);
Find.setActionCommand("ok");
AFwindow.pack();
AFwindow.setLocationByPlatform(true);
AFwindow.setVisible(true);
}
int area;
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equalsIgnoreCase("ok")){
try {
this.length = Double.parseDouble(tlength.getText());
this.width = Double.parseDouble(twidth.getText());
area = (int) (length * width);
answer();
}
catch(NumberFormatException ex){
ex.printStackTrace();
// System.out.println("There was an issue!");
// Can you vague that up for me?!?!
JOptionPane.showMessageDialog(AFwindow, ex);
}
}
}
public void answer(){
JPanel pan2 = new JPanel();
JLabel howanswer = new JLabel("Your answer is " + area + " We got this by multiplying the length and width");
pan2.add(howanswer);
JOptionPane.showMessageDialog(AFwindow, pan2);
}
public static void main(String[] args) {
System.out.println("Hi!");
new AF().AFWindow();
}
}
Are you expecting the answer frame to pop up when you push the OK button? If so, you need to call the answer method:
if (e.getActionCommand().equalsIgnoreCase("ok")){
try {
this.length = Double.parseDouble(tlength.getText());
this.width = Double.parseDouble(twidth.getText());
answer(); // <--- This is missing
}
Also, some other things you need to do:
Generally, you should call JFrame.setVisible at the end of your GUI construction method, after you have added components to the frame. I have shown this in the example below, but you should move setVisible(..) to the bottom of the AFwindow() method as well.
When you do int area = (int) (length * width); outside of any method, this statement will be interpreted as an instance variable initialization and occur when you instantiate the AF object. And when the object is instantiated, you have not yet assigned any values to length and with. Hence, area will always be 0. Move that statement to the inside of the answer function instead.
You forgot to add the actual components to the frame in the answer method. Hence, when you set the frame to visible, only an empty frame will be displayed.
Here are examples of some suitable changes:
public void answer(){
int area = (int) (length * width); // <--- Move this inside answer method
JFrame answer = new JFrame();
answer.setBackground(Color.yellow);
JPanel pan2 = new JPanel();
JLabel howanswer = new JLabel("Your answer is" + area + "We got this by multiplying the length and width");
pan2.add(howanswer);
answer.add(pan2); // <--- Don't forget to add your components to the frame
answer.pack(); // <--- Resize the frame to a suitable size
answer.setVisible(true); // <--- Set the frame to visible AFTER you have added the components
}
This code works for me:
public class Test {
public static void main(String[] args){
JFrame test = new JFrame();
test.setVisible(true);
test.setSize(100,100);
test.setResizable(false);
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I assume that you can try to reduce your code and try to find problem point such way. You can put some logging to ensure setVisible(true) was called. Also I recomend to use setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); to terminate thread after exit GUI (if do not want to perform some post-exit actions).

Categories