So I'm developing an application. I have a huge problem, and I know I'm probably overlooking something stupid, but my scollpanes aren't scrolling. Could someone please checkout the following code and tell me what I did wrong?
rotationPanel = new JPanel();
rotationPanel.setLayout(null);
rotationLabels = new JLabel[countStarters(team)];
resetXY(5,5);
for(int i = 0; i < countStarters(team); i++){
rotationLabels[i] = new JLabel(team.rotation.get(i).getName());
rotationLabels[i].setForeground(Color.BLACK);
addComp(rotationLabels[i], rotationPanel, labelX, labelY, labelSize);
labelY += 25;
}
//Other Code in between
rotationBar = new JScrollPane(rotationPanel);
rotationBar.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
rotationBar.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
rotationBar.setPreferredSize(new Dimension(520, 150));
addComp(rotationBar, this, 15, 75, new Dimension(520, 150));
//addComp method:
public void addComp(JComponent comp, JComponent panel, int xPos, int yPos, Dimension size){
comp.setLocation(xPos,yPos);
comp.setSize(size);
panel.add(comp);
}
The resetXY() method just sets the x and y position for the components
Any help would be appreciated
Cheers,
Dave
JScrollPane uses either the components preferredSize or if implemented Scrollable#getPreferredScrollableViewportSize to determine what size the scroll pane and its view port can be. When the viewport is larger the the scroll pane, the scroll bars will appear
The Swing API has being designed around the use of the layout manager, choosing to do without the will cause you no end of problems and additional work.
Layout managers help you over come the difference between systems, including font rendering, DPI, screen sizes and rendering pipelines to mention a few.
I think your JPanel needs to have its size set, otherwise it will shrink to fit the JScrollPane.
Related
So my problem is this: I have a class extending JProgressBar and basically it looks like a flashing circle(it also breaks into segments depending on the amount of tasks, assigned to that indicator and I need to use setUI each time I switch indicator to the next task, which is pretty bad, but it'll do for now). I need to position 37 of those circles on a JPanel so that they form a circle of their own. Right now I do it like this:
private void addToPane(JPanel pane){
pane.setLayout(null);
Insets insets = pane.getInsets();
int width = pane.getWidth();
int height = pane.getHeight();
Dimension size = new Dimension(30, 30);
//Dimension mid = new Dimension(width/2, height/2);
Dimension mid = new Dimension(200, 250);
int r = 210;
double revox, revoy, angle = -Math.PI/2;
double revangle = 2*Math.PI/37;
for(int i=1; i<38; i++){
FlashingIndicator templabel = new FlashingIndicator();
templabel.setPreferredSize(size);
templabel.setUI(new ProgressIndicator(flash, 0, false));
templabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
indicate.add(templabel);
revox = r*Math.cos(angle);
revoy = r*Math.sin(angle);
indicate.get(i - 1).setBounds(insets.left + mid.width + (int) revox, insets.top + mid.height + (int) revoy, size.width, size.height);
pane.add(indicate.get(i - 1));
angle-=revangle;
}
}
No need to say: this is pretty bad. I wanted to locate them depending on the size of the panel, but when the function is being called in createUIComponents() (I use IntelliJ Idea's GUI builder) - the panel is not properly created yet, so getWidth() just returns 0. Using random numbers like 200 and 250 is bad for the obvious reasons. Also seems like the general consensus is: Null Layout is bad and I shouldn't use it. So here's the question:
Which LayoutManager should I use in order to locate indicators properly? All I can think of is GridLayout, but the way I do it now indicators nicely overlap a bit, using a grid will make it look rough. And if I can't use managers for this - how can I make it dependnant on the size of the panel?
Right now it looks like this:
Override the paintDeterminate() method in a custom BasicProgressBarUI to render your indicator; a related example is seen here. You can scale the rendering, as shown here, in a way that fills the component; this will obviate the need for a custom layout manager internal to your component. Override getPreferredSize(), as discussed here, so that your custom progress indicator works correctly with enclosing layouts.
I have a 4x4 gridlayout and I'm trying to add 2 title bars above the tables I've created. I'm creating panels for title bars but because of the gridlayout it fills up all the space. Here's the code:
private WebScrollPane createPosRiskPanelWindow(int w, int h)
{
//Content area
posRiskPanel = new WebPanel((new GridLayout(2,2)));
posRiskPanel.setBackground(Color.WHITE);
//Add title bars
WebPanel posTitle = new WebPanel(new WebLabel("Current Positions"));
posRiskPanel.add(posTitle);
WebPanel riskTitle = new WebPanel(new WebLabel("Risk Exposure"));
posRiskPanel.add(riskTitle);
//Panels
CreatePositionPanel(posRiskPanel);
CreateRiskParamsPanel(posRiskPanel);
//Scroll content
posRiskScroll = new WebScrollPane (posRiskPanel, false);
posRiskScroll.setPreferredSize (new Dimension (w, h));
return posRiskScroll;
}
And here's what it looks like:
Is there a way I can resize those top 2 boxes?
Don't use GridLayout for the overall layout, since the only thing it knows to do is to create cells that are all exactly the same size. Since you don't want this, your GUI will require a different layout. Instead use GridBagLayout or else you could use nested JPanels with differing layouts, but I think that GridBagLayout for the overall layout is likely your best bet here. Other considerations include MigLayout if you're willing to use a 3rd party library.
I found it easier to just put the tables in their own panel and a titled border like so:
I'm adding a quantity of JTextField to a panel, and all of them are added but, the last one added takes the whole panel and seems all other text boxes added on the last one..... here is the code
public JPanel crearCartonFormulario() {
panel = new JPanel();
panel.setLayout(new BorderLayout());
JTextField[] textBoxes = new JTextField[25];
int cont = 0;
int posX = 10;
int posY = 0;
llenarArreglo();
while (cont <= 4) {
for (int i = 0; i <= 4; i++) {
if (cont == 2 && i == 2) {
textBoxes[i] = new JTextField("");
} else {
textBoxes[i] = new JTextField(String.valueOf(numeros[cont][i]));
}
textBoxes[i].setBounds(i + posX, 15 + posY, 40, 40);
textBoxes[i].setEditable(false);
panel.add(textBoxes[i]);
posX += 50;
}
posY += 50;
posX = 10;
cont++;
}
return panel;
}
This is returned at a panel where I keep multiple panels of this one, it works but in this one the last JTextField takes the whole panel space....
The new JFrame that contains the panels created by the method, adopt the last JTextField size and that text box doesn't take the bounds indicated by the method, but all the other text boxes still inside and correctly added.
panel.setLayout(new BorderLayout());
You are using a BorderLayout.
panel.add(textBoxes[i]);
When you use the add() method the default is to add the component to the CENTER of the BorderLayout. However, only a single component can be added to the center so the layout manager will only manage the size/location of the last component added. The rules of the BorderLayout is to make the component take up all the available space.
However, you have also used the setBounds() methods for the other text fields which is causing a problem. You should NOT attempt to use a layout manager and manage the bounds of the components yourself.
The solution is to just use a layout manager and let the layout manager do its job. Read the section from the Swing tutorial on Using Layout Managers for more information and use a more appropriate layout manager.
Update:
its a bingo table
Then maybe you shouldn't even be using JTextFields. Maybe a JTable would be a better component to use. The tutorial also has a section on How to Use Tables.
Your problem is here:
panel.setLayout(new BorderLayout());
You set the layout to BorderLayout and yet add components to the JPanel as if it were a GridLayout. Understand that when you add components to a BorderLayout-using container in a default way, the components get added in the BorderLayout.CENTER position which fills this position, covering anything added prevsiously.
Perhaps you wish to use a GridLayout instead? You will want to read the layout manager tutorial for more.
This is because you are using BorderLayout and BorderLaout Always requires a parameter like BorderLayout.CENTER, BorderLayout.WEST, BorderLayout.EAST, BorderLayout.NORTH and BorderLayout.SOUTH.
So basically BorderLayout only has 5 position where a component can go. And if you do not specify where when adding a component it defaults to BorderLayout.CENTER. And as there can only be one component at a time in the BorderLayout.CENTER position it only really adds the last one. So I'd suggest an other layout manager like GridLayout( if you want all the components to be equally sized).
I hope this helps :).
P.S. If you want me to give some explination on GridLayout just ask.
I'm trying with Swing layouts to leave a gap above controls that's calculated from the current size of the window. It basically works, except that the control only moves when the window is resized horizontally - if I resize vertically, it stays where it is - then resizing 1 pixel horizontally, it snaps into the correct place. Can anyone explain why the resizing gets ignored when I'm only resizing vertically?
I've proved the at the componentResized () is still being called on vertical resizes, and that contentPane.getWidth () and contentPane.getHeight () still give the right values. So the size of the Dimension is being set correctly, just being ignored. Its like I need to put a call into contentPane.payAttentionToUpdatesSizesOfYourComponents (), but I can't find any method that does this. contentPane.invalidate () has no effect.
Also noticed if I strip out the BorderLayout, and set the BoxLayout directly in the contentPane, then it works as I want. However while that's fine for this tiny example, the real window I have this problem on has some components in a JPanel set at NORTH with a gap above, some components in another JPanel set at SOUTH with a gap below, and a BorderLayout was the only way I could get these to position correctly so I can't strip it out.
Any advice or suggestions would be welcome!
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.Box.Filler;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public final class ResizeOnlyWorksHorizontally
{
public static final void main (final String [] args)
{
final JFrame frame = new JFrame ();
frame.setDefaultCloseOperation (WindowConstants.EXIT_ON_CLOSE);
final JPanel contentPane = new JPanel ();
frame.setContentPane (contentPane);
contentPane.setLayout (new BorderLayout ());
final JPanel top = new JPanel ();
top.setLayout (new BoxLayout (top, BoxLayout.Y_AXIS));
contentPane.add (top, BorderLayout.NORTH);
// Put a space, then a label below it
final Dimension startSpace = new Dimension (0, 0);
final Filler filler = new Filler (startSpace, startSpace, startSpace);
top.add (filler);
top.add (new JLabel ("Text"));
contentPane.addComponentListener (new ComponentAdapter ()
{
#Override
public final void componentResized (final ComponentEvent e)
{
// Just any calc based on contentPane width and height to demo problem
final int calc = (contentPane.getWidth () + contentPane.getHeight ()) / 2;
// Alter the size of the space above the label
final Dimension newSpace = new Dimension (0, calc);
filler.setMinimumSize (newSpace);
filler.setPreferredSize (newSpace);
filler.setMaximumSize (newSpace);
}
});
frame.pack ();
frame.setVisible (true);
}
}
To answer your question, you need the following after the sizes are changed to make sure the layout manager is invoked:
filler.revalidate();
However that is NOT a good solution as your entire approach to the problem is wrong. You should not be manually calculating sizes of components like that. That is the job of a layout manager. So you need to rethink your layout stategy. Don't forget you can nest panels with different layout managers.
For example if you need a changing gap in the frame then you should probably use a BoxLayout and you can add "glue" to the start and end. Or maybe you can use a GridBagLayout because you can control how components resize based on the space available.
Read the Swing tutorial on Layout Managers for more information.
It wouldn't let me put a long enough comment under your answer camickr :( I wanted to add that after posting this I also found this, similar but not identical problem with resizing BorderLayouts, and they describe a similar situation of NORTH/SOUTH positioned controls not paying attention to vertical sizing - Java Swing BorderLayout resize difficulties
I'd tried based on the replies to that to use GridBagLayout, and did get that to work after a bit of effort. Basically its a 1x5 grid layout then with cells containing (space I forcibly resize, controls, glue, more controls, space I forcibly resize), and this worked.
You should not be manually calculating sizes of components like that.
The only thing I'm manually setting the size of is the gap above+below the controls, all the controls themselves I'm letting the layout manager deal with. The size of those gaps has to match a background image on the frame which is sized to the frame but preserving aspect ratio, so the width of that border isn't something the layout manager can figure out, the real code for the 'calc' bit in my SSCCE above is:
final int edge = Math.min (contentPane.getWidth () / 4, contentPane.getHeight () / 3);
final int imgHeight = edge * 3;
final int borderSize = (contentPane.getHeight () - imgHeight) / 2;
So if the user resizes the window to be wide, there's black borders left+right of the image, and borderSize = 0. If the user resizes the window to be tall, there's black borders above+below the image, and I want the controls to avoid going there, so they always sit in the background image.
But thanks very much for the push in the right direction :)
I currently have the code below.
public class cRunningView extends JInternalFrame {
static final int xOffset = 30, yOffset = 30;
public cRunningView() {
// Get name;
super("RUNNING", true, // resizable
false, // closable
true, // maximizable
true);// iconifiable
System.out.println("##" + "p.getName()");
// ...Then set the window size or call pack...
setSize(500, 200);
// Set the window's location.
setLocation(xOffset * 0, yOffset * 0);
JScrollPane scrollPane = new JScrollPane();
}
}
My aim is to have a JInternalFrame with a number of buttons and a box/rectangle on half of the screen.
Within this box i want to be able to draw graphics for e.g. Draw oval from x,y to x,y.
I've tried looking at examples but see to get my self more confused than i did to begin. All my code is working e.g. Showing the main GUI window and my internal frame opening but i cant seem to find a good tutuirol/starting point to do graphics within a JScrollPane.
Please note i dont have to use a JScrollPane i just thought i would be a good idea cause it would give the graphics a border round it.
Before anyone moans about the question i think it is valid AND I DONT want the code to be given to me on a plate, i'd rather know and understand what im doing so i can advance my knowledge and be able to help others !
Do i have to make another class and do
JScrollPane myPane = JScrollPane(graphicsClass)
then do everything with paint() then or is there someway to create a graphic and do it without another class?
If i do :
JScrollPane scrollPane = new JScrollPane();
Graphics temp = scrollPane.getGraphics();
temp.setColor(new Color(1, 22, 33));
temp.fillOval(60, 0, 120, 60);
scrollPane.paint(temp);
It throws errors.
Thanks
You don't do Graphics in a scrollpane. Also, don't use the getGraphics() method to do custom painting.
Custom painting is done by overriding the paintComponent() method of a JPanel or JComponent. Then if required you can add the panel to a scrollpane and add the scrollpane to your frame. Don't forget to set the preferred size of the panel so scrolling will work.
Start by reading the Swing tutorial on Custom Painting.