Gridlayout makes its own margin - java

I had been making game with grid gui and I made MyPanel, which extends JPanel to display bg image, and own Buttons. The problem is, when I make gridlayout, which is larger than 12x12 then it makes its own margin:
Image on left is <=13 case and buttons fit perfectly, when in image on right, case >13 there is small margin, which I can't get rid of . Code:
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
MyPanel panel = new MyPanel();
panel.setBounds(10, 10, 360, 360);
frame.getContentPane().add(panel);
panel.setLayout(new GridLayout(size,size));
buttons = new Button[size][];
for(int i=0;i<size;i++)
{
buttons[i] = new Button[size];
for(int j=0;j<size;j++)
{
buttons[i][j] = new Button();
panel.add(buttons[i][j]);
}
}
}

Don't use a null layout!
The point of using a layout manager is that the layout manager will determine the size of the panel.
Then you just use pack() on the frame and all the components will be displayed at their preferred size.
Also, don't use Button, that is an AWT component. Swing components start with "J" so you should be using JButton.

Related

Adding JScrollPane to JPanel with another panels inside

i been working on some bigger project lately but couldn't figure it out why JScrollPane wouldn't work. I have never used it before and I read many solved problems about it on stackOverflow and other programming forums but non of the code were looking similar to mine to help me implement my method.
this is new project i made to make it short and show some examples.
Red colour is main panel that will contain another panel/JScrollPane inside that will be colour black
and i would like to make this Jpanel with colour black to be scrollable and hold any number of that white JPanels that might be from 0 to a 100+
public class ScrollablePane {
private JFrame frame;
private JPanel panelCopy;
private JPanel panel;
private JPanel container;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ScrollablePane window = new ScrollablePane();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public ScrollablePane() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
panel = new JPanel();
panel.setBackground(Color.RED);
panel.setBounds(0, 0, 434, 261);
frame.getContentPane().add(panel);
panel.setLayout(null);
container = new JPanel();
container.setBackground(Color.BLACK);
container.setBounds(10, 10, 414, 241);
container.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));
panel.add(container);
for(int i = 0; i < 20; i++) {
if(i > 0) {
panelCopy = new JPanel();
panelCopy.setPreferredSize(new Dimension(400, 40));
container.add(panelCopy);
}
}
}
}
if you want to use a JScrollPane, then your code actually needs to use a JScrollPane. The code you posted doesn't even create a JScrollPane.
If you want the panels to display vertically then don't use a FlowLayout. The FlowLayout is a horizontal layout. You could use a BoxLayout or a GridBagLayout.
Why do you create the "panel" variable and add it the the content pane? The content pane of the frame already is a JPanel that uses a BorderLayout. There is no need to add another panel
Don't use a null layout!!! Swing was designed to be used with layout managers. Scrolling won't work if the panel added to the scroll pane uses a null layout.
So in your case the basic logic might be something like:
Box container = Box.createVerticalBox();
// add you child panels to the container.
JPanel wrapper = new JPanel( new BorderLayout() );
wrapper.add(container, BorderLayout.PAGE_START);
JScrollPane scrollPane = new JScrollPane(wrapper);
frame.add(scrollPane, BorderLayout.CENTER);
Note the "wrapper" panel is used to prevent the panels from expanding in size when the scroll pane is larger then the preferred size of the "container" panel.
Try:
//JScrollPane scrollPane = new JScrollPane(wrapper);
JScrollPane scrollPane = new JScrollPane(container);
to see the different result.

Set margin about a JPanel of GridLayout in Swing

