I am attempting to create panel, PluginListPanel (extending JPanel), which will show a list of plugin panels which will respect the preferred height of the plugin's panel, but will force the width. I have a solution, but it is slow and has a weird bug. In the screenshot, there are two such panels, one to the left and one to the right:
I don't know different layout manager systems very well, but I know that the TOP field in the BorderLayout does what I want. So, I came up with this 'recursive' solution:
public PluginListPanel(List<PanelContainer> items) {
JPanel body = this;
for (PanelContainer item : items) {
body.setLayout(new BorderLayout(0, 0));
JPanel panel = new PluginOnePanel(item);
body.add(panel, BorderLayout.NORTH);
JPanel newBody = new JPanel();
body.add(newBody, BorderLayout.CENTER);
body = newBody;
}
}
The problem I encounter is when I scroll, the system responds somewhat slowly, and the colour of the SamplePluginPanels is different (see picture below), even if the number of SamplePluginPanels is as low as 8.
The question is, how can I make this more elegant, not slow down the program and not miscolour the panels?
Any insights are highly appreciated.
I think a vertical Box is the answer (actually 2, on both columns):
Box leftBox = Box.createVerticalBox();
Box rightBox = Box.createVerticalBox();
/* put them together */
setLayout(new GridLayout(2,1));
add(leftBox);
add(rightBox);
Also make sure, that the content of the scroll pane implements Scrollable and returns true, to scrollableTracksViewportWidth(). This will force equal widths.
Related
I am trying to create a JScrollPane that contains a JPanel that will be increasing and decreasing in height. When it becomes larger than the size of the JScrollPane, it should create a vertical scroll bar which will allow me to scroll through the entire JPanel. However, I am having difficulty achieving this. Yes, I know I am not using LayoutManagers. No, I will not be using them, and I need a solution that does not involve their usage.
Here are the two button's AbstractActions that add and subtract from the JPanel:
class AddACT extends AbstractAction
{
public void actionPerformed(ActionEvent e)
{
info.setSize(420,info.getHeight() + 40);
info.add(new SubPanel); // Adds another JPanel into the main JPanel (for content input)
gui.repaint();
infoS.validate();
}
}
class RemoveACT extends AbstractAction
{
public void actionPerformed(ActionEvent e)
{
info.remove(subPanel()); // This would remove the last JPanel added to the main JPanel
info.setSize(420,info.getHeight() - 40);
gui.repaint();
infoS.validate();
}
And here is the code for the main JPanel and the JScrollPane:
final JPanel info = new JPanel();
final JScrollPane infoS = new JScrollPane(info, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
info.setLayout(null);
info.setSize(420,600);
infoS.setLocation(10,80);
infoS.setSize(420,490);
gui.add(infoS); // gui is the frame's content pane (the overall JPanel)
This is the second project I've been trying to learn GUI by doing. I am a complete novice in Swing and am only intermediate in Java. Sorry if I am making a blindingly obvious mistake.
1) Use LayoutManagers (+1 to #kleopatra and #GagandeepBali comments)
The absence of LayoutManagers only guarantees your GUI's will look very trashy (especially when run on other OSes/builds) and being a Novice you should rather learn the correct way than learn the wrong way and get into bad habits like calling setSize() etc.
Have a read on these links to get you started:
A Visual Guide to Layout Managers
Concurrency in Swing
2) See this example for how to use a JScrollPane, it simply adds a JPanel with buttons to a JScrollPane which in-turn is added to the JFrame.
3) Also see this example for how to make the JScrollPane vertically scroll-able only.
4) For more on JScrollPanes have a look here: How to Use Scroll Panes.
5) As for how it interacts with LayoutManager, if you do not explicitly set its size via setPreferredSize(Dimension d) the scroll pane computes it based on the preferred size of its nine components (the viewport, and, if present, the two scroll bars, the row and column headers, and the four corners)
6) On your usage of validate():
validate() is used when new JComponents are added to a visible component
revalidate() is used when JComponent is removed/added from a visible component
revalidate() covers validate() too
Thus always use this:
//add or remove component(s)
revalidate();
repaint();
References:
http://www.daniweb.com/software-development/java/threads/405568/validate-vs-revalidate
LayoutManager is not required to solve the problem. The problem in Thrfoot's example is in these lines:
final JScrollPane infoS = new JScrollPane(info, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
info.setLayout(null);
info.setSize(420,600);
The program appears to recognize there is a need for scroll bars (it would show the scroll bar if your setting was VERTICAL_SCROLLBAR_AS_NEEDED), but the actual scrolling does not work (the scroll bar slider is not there).
To fix this, first set the preferred size of info, then construct the infoS.
Example:
info.setPreferredSize(420,600);
final JScrollPane infoS = new JScrollPane(info, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
The idea is to set the preferred size of the info panel before it is used for the scroll pane. This is the same reason to set the size and location of infoS before adding to the gui:
infoS.setLocation(10,80);
infoS.setSize(420,490);
gui.add(infoS); // gui is the frame's content pane (the overall JPanel)
I want to reduce the size between the components with in the Formatting group (left side on the image). How to do this?
JPanel formattingGroup = createGroupWithName("Formatting");
formattingGroup.setMinimumSize(new Dimension(250, 20));
formattingGroup.setLayout(new GridLayout(5, 0));
add(formattingGroup);
final JCheckBox showSurface = new JCheckBox("Show surface");
showSurface.setSelected(true);
formattingGroup.add(showSurface);
final JCheckBox showTerrain = new JCheckBox("Show terrain");
showTerrain.setSelected(true);
formattingGroup.add(showTerrain);
final JCheckBox showVehicleStatus = new JCheckBox("Show vehicle status");
showVehicleStatus.setSelected(true);
formattingGroup.add(showVehicleStatus);
JPanel pnl = createGroupWithName("Depth Stretch");
formattingGroup.add(pnl);
JSlider slider = new JSlider(0, 10);
pnl.add(slider);
When using a GridLayout all components are made the same size.
You are adding a JPanel with a TitledBorder and a JSlider to the grid. Therefore the checkboxes will take the same vertical height as that panel.
You need to use a different layout manager for the panel. Maybe a vertical BoxLayout.
You might look at available size variants, discussed in Resizing a Component.
Use gridbaglayout because that gives you the opportunity to give weights, to columns or rows and set spacing and padding values.
I made a Swing application that contains out of 12 Frames and they all are made with GridBagLayout.
I also tried other before that but they all had limits. That's where the GridBagLayout kicks in. It's a bit harder in begin to understand how it works, but once you get feeling with it, it really is best thing to get the components where you want.
If you want i'll give you a cool example of a frame created with GridBagLayout.
I am trying to add components to a jpanel dynamically from a database, one after the other, however they extend beyond the limits of the form (and even the screen) horizontally. I am using a panel with BoxLayout which positions inner components on the x-axis. What I would like to do is limit the addition of components on the x-axis at the border of the form (or the border of the container panel) .
What I tried so far is:
To set the maximum size (width) of the
container jpanel but that did not
work.
To set the layout manager to
flowlayout, but it also expands
infinitely on the x-axis.
To position the container panel inside a
scrollpane. That makes a huge
horizontal scrollbar, which means that
it does not limit the components to
the border of the form.
Should I make a custom layout? Any ideas simpler than that?
My code looks like:
jpanelCases.setLayout(new BoxLayout(this.jpanelCases, BoxLayout.X_AXIS));
db = Database.getInstance();
List<Category> cats = db.getCategories();
for(Category c : cats){
JPanel jp = new JPanel();
//addition of other components to the newly created panel here
jpanelCases.add(jp);
}
however they extend beyond the limits of the form (and even the screen) horizontally.
So what do you want to do in this case:
a) just ignore the components and not add them to the frame
b) display the components on a new line
If the answer is "b", the try the WrapLayout.
Try to put 2 glues, one at first one at last:
jpanelCases.setLayout(new BoxLayout(this.jpanelCases, BoxLayout.X_AXIS));
jpanelCases.add(Box.createHorizontalGlue());
db = Database.getInstance();
List<Category> cats = db.getCategories();
for(Category c : cats){
JPanel jp = new JPanel();
//addition of other components to the newly created panel here
jpanelCases.add(jp);
}
jpanelCases.add(Box.createHorizontalGlue());
What about using JScrollPane on the JPanel? This will contain the elements within the panel without exceeding its physical boundaries. Otherwise, if you do not like the scroll idea I suggest that you somehow keep track of the total sum of width of elements added to the panel with respect to the panel physical width, and stop adding elements when the next element width added to the sum exceeds the panel width.
I hope this helps!
I'm trying to create a JDialog like the Symbol dialog in Microsoft Word that you get by choosing Symbol... from the Insert menu. Basically, it's an n x m (n and m are not known until runtime) grid of small buttons. I've got a first version of this working nicely using a GridLayout. The problem is that when you resize the dialog (and there is a requirement that you should be able to resize it), the size of the buttons changes. I need the size of the buttons to remain constant.
But I want the dimensions of the grid containing the buttons to change. For example, if the dialog gets wider, but stays the same height, the number of rows should lessen, while the number of columns increases.
I've thought of a couple of ways to fix this:
When the dialog is resized, create a new GridLayout and repopulate it with the buttons. I'm going to try this and see how it looks, but it seems like a clumsy way of doing it.
Use some other type of layout such as a FlowLayout. I took a stab at this, but it put all n x m buttons in one row. I do not want to use horizontal scroll-bars and the buttons ran off the right edge. Anyway, it's supposed to be a 2-dimensional grid of buttons.
What is the best way to solve this layout problem?
Create a buttons panel with GridLayout and set a fixed size (could be calculated at runtime of course) to it. The buttons panel should be contained in a panel of BoxLayout.
Check out the BoxLayout Tutorial
Very Very basic example:
public static void main(String[] args) throws Exception
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel buttonPanel = new JPanel();
JPanel containerPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(2,2));
buttonPanel.add(new JButton("1"));
buttonPanel.add(new JButton("2"));
buttonPanel.add(new JButton("3"));
buttonPanel.add(new JButton("4"));
buttonPanel.setPreferredSize(new Dimension(300, 400));
containerPanel.add(buttonPanel);
frame.getContentPane().add(containerPanel);
frame.pack();
frame.setVisible(true);
}
if the dialog gets wider, but stays the same height, the number of rows should lessen, while the number of columns increases.
Wrap Layout might be what you are looking for.
I had a similar issue with a single column of buttons, and found that MiGLayout (third-party, available here) was simple and effective for this. It helped both with making a grid and with setting button sizes, although it took me a day or two to get used to its syntax.
But the key is really setting button sizes; GridLayout certainly seems like the way to go for a layout that is, well, a grid. I haven't tested, but I suspect that the built-in setXSize() methods would work just as well. The GridBagLayout tutorial has examples of some things you can do with sizing/positioning.
FlowLayout would be the way to go but you might have some configuration problems. What layout manager does the parent component use?
I have a text field to represent a name, and a combobox for registration type. Then, next to that I have a check box, but it's supposed to be underneath the other two fields. Here is what I have coded:
public RegPanel()
{
//create a new panel
new GridLayout(2,1);
//create one of two subpanels
subPanel = new JPanel(new FlowLayout());
//create a textfield
regTextField = new JTextField(20);
//create a combobox and don't let anyone add to it
regComboBox = new JComboBox(regOptions);
//create a border for the subpanel
subPanel.setBorder(BorderFactory.createTitledBorder("Registrant's Name & Type"));
//add regTypePanel and regBox to the panel
subPanel.add(regTextField);
subPanel.add(regComboBox);
//create a second subpanel with a flowlayout
subPanel2 = new JPanel(new FlowLayout());
//create a checkbox
regCheckBox = new JCheckBox("Dinner and Keynote Speech");
subPanel2.add(regCheckBox);
//add the subpanels to the main panel
add(subPanel);
add(subPanel2);
}
Any ideas what I am missing? Sorry for the crappy layout, I can't figure out how to fix the view.
So I realized I hadn't set the GridLayout right, so I changed that to "setLayout(new GridLayout(2,1));
But now on my gui, it totally screwed up the position of all the other elements.
Anyway new GridLayout(...) do nothing unless you use it in setLayout(...).
You can try using Box.createVerticalBox() (sample) instead of GridLayout to have your components in vertical alignment.
In your case, you are using
RegPanel (which layout?)
subPanel (FlowLayout)
regTextField
regComboBox
subPanel2 (FlowLayout)
regCheckBox
Which layout does your main RegPanel have? It has the default JPanel layout (if RegPanel is a subclass of JPanel), which is a FlowLayout. So, your RegPanel shows the two subPanels besides each other, which looks similar as if you had only one Panel with all the components. So, your RegPanel needs a LayoutManager, too - the GridLayout(2,1) seems okay (if you don't want to align the components in the two lines).
In my current project, I'm only ever using GroupLayout (apart from one occasional BorderLayout). It takes a bit to get used to (and a wrapper class to make the code easier to write and read), but for such form stuff, it seems ideal (when limited to the build-in Layout managers).
Also you might want to use a BorderLayout and realize that you nest one layout in another layout to achieve a different effect.
Have to mention MigLayout here as a great all-purpose layout manager -- it is extremely flexible and easy to use once you get to know it.