Java components replacement JPanel - java

I'm trying to create an application in 3 parts : 3 labels and 3 gridlayouts. When we click on a label, the corresponding gridlayout disappear and the frame replace automatically the components at the right place. I created a simple snippet :
import java.awt.Button;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class TestLayout extends JFrame{
private JPanel content;
private JLabel[] lbl;
private JPanel[] pnl;
private Boolean[] ih;
public TestLayout(){
setTitle("Test");
setSize(new Dimension(300, 400));
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
lbl = new JLabel[3];
pnl = new JPanel[3];
ih = new Boolean[3];
content = new JPanel(new GridLayout(6, 1));
for(int i=0; i<3; i++){
lbl[i] = new JLabel("Label" + i);
lbl[i].addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
for(int i=0; i<3; i++){
if(e.getSource() == lbl[i]){
//pnl[i].setVisible(!pnl[i].isVisible());
if(ih[i]) content.remove(pnl[i]);
else content.add(pnl[i]);
ih[i] = !ih[i];
}
}
}
});
pnl[i] = new JPanel(new GridLayout(3, 3));
}
for(int i=0; i<9; i++){
pnl[0].add(new Button("" + (i+1)));
pnl[1].add(new Button("" + (i+10)));
pnl[2].add(new Button("" + (i+19)));
}
for(int i=0; i<3; i++){
content.add(lbl[i]);
content.add(pnl[i]);
ih[i] = true;
}
add(content);
setVisible(true);
}
public static void main(String[] args){
new TestLayout();
}
}
The first problem is the use of a global gridlayout which resize all the components at the same size, but I think it would be better if labels could be smaller than the grilayouts.
The second problem is that even if the gridlayout is removed or setVisible(false), it still take a blank place in the global container.
What I get :
What I was expecting :
The only thing I don't wanna use is a GridBagLayout.
I was thinking about create a method init() which one remove all components of the global container then re add all the labels and all the panels, then create another method which do the exact same as the init() method but take a number as parameter (for example 2) then re add all the components excepting the second gridlayout. But I think it's a dirty way to do that because the container will content an empty case at the end and I think there is a better way than removing and re adding all the components (which basically doesn't solve the first problem of label's size)
How can I avoid theses problems ?

Try using a vertical BoxLayout.
Read the section from the Swing tutorial on How to Use BoxLayout for more information and working examples.

Related

Java Swing: how to add multiple JPanels to a JScrollPane

