I have been unable to sort out what combination of layout managers might produce the sort of result I have been asked to produce. I'd provide code, but nothing I have done has come close what I've been asked to implement. I thought when I started, it would be easy, but I am lost.
I have four JPanels. Behind each panel is an image specific to the panel. The JPanels need to be laid out left to right. Each panel is a different width. The JPanels contain from one to seven objects. Different panels have different objects, some have labels, some check boxes, some combo boxes and some text fields. The objects need to be padded on all sides and they need to line up properly between the panels. That is, result might look something like-
where "-" indicates either a radio button, combo box, check box or text field and "|" the different panels (each with an image). Though in practice the width of the panels needs to be quite a bit different.
I struggled with GridBagLayout inside a GridLayout(1,4) and eventually gave up, as I could never get the different objects to come out the same height, so none of the objects lined up horizontally.
I switched to what seems to me like a kludge. I made the panels each from a GridLayout(7,1) and if I had fewer than seven objects, I just padded the panel out with dummy labels.
That got me halfway to my goal. The GridLayout(7,1) panels inside a GridLayout(1,4) line up horizontally and I was able t put the images in and they resize with the panel.
I assumed it would be easy to replace my GridLayout(1,4) with something that allowed me to put the panels in such that the filled the height of the container. I assumed that if each panel was the same height, my horizontal alignment would be preserved. I just needed a container that filled the height and let the width vary and where I could add some padding.
Everything I have tried so far has been a complete failure, as soon as I put the four panels in any other type of container (tried FlowLayout, GridBagLayout, BoxLayout) the objects in the panels are no longer the same size (between panels) and horizontal alignment is completely lost. I am required to use a standard layout- is there anything that would actually work? As it is, the fields extend to the edges of the GridLayout, where I wanted to see my image as I can't see any way to pad a GridLayout on the sides when there is only one column. So I may be putting them in something else that actually has the image. Does this require some sort of container in a container in a container magic? I would love some advice.
i have never had a problem like this. i could usually find a layout or layout on top of layout that worked. the fact that there is a third party miglayout suggests there is some need for improvement in java
Thanks. I was trying something very similar to what you suggested with a GridLayout inside each panel (since a GridBagLayout seems to make radios, labels, and combo boxes different heights, but a GridLayout does not). It wasn't working for me, but I think what I did wrong was that I forgot to set the weighty. So the GridLayouts didn't fill the full height. Now that works.
What I then did was put my GridLayout panels (which will have all the pieces the same height) inside yet another GridBagLayout panel so that I could take advantage of Insets, i.e.,
Panel1 has the image attached, the other panels have setOpaque(false). The objects (check box, radio buttons, combo boxes, labels, text fields) are all the same height so that they line up and they do not extend to the edge of the images. One image basically has a central area where the objects should be placed and now at least when I invoke the window, they are in that area.
My only remaining problem, is that when I resize the window, since the inset values are fixed, the objects get too large for the part of the image area they are supposed to be contained in. The insets should really scale with the window. Would anyone know how I would do that? From where I sit, it sounds a bit challenging.
I still don't seem to have the hang of layouts. I am trouble getting things to be the size I want.
Here is a test of one of the 5 parts of the GUI. When I run it, I get a window that appears to be 400 x 225 and everything is nicely laid out on the screen. I can, if I want to, make it larger and it behaves pretty much the way I want (except for the insets staying a fixed size, which messes up the look). I did the same test for the second piece of the GUI and it also looks like it ought to. It is 400x235.
I then made stubs for the other three pieces.
I was trying to create empty panels of the right size to go in my top level container, which is done with the following code, but the result is all wrong. The completed panes come out about 600 x 250 not 400 x 225. The uncompleted panes are squeezed into what is left. What is worse is that for the two excessively large panes, the resize behavior is terrible. The upper panel retains almost it's entire height when I make the GUI smaller, while the middle panel shrinks to almost nothing. If I move the split pane divider so that both sides of the GUI are equal size, the top panel on the right grows in size, so that it is much too high. The middle panel shrinks in height until it becomes the size I wanted it to be in the first place. The split pane slider can be moved until I hit the size I set for the panels (that works anyway!).
I can eliminate some of the problem by setting weighty on the top right panel, then it starts out the correct height, though it is still too wide. It then stays a constant size when I make the dialog larger, which is actually what I want. But the behavior where the top panel hardly changes size and the bottom panels disappear is still not resolved. I tried setting grid height and it made no difference.
Am I approaching this problem the wrong way? Where should I look to try and resolve the problems I am seeing? I am still restricted to standard Java layout managers. Am I just setting up the GridBagLayout incorrectly?
The thing that puzzles me is the combination of two requirements: that things be in different panels, but that the position of controls in each panel is precisely related to controls in other panels. Just for my education, can you tell me why that's important? I mean, why have the controls in different panels if they're supposed to line up with each other?
To answer Ralph, panel2 and panel 3 each have an image behind them. Panel1 and panel 4 do not have an image behind them. Panels 2 and 3 actually have related controls, but panel 2 uses five controls and panel 3 only needs the first and the third one. So controls 1 and 3 should line up, but panel 3 should not display the other controls. Panel 1 has labels for four of the controls. Panel 4 is completely unrelated to the other panels in terms of what the controls are used for, I just thought it looked better to have the components line up with the other 3 panels. rather than have them at an arbitrary location. The 'requirement' I am working from requires stacking 3 components on top of each other vertically. It would actually have made more functional sense to place panel 4 underneath the other three panels. But I don't have enough vertical height and I have plenty of width. Not also, if the same control appeared in a given row, life would be easier. But one column has a label in column 1, a combo box in column 2, nothing in column 3 and a checkbox in column 4. GridBagLayout, for example, gives these controls different heights.
Anyway, setting up a GridBagLayout with 4 columns would solve my horizontal alignment problems. But then I would need to place an image underneath just column 2 and another image just underneath column3 and have the images resize in synch with the columns. That's why I chose to use four panels and then try to get the controls aligned across the panels. Also, the image needs to be wider than the control in the column, but that seems manageable (though not clear how to increase the inset width with the column width). I am willing to concede that the basic concept for implementing this requirement is misguided and throw it out. I'm just not able to think of something clever to substitute it with.
Here is a picture (attached) of the package panel happily displayed in it's own test frame. Note, I haven't implemented the actual values of the combo boxes and in column 2 the other fields will actually be Double text fields. So the labeling is not as redundant as it looks at the moment. Also, I was planning to put a layer over 'blister', for example, when it was unchecked to better indicate the active panel. Then I could possibly remove the check boxes and find room to move panel 4 to a horizontal line under the other three panels. Note that the bottle labels are inside the bottle now, but if I widen the window, since the insets to the controls are a fixed size, I end up with the controls being wider than my bottle.
Ranga, I will try to put an SSCCE together. The code currently is 1600 lines. My problem is that I'm not really understanding the relationship between final size and preferred size. As I remove elements, the panel size shrinks. I thought I could create an example where I had dummy panels where I just set a size, i.e.,
but when I put my 'real' package panel (with a requested size of 300,225) and real excipient panel (with a requested size of 300,235) then the GUI displays with the humidity panel squeezed down to about 100 pixels and the excipient panel expanded to larger than I need it to be (and larger than the window that comes up when I just create a test file to display just that panel in a 300x235 frame. I'm have trouble seeing how to make a simple example in those conditions, since leaving things out changes the behavior. I'm not totally convinced that if I put real panels on the left side, that Java wouldn't shrink the right side, which is doesn't do with a dummy like the one above, even if I ask for a width of 800.
So I think I need to create several examples that cover different aspects of the problem, where by problem I really mean something that I don't understand why I get the behavior I see. That may take a little time.
Ok. The image clarifies many things...a picture is truly equal to thousand words - so, you do get the layout you want, but when you resize, you lose it...that seems to be the summary of the problem. The concept of layout managers was precisely for this reason...to have the layouts look the same when screen is resized.
One more point. I see that you are calling setSize() on the panel. I would rather call setPreferredSize() as GridBagLayout respects the preferred size of a component.
I think I have got a solution. The adding of 4 panels remain the same (see my earlier reply with code).
Now for each of the individual panels, I am setting the layout as new GridLayout(6,1) - and then, adding 6 JPanels to each of these panels. And then adding individual components to each of the internal panel based on the need. For example, for the first panel, I woud add components only to internal panel 3,4,5,6. For the second panel, I would add components only to internal panel 1,3,4,6. This works fine for resize too. Am providing the code and 2 images - one intial size and one when resized:
What I had done was very similar, but less elegant. I set the layout as a new GridLayout(6,1) and populated it with 6 objects. Where I wanted an object, I used the object. Where I did not want an object, I added a JLabel and made it transparent. So I am glad I was not too far off in coming up with a solution.
I have a couple problems. One I suspect is related to setting the size of components. I was setting size on practically every JPanel and I suspect that was not the best idea. I also tried to minimize the number of layouts I nested in other layouts, which may also have contributed to my grief. I need to go back armed with all this good help and try and clean up what I have. When I am done, I suspect I will still have two questions for which I haven't been able to come up with a solution.
If you notice, I have a png image behind panel2. Let's suppose the image was a picture frame and I wanted text fields in the center of that picture of a frame that were narrow enough so they would not touch the picture frame pixels. I did this, I made a GridBagLayout and used Insets to create a border around my GridLayout(6,1). But, I have a requirement that the frame can be stretched horizonally. As the image gets wider, the picture frame part of it also gets wider, the Insets are a fixed number of pixels, so eventually, the text field is not inside the frame, but overlapping it. I will post some code to illustrate this, I'm busy with some non-Java stuff at the moment.
I also have a bigger layout that is a split panel with two windows on one side (in a GridBagLayout(2,1)) and three on the other (GridBagLayout(3,1)). I'd like to be able to push and pull this layout and have each of the 5 panels grow and shrink by the same percentage. They are not. The top panel hardly changes and the lower panels shrink or grow. I will also post an example of this. I am thinking that if I limit my requests to set size and use set PreferredSize where that is applicable, I might just find this problem goes away. The panels are quite happy when I make a test application to display each one separately, but they don't play well together.
The text field is fixed, you can stretch the window, but the text field does not change size.
Here is another. The text field now stretches with the window, so if there is a lot to enter, you can stretch the window and see all of it. BUT, notice how the field begins to overlap the image of the frame that it is in. That's because the insets I used to make it look pretty at the beginning are a fixed width. I was hoping there was a not too difficult way to allow the text field to widen with the window without it overlapping the image and making the whole thing look ugly.
This is an extremely tricky problem. You have an image which will take all of the panel - simply because, Java doesn't know that some 'part' of the image has to be treated as a border - human eyes does know that. I have a solution where I have used 'filler' panels - basically transparent JPanels that occupy the four directions - just covering the image border - thus giving the illusion of the main panel being present in the middle part. I did a trail and error with weights...
However, note that this works on a windows machine with the provided image - if things change like env. or image, I am not sure how this will turn out...
The following code works for me both initially and when I resize too (I am posting only the changed parts from your program FrameImageTest1):
one more point to add. I see that you have made the GridBagConstraints variable as a class variable. This is generally not a good idea, as you have to keep track/reset values for each addition of component - I understand that in your case, you have to use it several times, but...you can try to have an instance under say ImagePanel and ImageGrid that would at least lessen the complexity.
this is one case, where a tool like NetBeans would help us - as it adds new constraints instance for every component.
One quick question. The way I was handling the GridBagConstraints didn't seem right to me when I did it. That was one of the ways I saw it handled Googling through code fragments trying to get things working. There are a bunch of variables to set and a lot of them are the same every time. If you just set them all each time you need them (something else I saw a lot) I think it hurts the readability of the code. The other thing I have seen people do is define a method to set the constraints (and return a new GBC object each time). Do you think having a method to create GBC methods is a good way to go?
I don't think having a method for gbc is a good idea. I personally prefer setting it using a variable like you have done. But, in your case, if the same variable is repeatedly used a lot of times, then it becomes difficult to keep track and reset it. A better way in your case would to declare a local variable and use that within the method a few times.