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);
Related
I am developing a simple application, and am currently working on the gui design using Swing. In my program I have a JPanel which I would like to have a background color black like so:
JPanel playerPanel = new JPanel();
playerPanel.setOpaque(true);
playerPanel.setBackground(Color.BLACK);
This code works fine. However, the problem is when I assign a Layout Manager to the panel:
JPanel playerPanel = new JPanel();
playerPanel.setOpaque(true);
playerPanel.setBackground(Color.BLACK);
playerPanel.setLayout(new BoxLayout(playerPanel, BoxLayout.PAGE_AXIS));
For some reason, this makes the black color of the panel go away. This happens no matter where I place the .setLayout(...) command, before or after the .setBackground(...) and .setOpaque(true).
Why is this, and how do I work around this? How do I keep a black JPanel that uses a BoxLayout manager?
Verify that your panel's content is not obscuring the altered background. Resize the example below, which I've artificially enlarged, to see the effect.
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Random;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
* #see https://stackoverflow.com/a/57785802/230513
*/
public class BoxTest {
public static final Random random = new Random();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new BoxTest().create();
}
});
}
void create() {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.setBackground(Color.BLACK);
panel.add(Box.createVerticalGlue());
for (int i = 0; i < 4; i++) {
panel.add(new VariablePanel());
panel.add(Box.createVerticalGlue());
}
JFrame f = new JFrame("BoxTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(panel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
f.setSize(f.getWidth(), f.getHeight() + 64);
}
}
/**
* A VariablePanel has a label showing its current size,
* as well as a variable number of text items.
*/
class VariablePanel extends JPanel {
private static final String text =
"Sed ut perspiciatis unde omnis iste natus error sit.";
private final JLabel sizeLabel = new JLabel("Size:");
public VariablePanel() {
this.setLayout(new GridLayout(0, 1));
this.add(sizeLabel);
int count = BoxTest.random.nextInt(5) + 1;
for (int i = 0; i < count; i++) {
this.add(new JLabel(text));
}
this.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
int w = e.getComponent().getWidth();
int h = e.getComponent().getHeight();
sizeLabel.setText("Size: " + w + "\u00d7" + h);
}
});
}
}
Swing components (except JLabel) are opaque by default. This means:
you don't need playerPanel.setOpaque(true)
most components you add to the panel will be opaque and cover the background of your playerPanel.
Also, the BoxLayout respects the maximum size of any component you add to the panel. So if you add a component:
like a JButton which has a defined maximum size, you will see the button on top of the playerPanel and the background will surround the button.
like a JPanel, which does not have a defined maximum size, the panel will be resized to fill the entire area of the playerPanel and you won't see the background of the playerPanel.
If you want to see the background of the playerPanel show through a component added to the playerPanel, then you need to use setOpaque(false) on the component. For example:
JPanel child = new JPanel();
child.setOpaque( false );
playerPanel.add( child );
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.
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. .
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 );
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);
}
});
}
}