(Sorry if this question is not done properly, I'm new. But at least I researched a lot before asking my own question)
Hello. I'm writing a blackjack game in java and it's turning quite massive. My problem is how to handle multiple instances of swing components, I guess you can call it. I can't figure out wether to create the components (such as jpanels and jbuttons) as class level, or in specific methods.
If I create them in their corresponding method, then my action listener can't see them, but if I create them as class level, then they get deleted when I call dispose().
class BlackjackGame extends JFrame implements ActionListener{
public void mainMenu(){
JPanel menuPane = new JPanel(new GridBagLayout()); //Init of main menu
GridBagConstraints c = new GridBagConstraints();
menuPane.setBackground(new Color(125,0,0));
menuPane.setBounds(620,220,175,250);
JLabel menuTitle = new JLabel("Welcome to Blackjack!");//Main menu-content
c.gridx = 1;
c.gridy = 0;
c.insets = new Insets(0,0,20,0);
menuPane.add(menuTitle, c);
JButton playButton = new JButton("Play!");
playButton.addActionListener(this);
c.gridx = 0;
c.gridy = 1;
c.gridwidth = 3;
c.ipadx = 25;
c.ipady = 25;
c.insets = new Insets(0,0,0,0);
menuPane.add(playButton, c);
JButton exitButton = new JButton("Exit!");
exitButton.addActionListener(this);
c.gridx = 0;
c.gridy = 2;
c.gridwidth = 3;
menuPane.add(exitButton, c);
JButton rulesButton = new JButton("Set rules.");
rulesButton.addActionListener(this);
c.gridx = 0;
c.gridy = 3;
c.gridwidth = 3;
menuPane.add(rulesButton, c);
this.add(menuPane,0);
}
//This is where I get problems
public void actionPerformed (ActionEvent event){
if(event.getSource() == playButton){
//I want the menuPane to disappear, and a transition into the game.
menuPane.dispose();
//Call method for the rest of the game.
}else if(event .getSource() etcetera etcetera){
etcetera etcetera
}
}
}
When done this way, the actionlistener cannot find my components, such as playButton or menuPane. But if I had introduced them as class level objects:
class BlackjackGame extends JFrame implements ActionListener{
JPanel menuPane = new JPanel(new GridBagLayout());
JLabel menuTitle = new JLabel("Welcome to Blackjack!");
JButton playButton = new JButton("Play!");
JButton exitButton = new JButton("Exit!");
JButton rulesButton = new JButton("Set rules.");
public void mainMenu(){
//Rest of code
}
public void actionPerformed(ActionEvent event){
menuPane.dispose();
//Rest of code
}
}
...then as I call menuPane.dispose(), how can I get it back when I want to call mainMenu() again? If I want to go back to the main menu, then I would need to create a new instance of menuPane, as well as all the buttons, but as they are class level and already disposed I can't.
Please help me, and thank you!
PS. I can post my full code as it is atm if it would help.
Edit: Dan's answer has been accepted, as it was indeed the correct answer and it worked for my specific program very well. Thank you and merry christmas!
First, unless I've misunderstood your code, menuPane.dispose() shouldn't work as JPanel does not have a function called dispose()
The best way to do what you want to do if you want to use the same menuPane for the menu. Instead of menuPane.dispose(); use remove(menuPane); and then add(yourOtherPanel);
Working Example
import java.awt.Color;
import java.awt.EventQueue;
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;
#SuppressWarnings("serial")
public class BlackjackGame extends JFrame implements ActionListener {
private JPanel menuPane;
private JLabel menuTitle;
private JButton playButton;
private JButton exitButton;
private JButton rulesButton;
private JPanel otherPane;
private JLabel otherTitle;
private JButton otherButton;
public BlackjackGame() {
mainMenu();
otherPanel();
setSize(400, 400);
setVisible(true);
}
private void mainMenu() {
menuPane = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
menuPane.setBackground(new Color(125,0,0));
menuPane.setBounds(620,220,175,250);
menuTitle = new JLabel("Welcome to Blackjack!");
c.gridx = 1;
c.gridy = 0;
c.insets = new Insets(0,0,20,0);
menuPane.add(menuTitle, c);
playButton = new JButton("Play!");
playButton.addActionListener(this);
c.gridx = 0;
c.gridy = 1;
c.gridwidth = 3;
c.ipadx = 25;
c.ipady = 25;
c.insets = new Insets(0,0,0,0);
menuPane.add(playButton, c);
exitButton = new JButton("Exit!");
exitButton.addActionListener(this);
c.gridx = 0;
c.gridy = 2;
c.gridwidth = 3;
menuPane.add(exitButton, c);
rulesButton = new JButton("Set rules.");
rulesButton.addActionListener(this);
c.gridx = 0;
c.gridy = 3;
c.gridwidth = 3;
menuPane.add(rulesButton, c);
add(menuPane);
}
private void otherPanel() {
otherPane = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
otherPane.setBackground(new Color(125,0,0));
otherPane.setBounds(620,220,175,250);
otherTitle = new JLabel("Welcome to Second Pane!");
c.gridx = 1;
c.gridy = 0;
c.insets = new Insets(0,0,20,0);
otherPane.add(otherTitle, c);
otherButton = new JButton("Go Back!");
otherButton.addActionListener(this);
c.gridx = 0;
c.gridy = 1;
c.gridwidth = 3;
c.ipadx = 25;
c.ipady = 25;
c.insets = new Insets(0,0,0,0);
otherPane.add(otherButton, c);
}
public void actionPerformed (ActionEvent event) {
if(event.getSource() == playButton) {
remove(menuPane);
add(otherPane);
validate();
repaint();
} else if(event.getSource() == otherButton) {
remove(otherPane);
add(menuPane);
validate();
repaint();
}
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new BlackjackGame());
}
}
Edit for comments
So the java method remove() only removes the object from the container, which in this case is the JFrame. This method does not effect the object it moves so the object can be reused later. Hence why in the code above I can just use the remove() and add() methods without redeclaring or remaking menuPane and otherPane.
As for why I declare the objects like this
`private JPanel menuPane;`
And then initialize like this
menuPane = new JPanel(new GridBagLayout());
This is because I want the ActionListener to be able to see the objects without initializing them straight away. The line private JPanel menuPane; makes the object a global variable and the line menuPane = new JPanel(new GridBagLayout()); makes it into what I am going to use. Doing it this way instead of JPanel menuPane = new JPanel(new GridBagLayout()); also means I can reuse the same variable in multiple methods. For example
private JPanel panel;
private void createPanelOne() {
panel = new JPanel(new FlowLayout());
...
add(panel);
}
private void createPanelTwo() {
panel = new JPanel(new GridBagLayout());
...
add(panel);
}
After doing this, you will have two JPanels in your JFrame and they will be different, but you only need to use one JPanel
This is the other way of declaring it and it makes a local variable. Local variables aren't visible to other methods outside of the method you are using unless you pass them through.
JPanel panel = new JPanel();
I wouldn't say this is a con in the slightest. I think sometimes it is good to use local variables in a method that shouldn't be visible to other methods.
Finally to pass local variables through to other methods you can use arguments in a method you have made. For example
public void setSomeValue(int val) {
someValue = val;
}
Related
My partner and I are writing this program for a game. He used GridBagLayout for our grid and I'm trying to troubleshoot some problems with the grid.
Here's the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
#SuppressWarnings("serial")
public class NewGame extends JFrame{
private int width = 500, height = 500, xSquares = 4, ySquares = 4;
Font buttonFont = new Font("Times New Roman", Font.PLAIN, 15);
endGame end = new endGame();
public NewGame() {
super("OnO");
// gridbaglayout is flexible but kinda complicated
GridBagLayout Griddy = new GridBagLayout();
this.setLayout(Griddy);
JPanel p = new JPanel();
p.setLayout(Griddy);
this.add(p);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.weighty = 1;
c.gridwidth = 4;
c.gridheight = 4;
NewBoard board = new NewBoard(xSquares, ySquares);
// board at top left
c.gridx = 0;
c.gridy = 0;
this.add(board, c);
// find a way to make buttons smaller
JButton EndGame = new JButton("End");
EndGame.setBackground(Color.black);
EndGame.setForeground(Color.white);
EndGame.setFont(buttonFont);
EndGame.addActionListener(end);
JButton Undo = new JButton("Undo");
Undo.setBackground(Color.black);
Undo.setForeground(Color.white);
Undo.setFont(buttonFont);
JButton NewGame = new JButton("New Game");
NewGame.setBackground(Color.black);
NewGame.setForeground(Color.white);
NewGame.setFont(buttonFont);
// fit 3
c.gridwidth = 1;
c.gridheight = 1;
c.gridy = 3;
c.fill = GridBagConstraints.HORIZONTAL;
p.add(EndGame, c);
c.gridx = 2;
c.fill = GridBagConstraints.HORIZONTAL;
p.add(Undo, c);
c.gridx = 3;
c.fill = GridBagConstraints.HORIZONTAL;
p.add(NewGame, c);
this.setPreferredSize(new Dimension(width, height));
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.pack();
this.setLocation(450, 30);
this.setVisible(true);
}
public class endGame implements ActionListener {
public void actionPerformed(ActionEvent event) {
System.exit(0);
}
}
public class newGame implements ActionListener {
public void actionPerformed(ActionEvent event) {
}
}
}
When this code is run with the other classes in our program, the endGame, Undo, and NewGame buttons overlap with the board:
I want to find a way to display the 3 buttons either above or below the board in its individual space, but I've tinkered with the code for a long time and can't find the solution yet. I'm not sure what I should be doing here.
First of all, variable names should NOT start with an upper case character. Learn and follow Java naming conventions.
I want to find a way to display the 3 buttons either above or below the board
Simplest solution is to not use a GridBagLayout for the frame.
Just use the default BorderLayout of the frame. Then you can use a JPanel with the FlowLayout for your buttons, and a GridLayout for your board panel.
The basic logic would be:
JPanel buttons = new JPanel();
buttons.add(endGame);
buttons.add(undo);
buttons.add(newGame);
this.add(button, BorderLayout.PAGE_START);
NewBoard board = new NewBoard(xSquares, ySquares);
this.add(board, BorderLayout.CENTER);
By default a JPanel uses a FlowLayout so the buttons will be displayed on a single row.
Read the Swing tutorial on Layout Managers for more information and working examples to better understand how this suggestion works.
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);
});
}
}
I have a frame that has couple of panels and they change by CardLayout.
Inside each panel i will have different components. To design the GUI of the panel I used GridBagLayout. But the problem is any component or Layout I use for these paneles, they all stay at the top of the page. So basically the panel size of the CardLayout is some small amount of the frame. I want to make the sub panel size as large as the main CardLayout size.
Code for main CardLayout:
public class MainPanel extends JPanel {
private CardLayout cl = new CardLayout();
private JPanel panelHolder = new JPanel(cl);
public MainPanel() {
NewSession session = new NewSession(this);
ChooseSource chooseSource = new ChooseSource(this);
panelHolder.add(session, "1");
panelHolder.add(chooseSource, "2");
cl.show(panelHolder, "dan");
add(panelHolder);
}
public void showPanel(String panelIdentifier){
cl.show(panelHolder, panelIdentifier);
}
}
A sub panel:
public class ChooseSource extends JPanel {
MainPanel ob2;
JButton btn;
JLabel label;
JTextField field;
public ChooseSource(MainPanel mainPanel){
this.ob2 = mainPanel;
btn = new JButton("Browse");
label = new JLabel("Folder ");
field = new JTextField();
btn.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
ob2.showPanel("1");
}
});
GridBagLayout layout = new GridBagLayout();
setLayout(layout);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
c.ipady = 20;
c.gridheight = 2;
add(btn, c);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 1;
c.gridy = 0;
c.ipady = 10;
c.gridheight = 1;
c.insets = new Insets(0,10,0,0);
add(label, c);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 1;
c.gridy = 1;
c.ipady = 0;
c.gridheight = 1;
c.insets = new Insets(0,10,0,0);
add(field, c);
}
}
The left image shows how it is not, and right one is the one I am trying to make. basically I want to have access to all the available space of the panel.
Any idea?
Change the layout manager of MainPanel to something like BorderLayout or GridBagLayout
my name is Gab.
I'm making a program that will make vanish one page for an other by clicking a button. The thing is, I can't pass the appropriate datas from my two classes. It may sounds weird like this, but here's my code:
My first class (class1):
import javax.swing.*;
import java.awt.*;
import java.util.Scanner;
public class class1 {
public static void main(String[] args) {
JPanel panel = new JPanel();
JFrame frame = new JFrame();
GridBagLayout gridBag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
contenu.setLayout(gridBag);
boolean start = false;
JLabel label1 = new JLabel(
"<html><p><span style = 'font-size: 18px; font-color: blue'>The Number's Genius </span>(version 1.4)</p></html>");
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
c.gridheight = 1;
c.gridwidth = 4;
c.ipadx = 500;
panel.add(label1, c);
JLabel xxx = new JLabel("");
c.gridx = 0;
c.gridy = 4;
c.gridwidth = 3;
c.fill = GridBagConstraints.HORIZONTAL;
c.ipadx = 550;
panel.add(xxx, c);
JButton start = new JButton("<html><p><b>Start</b></p></html>");
c.gridx = 3;
c.gridy = 4;
c.gridwidth = 1;
c.ipadx = 1;
c.anchor = GridBagConstraints.LINE_END;
panel.add(start, c);
JLabel msg1 = new JLabel(
"<html><p style = 'background-color: white; font-size: 10px'>Click on Start to begin.</p></html>");
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 1;
c.gridheight = 3;
c.gridwidth = 4;
panel.add(msg1, c);
JLabel msg2 = new JLabel(
"<html><p style = 'background-color: white; font-size: 10px'>Ok, let's begin.</p><p style = 'background-color: white; font-size: 10px'>First question: Is your number even?</html>");
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 1;
c.gridheight = 3;
c.gridwidth = 4;
panel.add(msg1, c);
Moteur moteur = new Moteur();
start.addActionListener(moteur);
frame.setContentPane(contenu);
frame.setSize(700, 300);
frame.setVisible(true);
frame.setResizable(false);
}
}
You might notice that the second class has some text in french, but don't worry, it's not important. Here's my second class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Moteur implements ActionListener {
public void actionPerformed(ActionEvent e) {
msg1.setVisible(false);
msg2.setVisible(true);
}
}
In fact, I want the program to make 'msg1' visibility to false and 'msg2' visibility to true, but I can't make the program work because the second class don't know what is 'msg1' and 'msg2'. Please, help me!
Regards, -Gab
For a method to be able to use an object, it needs a reference to this object. You're creating a Moteur instance, but you don't pass any object to this Moteur instance, so it doesn't have a reference to any object except itself.
For the Moteur class to be able to call methods of msg1 and msg2, you need to pass a reference to these two objects to Moteur:
public class Moteur implements ActionListener {
private JLabel messageToHide;
private JLabel messageToShow;
public Moteur(JLabel messageToHide, JLabel messageToShow) {
this.messageToHide = messageToHide;
this.messageToShow = messageToShow;
}
public void actionPerformed(ActionEvent e) {
messageToHide.setVisible(false);
messageToShow.setVisible(true);
}
}
And then, when you create the Moteur, you give them the two labels to hide and show:
Moteur moteur = new Moteur(msg1, msg2);
Use getters and setters for msg's.
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();
}
});
}
}