I am trying to create a panel, using MigLayout, divided on three rows. The first and last row should have a pushY of some ratio (in this case, 2f) and the row in between should grow as mush as possible in order to occupy the remaining space.
However, I have some cases in which the last row, for example, which is a panel on its own, will have no components in it. In this case, I want the 2nd row to occupy all the height and I can't achieve that.
Please not that making it invisible is not possible due to other flow-dependencies.
I've attached the code here:
public class TestClass {
public static void main(String[] args) {
createPanel(true);
createPanel(false);
}
private static void createPanel(boolean removeAll) {
JFrame frame = new JFrame();
JPanel panel = new JPanel(new MigLayout(new LC().fill().gridGap("0", "0").insetsAll("0")));
panel.add(new JLabel("first row"), new CC().grow().newline().pushY(2f));
JTextArea abc = new JTextArea("abc");
abc.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
panel.add(abc, new CC().push().grow().newline());
JPanel pnl = new JPanel(new MigLayout(new LC().fill().gridGap("0", "0").insetsAll("0")));
pnl.add(new JLabel("aaa"), new CC());
pnl.add(new JLabel("bbb"), new CC().newline());
pnl.add(new JLabel("ccc"), new CC().newline());
panel.add(pnl, new CC().grow().newline().pushY(2f));
if (removeAll) {
pnl.removeAll();
}
frame.setContentPane(panel);
frame.setSize(100,800);
frame.setVisible(true);
}
}
Use dock feature for that, so top will dock in north, bottom in south, and middle row will grow between them. http://www.miglayout.com/QuickStart.pdf check the page no.5 for docking tutorial.
Related
I have an assignment which requires me to create the layout that you see in the image as part of the development of a game. I've never worked with Java for desktop applications before so i'm a complete noob when it comes to using the Swing & AWT libraries. The image suggests that we use a JLayeredPane as our root container and then add the rest on top of it. My issue is that i've tried starting with the background image and the gridLayout but i can't seem to make anything other than the background show up. The grid doesn't show up at all (no border line, no background of the cells) and any other component i've added to it has failed. Can somebody point me in the right direction here? I've read the docs & saw some example of various layouts,containers and components but i can't seem to make all of them work together.
Here's my code so far:
public class BoardView extends JFrame{
// Constructor
public BoardView() {
JFrame window = new JFrame("Sorry Game"); // create a new Jwindow instance
ImageIcon appIcon = new ImageIcon(getClass().getClassLoader().getResource("res/icon.png")); // create the icon for the app
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // when the 'X' button is clicked, the app stops
window.setSize(new Dimension(1000, 700)); // setting the size of the window
window.setResizable(false); // Window won't be resizable
window.setIconImage(appIcon.getImage()); // set the icon for the app
window.setLayout(new BorderLayout());
JLayeredPane layeredPane = new JLayeredPane();
JLabel background = new JLabel();
background.setSize(1000,700);
background.setIcon(new ImageIcon(getClass().getClassLoader().getResource("res/background.png"))); for the JLabel
layeredPane.add(background,0);
JPanel gridPanel = new JPanel(new GridLayout(16,16));
gridPanel.setSize(650,700);
layeredPane.add(gridPanel);
for(int i = 0; i < 256; i++) {
JLabel tile = new JLabel();
tile.setBackground(Color.red);
tile.setBorder(new LineBorder(Color.black));
gridPanel.add(tile);
}
JLabel logo = new JLabel();
logo.setIcon(new ImageIcon(getClass().getClassLoader().getResource("res/sorryImage.png")));
layeredPane.add(logo);
window.add(layeredPane);
window.setLocationRelativeTo(null); // centers the window to the screen
window.setVisible(true); // make the window visible
}
}
My thought process was that i could set the JFrame's layout to a BorderLayout so that i can brake the final layout down into two parts, the West one and the East one. The West one would contain the Grid and the various JLabels and Buttons and the East one would contain the rest of the components. I've tried using the BorderLayout.WEST & EAST parameters when adding components to the JFrame but none has worked or changed a single thing. I've also tried using an index for the depth when adding components to the JLayeredPane as per the docs but again nothing changes.
P.S. Please note that i'm not looking for someone to create the layout for me. I want someone to help me understand what i'm doing wrong and what the best way of creating such layouts is.
In order to initialize the cells of the grid that i want to have images in, don't i need to add them manually in those positions?
If you use a GridLayout every cell must have a component and the components must be added in sequential order. That is as components are added they will wrap automatically to the next row as required.
So even if you don't want an image in a cell you would need to add a dummy component, lets say a JLabel with no text/icon.
An easier approach might be to use a GridBagLayout. The GridBagLayout can be configured to "reserve" space for cells that don't have components. So you can add a component to a specific cell.
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
public class GridBagLayoutSparse extends JPanel
{
public GridBagLayoutSparse()
{
setBorder( new LineBorder(Color.RED) );
GridBagLayout gbl = new GridBagLayout();
setLayout( gbl );
/*
// Set up a grid with 5 rows and columns.
// The minimimum width of a column is 50 pixels
// and the minimum height of a row is 20 pixels.
int[] columns = new int[5];
Arrays.fill(columns, 50);
gbl.columnWidths = columns;
int[] rows = new int[5];
Arrays.fill(rows, 20);
gbl.rowHeights = rows;
*/
// Add components to the grid at top/left and bottom/right
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = 0;
addLabel("Cell 0:0", gbc);
gbc.gridx = 3;
gbc.gridy = 4;
addLabel("Cell 3:4", gbc);
}
private void addLabel(String text, GridBagConstraints gbc)
{
JLabel label = new JLabel(text);
label.setBorder( new LineBorder(Color.BLUE) );
add(label, gbc);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("GridBagLayoutSparse");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout( new GridBagLayout() );
frame.add(new GridBagLayoutSparse());
frame.setSize(300, 300);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}
Run the code as is and the components will be grouped together in the center.
Uncomment the block comment and run again. The components will be positioned in the appropriate cell.
This question already has answers here:
Java: vertical alignment within JPanel
(3 answers)
Closed 4 years ago.
the task i am trying to do is simple. I want to add JButtons to a panel in a vertical way, but using a loop to adding it, i tried to do it using .setBounds() and .setLocation() mehtod, but i dont have any results.
In a simple way, i want to do this but adding the buttons vertically and keeping the JScroll bar...:
public class NewMain {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
frame.setLayout(null);
for (int i = 0; i < 10; i++) {
JButton asd=new JButton("HOLA "+i);
asd.setLocation(i+20, i+20);
panel.add(asd);
}
JScrollPane scrollPane = new JScrollPane(panel);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setBounds(50, 30, 300, 50);
JPanel contentPane = new JPanel(null);
contentPane.setPreferredSize(new Dimension(500, 400));
contentPane.add(scrollPane);
frame.setContentPane(contentPane);
frame.pack();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
Give the JPanel that holds the JButtons an appropriate layout manager that adds components in a vertical manner. A GridLayout(0, 1) would work, the parameters referring to 0 rows -- meaning variable number of rows, and 1 column. This will add the JButtons into a vertical grid, column of one
Other possible solutions include BoxLayout and GridBagLayout, both of which are a little more complex than the GridLayout.
Also avoid using null layouts as you're doing as this leads to inflexible GUI's painful debugging and changes.
I'm looking at the How To Use BoxLayout documentation, which clearly says that
What if none of the components has a maximum width? In this case, if
all the components have identical X alignment, then all components are
made as wide as their container.
Let's assume we're adding a lot of JButton instances to a JPanel. If the maximum width of these buttons are none AND we invoke setAlignmentX(Component.LEFT_ALIGNMENT) on all of these buttons - then each of these buttons should stretch across its entire row. The documentation even illustrates this using the below picture.
I can't get this to work!
I've tried doing setMaximumSize(null) and setMaximumSize(new Dimension(-1,-1)) and setMaximumSize(new Dimension(0,0)) on the buttons but nothing gives me the described behaviour.
What excactly does the documentation mean when it says :
What if none of the components has a maximum width?
What is a maximum width of none?
The best I've been able to produce is the below. Reading the documentation I would expect that the buttons should be able to stretch across their entire rows. I know I can use other layout managers as well for this, but I would like to achieve this with BoxLayout (granted the documentation is right / I've understood the documentation right).
public class CustomList extends JPanel {
private final Box box = Box.createVerticalBox();
public CustomList() {
for (int i = 0; i < 10; i++) {
JButton b = new JButton("Button item" + i);
//b.setMaximumSize(new Dimension(0,0));
b.setAlignmentX(Component.LEFT_ALIGNMENT);
box.add(b);
}
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(box, BorderLayout.CENTER);
}
public static void main(String[] args) {
CustomList l = new CustomList();
l.setSize(200, 200);
l.setBackground(Color.red);
JFrame frame = new JFrame("Vertical Box");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(l, BorderLayout.CENTER);
frame.setSize(300, 200);
frame.setVisible(true);
}
}
Your buttons actually have a maximum width.
What you can do is create JPanel objects with BorderLayout in your loop, add each button to each panel (to BorderLayout.CENTER, which is the default anyway).
BorderLayout.CENTER doesn't care about the maximum size of its child Component, so you end up with a JPanel whose whole content is filled by a JButton.
Since the JPanel itself has a huge default maximum size of new Dimension(Short.MAX_VALUE, Short.MAX_VALUE) (this is width=32767,height=32767 !!) which is the default maximum size of Component, you will get the expected result :
public CustomList() {
for (int i = 0; i < 10; i++) {
JPanel panel = new JPanel(new BorderLayout());
JButton b = new JButton("Button item" + i);
//b.setMaximumSize(new Dimension(0,0));
b.setAlignmentX(Component.LEFT_ALIGNMENT);
panel.add(b);
box.add(panel);
}
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(box, BorderLayout.CENTER);
}
The following code lays out the JLabels using the GridLayout. The arguments to the GridLayout are the following: rows, cols, horizontal gap, vertical gap. In the example below I have 3 pixels wide gap between labels both vertically and horizontally.
To use images instead of numbers, you could pass an ImageIcon to the constructor of the JLabel instead of the text.
import java.awt.GridLayout;
import javax.swing.*;
import javax.swing.border.BevelBorder;
public class FrameTest {
public static void main(String[] args) {
final JFrame f = new JFrame("Frame Test");
JPanel panel = new JPanel(new GridLayout(4, 4, 3, 3));
for (int i = 0; i < 16; i++) {
JLabel l = new JLabel("" + i, JLabel.CENTER);
// JLabel l = new JLabel(new ImageIcon("image_file.png"),
// JLabel.CENTER);
l.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
l.setFont(l.getFont().deriveFont(20f));
panel.add(l);
}
f.setContentPane(panel);
f.setSize(200, 200);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
in that code the applets build up like a stack , but I want to make it replaceable like if I have a moving robot and I only want to replace the label where the robot moves instead of building a whole new grid ? or can I do that with any other GUI in java ?
First of all, I'd suggest to use an array of JLabel to keep track of the references of each label.
JLabel[] labels = JLabel[16];
Then, when an event happens, you could use the JLabel#setIcon method to change the Icon dynamically.
I have to do make a program that has to be able to show a matrix in form of Jtextfields or Jtextareas, so that the user can write in them(a number of the matrix for each Jtextfield).
The problem is that I have no idea how to create a custom JPanel with the size and quantity of Jtextfields that the user specifies(a different each time).
I have already googled the question, to no avail.
Take a look at GridLayout. It is pretty simple to put together a grid together with a couple params (row and col count). To paraphrase from the JavaDoc:
public static void main (String[] args) {
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(3,2));
panel.add(new JTextField("1"));
panel.add(new JTextField("2"));
panel.add(new JTextField("3"));
panel.add(new JTextField("4"));
panel.add(new JTextField("5"));
panel.add(new JTextField("6"));
would result in a 3 row by 2 col grid of JTextFields
EDIT:
here is some more, in a class named Demo:
public class Demo {
public static void main(final String[] args) {
if (args.length < 2) {
System.out.print("please enter row and col on commandline");
}
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new Demo(Integer.parseInt(args[0]), Integer.parseInt(args[1]));
}
});
}
public Demo(int colCnt, int rowCnt) {
JFrame frame = new JFrame("Demo");
frame.setSize(600, 600);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(colCnt,rowCnt));
for (int i =0; i < rowCnt*colCnt; i++) {
panel.add(new JTextField(""+i));
}
frame.setContentPane(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
First of all, I would build a 2d array of the text fields\areas. When you get the user input you can then initialize the arrays and "new up" all of the widgets. After adding all of them to the parent panel\frame you may have to do some calculation based on the used up size and resize your top level window. Aside from that, as already suggested, GridLayout will be a good choice for the direct parent component.
Hope this helps.
To change the appearance at runtime, all you need to do is replace the content with new components.
So depending on how you get your input, you replace the numbers given in akf's answer with the input.
panel.setLayout(new GridLayout( rows, columns));
and then to show the new panel you add it in the JFrame with
add( panel );
Your assignment however might be something along the lines of subclassing a JPanel to show a matrix. I get that impression in your wording. Then its a whole different solution.
If your only goal is to implement a matrix where you can edit values a JTable is by far the simplest. Put the following in a JFrame
DefaultTableModel data = new DefaultTableModel(3 , 3);// rows, cols
JTable table = new JTable(data);
add(table);
pack();
setVisible(true);
This would also simplify modifying the height and width of the matrix by using data.setRowCount( newValue ).