I'm trying to setup the margin about the JPanel that it has inside the GridLayout refer to the JFrame, but I don't found the solution using other answer. I don't know if it's important problem, but also it show only the first button before I go to each button with mouse.
The image is an example, I want to setup the JPanel to start from the corner of the grid of image, because the image has a border (not from code, but from decoration board), the blue squares are the button inside the GridView, but I'm trying to fit the gridView to the image draw grid, using the set property (using proportion of pixel).
public class Gui extends JPanel implements View {
private final JPanel gui = new JPanel(new BorderLayout(3, 3));
private JButton[][] chessBoardSquares = new JButton[5][5];
private JPanel chessBoard;
private ImageIcon ArrayWithoutPlayer[] = new ImageIcon[7]; //{1,2,3,4,10,11,12}
private ImageIcon ArrayWithPlayer[] = new ImageIcon[3]; //{1,2,3}
private JFrame frame; //This is the whole frame
public Gui() {
createAndShowGUI();
}
private void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("TextDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Display the window.
frame.setSize(800, 800);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
//frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
//frame.pack();
frame.getContentPane().add(new ImagePanel( setImageIconFromUrl("/home/amministratore/Documenti/Java/ing-sw-2020-palini-rigutti-vangi/image/SantoriniBoardR.png",800,800).getImage()));
chessBoard = new JPanel(new GridLayout(0, 5));
chessBoard.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
//chessBoard.setLayout(new BoxLayout());
//chessBoard.setPreferredSize(new Dimension(400, 100));
chessBoard.setBackground(Color.blue);
//chessBoard.setAlignmentX((float) (2.2/21)*frame.getWidth());
//chessBoard.setAlignmentY((float) (2.2/21)*frame.getHeight());
//chessBoard.setMaximumSize(new Dimension((16/21)*frame.getWidth(),(16/21)*frame.getHeight()));
//chessBoard.setAlignmentX(JLabel.LEFT_ALIGNMENT);
//chessBoard.setBorder(new LineBorder(Color.BLACK));
Insets buttonMargin = new Insets(0,0,0,0);
for (int ii = 0; ii < chessBoardSquares.length; ii++) {
for (int jj = 0; jj < chessBoardSquares[ii].length; jj++) {
JButton b = new JButton();
b.setMargin(buttonMargin);
b.setBorder(null);
b.setBorderPainted(false);
b.setContentAreaFilled(false);
b.setOpaque(false);
chessBoardSquares[ii][jj] = b;
b.setText("AA");
chessBoard.add(chessBoardSquares[ii][jj]);
}
}
//chessBoard.setOpaque( false );
chessBoard.setBackground(new Color(255,0,0,0));
frame.dispose();
frame.add(chessBoard);
frame.setVisible(true);
//chessBoardSquares[0][0].setIcon( ArrayWithoutPlayer[0]); //This is the method to set Icon inside the button
}
}
I'm trying to setup the margin about the jpanel that it has inside the GridLayout
//b.setMargin(buttonMargin);
//b.setBorder(null);
//b.setBorderPainted(false);
I don't think you need all that code.
Instead just set the Border of the button:
b.setBorder( new EmptyBorder(5, 5, 5, 5) );
Edit:
frame.getContentPane().add(new ImagePanel(...));
…
frame.add(chessBoard);
First of all frame.getContentPane().add(…) and frame.add(…) is the same thing. That is the component will be added to the content pane. The second format is just a shortcut for the first.
So you are attempting to add two components to the BorderLayout.CENTER. This will not work as the BorderLayout will only support a single component in any location.
Swing was designed with a parent/child relationship so it appears you want something like:
JFrame (content pane)
ImagePanel
chessBoard
So your logic should be something like:
ImagePanel background = new ImagePanel(…);
background.setLayout( new BorderLayout() );
background.add(chessPanel, BorderLayout.CENTER);
frame.add(background, BorderLayout.CENTER);
Now you have your parent/child relationship between the components.
frame.setSize(800, 800);
Don't set the size of the frame. (800, 800) is the wrong size. If your ImagePanel is (800, 800) then the frame must be bigger because the frame also includes the title bar and the border.
So instead your logic should be:
frame.pack();
frame.setVisible(true);
The pack() method will allow the frame to determine its own preferred size AFTER all the components have been added to the frame.
Note:
In you ImagePanel class you will also need to implement the getPreferresSize() method of your Image. This will allow the pack() method to work properly. Read the section from the Swing tutorial on Custom Painting for a working example.

How to add two JPanels to a JFrame in the center?