On the net I read that to add a component to a JscrollPane we must perform:
scrollPane.getViewport().setView(jpanel);
Well, this is my code. To show multiple components, in this case JButtons, I am trying to add them into multiple JPanels and add these last in order at the end. But only the last JPanel is shown. Why?
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import layout.TableLayout;
public class Main {
public static void main(String argv[]) {
JFrame jframe = new JFrame("Protocollo UTL");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setSize(1200, 450);
JPanel body = new JPanel();
double[][] size = {
{0.05},
{0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05}
};
body.setLayout(new TableLayout(size));
for(int i=0; i<19; i++) {
body.add(new JButton(String.valueOf(i)), "0,"+String.valueOf(i));
}
JPanel body2 = new JPanel();
body2.setLayout(new TableLayout(size));
for(int j=0; j<6; j++) {
body2.add(new JButton(String.valueOf(j)), "0,"+String.valueOf(j));
}
JScrollPane scrollPane = new JScrollPane(body,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.getViewport().setView(body);
scrollPane.getViewport().setView(body2);
jframe.add(scrollPane);
jframe.setVisible(true);
}
}
You are overriding the first one with the second statement
scrollPane.getViewport().setView(body);
scrollPane.getViewport().setView(body2);
You should add both JPanels to some parent component, and set that component as view. Something like this:
Container cont = new Container();
cont.add(body);
cont.add(body2);
scrollPane.getViewport().setView(cont);
EDIT
I don't think you need that line (setView(...)) at all. Try this (put this instead of last four lines)
Container cont = new Container();
cont.add(scrollPane);
cont.add(body2);
cont.setLayout(new GridLayout());
jframe.add(cont);
jframe.setVisible(true);

How to implement layout?

I have a GUI program which includes JLabels and JButtons and basically I want a layout that would help me display them as follows:
Label1 Button1
Label2 Button2
Label3 Button3
.....
Is there a layout that would allow me to achieve the above result?
I have looked at this example but is too complex and was wondering if there is anything automated that I can use?
This is one of the few things for which I'd recommend (a utility method and) GroupLayout as seen in this answer.
You can use GridLayout. Documentation here.
This is just for simplicity, and for your question. GUI is really dependent on what you would like to do and is really a thing that can be hardly automated..., and i don't think you only want those 6 elements on your GUI, but theoretically this will do it:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class GUITest {
private Box labelbox = new Box(BoxLayout.Y_AXIS);
//Y_AXIS means they are placed vertically in the box
private Box buttonbox = new Box(BoxLayout.Y_AXIS);
private JFrame frame = new JFrame();
private JPanel panel = new JPanel();
public void makeGUI1() {
for (int i = 1; i <= 3; i++) {
//if you want to save the references, you should make
//an ArrayList<JLabel> and add each of them to it
JLabel label = new JLabel("Label " + i);
labelbox.add(Box.createVerticalStrut(5));
//these are for giving the labels some extra space
//between them vertically to be in line with the buttons
labelbox.add(label);
labelbox.add(Box.createVerticalStrut(10)); //these are too
}
for (int i = 1; i <= 3; i++) {
//if you want to save the references, you should make
//an ArrayList<JButton> and add each of them to it
JButton button = new JButton("Button " + i);
buttonbox.add(button);
}
panel.add(labelbox, BorderLayout.EAST);
//you can find picture of each constant:
//http://download.java.net/jdk7/archive/b123/docs/api/java/awt/BorderLayout.html
panel.add(buttonbox, BorderLayout.WEST);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
GUITest guitest = new GUITest();
guitest.makeGUI1();
}
});
}
}
You can also use obj.setBounds(LeftSpaceParameter,TopSpaceParameter) with which you can place the gui elements or objects at any position of your choice. You need to put the default layout to null
yet gridLayout is much easier. .

Nested JScrollPane not fitting

I'm having an issue with nested JScrollPanes. Basically I want to have one outer JScrollPane that scrolls vertically but not horizontally (Think the Netflix web interface). Inside this outer JScrollPane I want to have multiple JScrollPanes that scroll horizontally. My problem is that horizontal scrollbars for the inner JScrollPanes never show up as it looks like they take up the entire preferred size of their JPanels. Here is an image to describe what I am talking about:
EDIT: This code based on camickr's answer is now working:
import java.awt.BorderLayout;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class NestedScrollPane extends JFrame {
public NestedScrollPane() {
ScrollablePanel outerPanel = new ScrollablePanel();
outerPanel.setScrollableWidth(ScrollablePanel.ScrollableSizeHint.FIT);
outerPanel.setLayout(new BoxLayout(outerPanel, BoxLayout.Y_AXIS));
for (int j = 0; j < 20; j++) {
ScrollablePanel innerPanel = new ScrollablePanel();
innerPanel.setScrollableHeight(ScrollablePanel.ScrollableSizeHint.NONE);
innerPanel.setLayout(new BoxLayout(innerPanel, BoxLayout.X_AXIS));
JScrollPane innerScrollPane = new JScrollPane(innerPanel);
innerScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
for (int i = 0; i < 10; i++) {
JLabel longLabel = new JLabel("asefaesfesfesfgesgersgrsgdrsgdrsgderg ");
innerPanel.add(longLabel);
}
outerPanel.add(innerScrollPane);
}
JScrollPane outerPane = new JScrollPane(outerPanel);
outerPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
this.setContentPane(outerPane);
this.setSize(400, 400);
outerPane.setSize(400, 400);
this.setVisible(true);
}
public static void main (String[] args) {
NestedScrollPane pane = new NestedScrollPane();
pane.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I took a look at How to get JScrollPanes within a JScrollPane to follow parent's resizing but using BoxLayout or BorderLayout on the outer panel doesn't seem to fix anything.
You need to implement the Scrollable interface of the outer panel added to the viewport to force the panel to fill the width of the viewport.
An easy way to do this is to use the Scrollable Panel. You should be able to use:
// JPanel outerPanel = new JPanel();
ScrollablePanel outerPanel = new ScrollablePanel();
outerPanel.setScrollableWidth( ScrollablePanel.ScrollableSizeHint.FIT );

Why doesn't my JFrame show up?

I'm trying to make a solved sudoku puzzle show up in a window with 81 boxes. I did this:
import java.awt.GridLayout;
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class GraphicSolver extends JFrame {
GraphicSolver(int[][] spelplan) {
Panel panel = new Panel(new GridLayout(9,9));
for(int i=9;i<9;i++){
for(int x=0;x<9;x++){
panel.add(new JLabel(""+spelplan[i][x]));
}
}
Frame frame = new Frame();
frame.add(panel);
frame.setVisible(true);
}
}
However, it only gives me an empty window without any numbers. I'd be pleased if someone could point me in the right direction.
The outer loop should start at zero:
for(int i=0;i<9;i++){
You seem to have two Frames. 1 is the JFrame (the class GrpahicSolver itself) and the other a frame that you are creating within it.
I suggest you replace frame.addPanel() with this.addPanel() and it should work.
Try calling frame.pack (), this will pack all the components into the frame to be displayed after computing the correct size with the panels. Also, follow the fix suggested by #trashgod above will solve the fact that no panels were added, and the fix by #Ashkan Aryan will make your code a bit more reasonable (although it should work without it, but then there is no point in inheriting from JFrame).
The code below works for me:
GraphicSolver(int[][] spelplan) {
Panel panel = new Panel(new GridLayout(9,9));
for(int i=0;i<9;i++){
for(int x=0;x<9;x++){
panel.add(new JLabel(""+spelplan[i][x]));
}
}
this.add(panel);
this.pack ();
this.setVisible(true);
}
import java.awt.GridLayout;
import javax.swing.*;
public class GraphicSolver {
GraphicSolver(int[][] spelplan) {
// presumes each array 'row' is the same length
JPanel panel = new JPanel(new GridLayout(
spelplan.length,
spelplan[0].length,
8,
4));
for(int i=0;i<spelplan.length;i++){
for(int x=0;x<spelplan[i].length;x++){
panel.add(new JLabel(""+spelplan[i][x]));
}
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
int[][] plan = new int[4][7];
for (int x=0; x<plan.length; x++) {
for (int y=0; y<plan[x].length; y++) {
plan[x][y] = (x*10)+y;
}
}
new GraphicSolver(plan);
}
});
}
}

How can I make MiGLayout behave like Wrap Layout?

I'd like to replicate the example shown here:
Wrap Layout
Using MiGLayout. I have tried some combinations, but I'm
having a hard time making the buttons wrap automatically
to new rows as the container shrinks.
Could someone please provide a working example doing this?
Here is a shell for the program:
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
public class MiGTest extends JFrame{
private JPanel jPanel;
private JButton jButton;
public static void main(String[] args) {
new MiGTest().setVisible(true);
}
public MiGTest(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new MigLayout("debug"));
initComponents();
addComponents();
pack();
}
private void addComponents() {
add(jPanel);{
for (int i = 0; i < 10; i++) {
jPanel.add(new JButton("" + i));
}
}
}
private void initComponents() {
jPanel = new JPanel(new MigLayout("debug"));
jButton = new JButton("Test");
}
}
According to the creators of MiGLayout and the answers to the following questions:
http://migcalendar.com/forums/viewtopic.php?f=8&t=3421
http://migcalendar.com/forums/viewtopic.php?f=8&t=2270&hilit=wrap+container
http://migcalendar.com/forums/viewtopic.php?f=8&t=2015&hilit=wrap+container
http://migcalendar.com/forums/viewtopic.php?f=8&t=1137&hilit=wrap+container
, MiGLayout quite simply doesn't support this. Neither does it support
wrapping within a single cell.
I've been declaring the .width("xx%") and then calling wrap when the row's widths add up to 100%. This works if you can declare each component to be a certain percentage of a row (they don't all have to be the same percentage).

Categories