I am creating a game which has a background image with cards displayed overtop. I would like to place the background image and cards such that they're always centered vertically and horizontally, even upon resizing the JFrame.
Currently, I am creating the cards (each a JPanel) and adding them into a container JPanel (no layout manager), then I add that Jpanel to the JFrame. After that I place the background image in a JPanel, then add that JPanel to the JFrame. The result is: The background image is hidden behind the cards and revealed when removing each card as desired. The background image is always centered but the card's JPanel does not move around upon resize. I am having a hard time getting the cards to always be centered, no matter what I try. I also need to add another JPanel to the JFrame in the South border, so that will need to work as well. I appreciate your assistance!
In the class that extends JFrame:
setSize(1060,700);
cardPanel = new JPanel();
cardPanel.setSize(1060,700);
cardPanel.setOpaque(false);
cardPanel.setLayout(null);
...card.setLocation(x, y); //loop through cards
...cardPanel.add(card); //and add each one
add(cardPanel, BorderLayout.CENTER); //add cardPanel to JFrame
//Add background image
bgPanel = new JPanel();
URL url = getClass().getResource("images/dragon_bg.png");
imgIcon = new ImageIcon(url);
JLabel background = new JLabel(imgIcon);
bgPanel.setLayout(new BorderLayout());
bgPanel.add(background);
add(bgPanel, BorderLayout.CENTER);
setVisible(true);
I would like to place the background image and cards such that they're always centered vertically and horizontally, even upon resizing the JFrame.
Then you need to use layout managers on your panels. The layout manager is responsible for redoing the layout.
How to add two JPanels to a JFrame in the center?
You could try using the OverlayLayout for this. I think the basic code would be:
JPanel contentPane = new JPanel( new GrigBagLayo9ut() );
frame.add(contentPane, BorderLayout.CENTER);
JPanel overlay = new JPanel()
overlay.setLayout( new OverlayLayout(overlay) );
contentPane.add(overlay, new GridBagConstraints()); // this should center the overlay panel
overlay.add(yourCardPanel); // you care panel must use a suitable layout
overlay.add(new JLabel() ); // use a JLabel for the background not a custom panel
I also need to add another JPanel to the JFrame in the South border,
The default layout manager for a JFrame's content pane is a BorderLayout. We already added the game panel to the center, so know you just add your other panel to the SOUTH.
If the OverlayLayout doesn't work the way you want then you will need to nest panels. Something like:
JPanel center = new JPanel( new GridBagLayout() );
frame.add(center, BorderLayout.CENTER);
JLabel background = new JLabel(...);
background.setLayoutManager( new GridBagLayout() );
center.add(background, new GridBagConstraints());
background.add(yourCardPanel, new GridBagConstraints());
Edit:
Using nested panels:
import java.awt.*;
import javax.swing.*;
public class GridBagLayoutCenter extends JPanel
{
public GridBagLayoutCenter()
{
setLayout( new BorderLayout() );
JLabel background = new JLabel( new ImageIcon("mong.jpg") );
background.setLayout( new GridBagLayout() );
add(background, BorderLayout.CENTER);
JPanel tiles = new JPanel();
tiles.setPreferredSize( new Dimension(200, 200) );
tiles.setBackground( Color.RED );
background.add(tiles, new GridBagConstraints());
add(new JLabel("SOUTH"), BorderLayout.SOUTH);
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("GridBagLayoutCenter");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new GridBagLayoutCenter() );
frame.setSize(400, 400);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
The preferred size of the "tiles" panel should not be hardcoded. The size should be determined by your custom layout manager based on the tiles that you add to the panel. The size should not change as tiles are removed.
I ultimately decided to place the background image in the card panel itself, then put the card panel in a box layout manager so that it's always centered. I renamed cardPanel to gameBoard. Definitely could be cleaner, but I can only work with my requirements.
setSize(new Dimension(1000, 600));
gameBoard = new JPanel();
gameBoard.setLayout(null);
gameBoard.setOpaque(false);
Dimension expectedDimension = new Dimension(920, 500);
gameBoard.setPreferredSize(expectedDimension);
gameBoard.setMaximumSize(expectedDimension);
gameBoard.setMinimumSize(expectedDimension);
//add cards to gameBoard here
JLabel background = new JLabel( new ImageIcon( getClass().getResource("images/graphic.png") ) );
background.setLocation(79,0); //manually center graphic
background.setBounds(new Rectangle(0, 0, 920, 500));
gameBoard.add(background);
Box centerBox = new Box(BoxLayout.Y_AXIS);
centerBox.setOpaque(true);
centerBox.setBackground(Color.WHATEVER);
centerBox.add(Box.createVerticalGlue());
centerBox.add(gameBoard);
centerBox.add(Box.createVerticalGlue());
add(centerBox);
setVisible(true);

JFrame setComponentZOrder() changes size of the objects

I'm trying to write an undecorated JFrame. I'm trying to put my button over my background label. However setting the button's Z order causes the button streches to size of jframe and neither setBounds() nor setSize() changes the situation. Here is my code:
import javax.swing.*;
public class MyApp {
public static void main(String[] args) {
JFrame mainFrame = new JFrame();
mainFrame.setBounds(0, 112, 100, 50);
mainFrame.setLayout(null);
mainFrame.setUndecorated(true);
JLabel lblBackground = new JLabel(new ImageIcon(JFrame.class.getResource("/res/green.png")));
lblBackground.setBounds(0, 0, 100, 50);
JButton btnStart = new JButton("");
btnStart.setBounds(5, 15, 10, 15);
mainFrame.add(lblBackground);
mainFrame.add(btnStart);
mainFrame.setComponentZOrder(btnStart, 0);
mainFrame.setComponentZOrder(btnStart, 1);
mainFrame.setVisible(true);
}
}
Thanks for replies.
Use a JLayeredPane for this.
You will need to create a new JLayeredPane:
JLayeredPane layered = new JLayeredPane();
Set your JFrame to use this as a content pane:
mainFrame.setContentPane(layered);
And add your components, in this format:
layered.add(Component c, int layerNumber);
Hope that works for you!
More on JLayeredPanes
Don't play with null layouts. Swing was designed to be used with layout managers
Add the button to the label. For example:
JLabel label = new JLabel(...);
label.setLayout( new FlowLayout() );
JButton button = new JButton(...);
label.add( button );
frame.add(label);
frame.pack();
frame.setVisible(true);
Now the frame should be the same size as your image. The button should be centered on the top of the image. If you want the button positioned somewhere else then use a different layout manager.

Swing: Showing a transparent Panel hovering over another Panel

I want to show a textArea showing some text (will show log lines) , and have an animated gif hoovering above it. I tried the solution described here , but all I get is a grey screen. Hints?
public class TestLayeredPanes {
private JFrame frame = new JFrame();
private JLayeredPane lpane = new JLayeredPane();
public TestLayeredPanes() {
frame.setPreferredSize(new Dimension(600, 400));
frame.setLayout(new BorderLayout());
frame.add(lpane, BorderLayout.CENTER);
//Build the animated icon
JLabel buildingIcon = new JLabel();
buildingIcon.setIcon(new ImageIcon(this.getClass().getResource(
"/com/ct/tasks/cmviewer/gui/progress_bar.gif")));
JPanel iconPanel = new JPanel();
iconPanel.add(buildingIcon);
//Build the textArea
JTextArea textLog = new JTextArea("Say something");
JPanel textPanel = new JPanel();
textPanel.add(new JScrollPane(textLog));
//Add the panels to the layered pane
lpane.add(textPanel, 0);
lpane.add(iconPanel, 1);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new TestLayeredPanes();
}
}
Try putting your animated GIF on the glass pane of your root pane:
http://download.oracle.com/javase/tutorial/uiswing/components/rootpane.html
JXLayer make easier to do that. Look at JXLayer samples.
You also can take a look at code of XSwingX
Since you started with a working example, why did you remove lines of code from the example you copied?
Layered panes don't use a layout manager therefore the size of your components are (0, 0), so there is nothing to display. The setBounds(...) method in the example are there for a reason.

Categories