I'm trying to put multiple JPanel cards into my main panel. and if new card panel does not fit I want it to be placed in next line. In the image below, you see that all my card panels go to right and if I set HORIZONTAL_SCROLLBAR_ALWAYS horizontal scroll works. So here I want 4 card panel in each line of my main panel so that vertical scroll works.
public class PanelTraining extends JPanel{
private static final long serialVersionUID = 1L;
public PanelTraining(List<FccMeta> ffcms) {
super(new BorderLayout()); // set layout to absolute
setPreferredSize(new Dimension(880, 580));
setBorder(new LineBorder(Color.decode("#A11E1E"),1, true));
JPanel pnlChart = new JPanel();
pnlChart.setPreferredSize(new Dimension(860, 180));
pnlChart.setBackground(Color.YELLOW);
add(pnlChart, BorderLayout.NORTH);
JPanel pnlTrSet = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 5));
//pnlTrSet.setSize(860, 380);
for (FccMeta fccMeta : ffcms) {
JPanel pnlCard = new MyCustomPanelCard();
pnlTrSet.add(pnlCard);
}
JScrollPane scroll = new JScrollPane(pnlTrSet);
//scroll.setPreferredSize(new Dimension(860, 380));
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
add(scroll, BorderLayout.CENTER);
}
}
EDIT according to the answer given below. I changed my implementation by this Class
ScrollablePanel pnlTrSet = new ScrollablePanel(new FlowLayout());
pnlTrSet.setScrollableWidth( ScrollablePanel.ScrollableSizeHint.FIT );
pnlTrSet.setScrollableBlockIncrement(
ScrollablePanel.VERTICAL, ScrollablePanel.IncrementType.PIXELS, 230);
You need to implement the Scrollable interface of your panel to have the width fixed to the size of the viewport of the scrollpane.
Basically you need to override the getScrollableTracksViewportWidth() method to return “true”.
An easy way to do this is to use the Scrollable Panel. It has a method that allows you to control this property.
Edit:
The above will only prevent the horizontal scrollbar from appearing. However the FlowLayout will continue to display all the buttons on a single row because the preferred size calculation of the panel is still not correct.
To get the buttons to wrap, you must replace the FlowLayout of your panel with the Wrap Layout. The Wrap Layout will recalculate the preferred height of the panel correctly so that the components can wrap and the vertical scrollbar can appear.
Related
I'm in the process of creating a circuit editor (similar to any regular paint software with a basic menu and a canvas with specifiable dimensions). I am currently trying to transform the previously unscrollable canvas (JPanel) to a scrollable one.
The obvious design error at the moment is that while the scrollbars seem to correctly reflect the internal size of the canvas (which can of course be way bigger than the JFrame), due to the canvas JPanel being added in the CENTER of the BorderLayout of the master panel, it always resizes along with the JFrame.
public final class MainFrame extends JFrame
{
public MainFrame()
{
JPanel menuPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
// Populate Menu Panel
// ...
JPanel canvasPanel = new JPanel();
canvasPanel.setBackground(Color.white);
Dimension canvasDims = new Dimension(800,600);
canvasPanel.setPreferredSize(canvasDims);
canvasPanel.setMinimumSize(canvasDims);
canvasPanel.setMaximumSize(canvasDims);
JScrollPane canvasScrollPane = new JScrollPane(
canvasPanel,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
JPanel masterPanel = new JPanel(new BorderLayout());
masterPanel.add(menuPanel, BorderLayout.NORTH);
masterPanel.add(canvasScrollPane, BorderLayout.CENTER);
setContentPane(masterPanel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1200, 700);
setMinimumSize(new Dimension(500, 500));
setLocationRelativeTo(null);
setVisible(true);
}
I've read quite a few posts regarding centering JPanels and scrollbars but with both complexities added together, things might be a bit more complicated as I haven't yet found a solution.
What I'm really trying to achieve is to have the canvas' JPanel fixed in whatever size the user might have specified and centered in the middle as well as the scrollbars behaving as one would expect like in the beloved windows' paint:
How would you go about doing this/fixing my design? Any help would be greatly appreciated!
P.S. Happy new Year :)
JPanel fixed in whatever size the user might have specified and centered in the middle as well as the scrollbars behaving as one would expect
So you need to nest panels so the canvas panel can be displayed at its preferred size, while the parent panel resizes with the size of the frame.
An easy way to do this is with a JPanel that uses a GridBagLayout. Then you add the canvas panel to this panel using the default GridBagConstraints.
So the basic structure of the panels would be:
JPanel canvas = new JPanel();
canvas.setPreferredSize( new Dimension(300, 300) );
canvas.setBackground(Color.RED);
JPanel wrapper = new JPanel( new GridBagLayout() );
wrapper.add(canvas, new GridBagConstraints() );
frame.add(new JScrollPane(wrapper));
Note: there is no need for your "masterPanel". The default layout manager for the content pane of a JFrame is a BorderLayout, so you just add the "menuPanel" and "scrollPane" directly to the frame with the proper BorderLayout constraints.
Here is my JPanel class. I have BoxLayout in it and only one JLabel added. My JLabel is on the left side of the screen. Is there any way to align all the components that are in the BoxLayout to the center. I tried this : setAlignmentX(CENTER_ALIGNMENT); but it doesnt work
public class MainPanel extends JPanel
{
// This layout we will use as our base layout.
private BoxLayout mainLayout = new BoxLayout(this, BoxLayout.Y_AXIS);
// This we will use to control padding in our main panel
EmptyBorder mainBorder = new EmptyBorder(10, 10, 10, 10);
private JLabel title = new JLabel("Podesavanja");
public MainPanel()
{
setLayout(mainLayout);
setBackground(Color.GRAY);
setAlignmentY(CENTER_ALIGNMENT);
// Setting padding
setBorder(mainBorder);
add(title);
}
// Dodajemo sve Ostale panele u ovu main panelu
public static void addPanel(JPanel panel)
{
addPanel(panel);
}
}
First of all, you call setAlignmentY() instead of setAlignmentX(). Second, you're calling it on the panel instead of calling it on the JLabel.
Fix those two bugs, and the label will be centered.
Is there any way to do it for all the elements inside layout ?
Not with a BoxLayout. A BoxLayout uses the alignment of individual components.
You can use different layout managers:
A GridBagLayout will allow you to set the alignment by using a GridBagConstraint. You set the alignment once and it will be used by all components. Of course you need to set the gridY of each component. So is this any different then setting the x alignment of the BoxLayout?
You can use a 3rd part layout manager like the the Relative Layout.
It works similar to a BoxLayout in that you can layout components horizontally or vertically. However RelativeLayout also allows you to specify alignment for the panel as a whole:
RelativeLayout rl = new RelativeLayout(RelativeLayout.Y_AXIS);
rl.setAlignment( RelativeLayout.CENTER );
JPanel panel = new JPanel( rl );
I'm new to Swing and I currently work on some sort of graphic editor.
First I started implementing the toolbar (class OptionsBar) as an extended JPanel. Everything looked fine(image below), but it didn't work as a toolbar (it wasn't always focused). Then I found out that there actually exists a JToolBar element, so I replaced "extends JPanel" with "extends JToolBar". I look thorugh toolbar specifications. It seemed like I should change anything.
The problem is that the toolbar is transparent (besides its panel elements) even though isBackgroundSet() returns true. (image 2)
The second bug is drag the toolbar and then bring it back to the initial positions. It shrinks. (image 3)
Also, some movements (i can't describe them exactly) result in java.lang.IllegalArgumentException: illegal component position
The main windows is a JFrame that has border layout and uses a desktop pane.
Any help? Thanks!!
public class OptionsBar extends JToolBar {
..some constants and attributes..
public OptionsBar(BrushStroke brushStroke, BrushStroke savedBrushStroke) {
super();
this.setBackground(backgroundColor);
// keep the references to strokes from the main gui
this.brushStroke = brushStroke;
this.savedBrushStroke = savedBrushStroke;
// create buttons for selecting pencil/eraser
JToggleButton brushButton = makeInstrumentButton(brushIcon, "Pencil");
JToggleButton eraserButton = makeInstrumentButton(eraserIcon, "Eraser");
// make a button for adjusting colors
JButton adjustColorButton = makeAdjustButton();
// create label for descriptions
JLabel toolsLabel = makeDescriptionLabel("Tools");
JLabel parametersLabel = makeDescriptionLabel("Parameters");
JLabel colorsLabel = makeDescriptionLabel("Colors");
// create panel for brush size and opacity parameters
ParameterPanel sizePanel = new ParameterPanel("Size", "1", 1,
maxBrushSize, 1);
ParameterPanel opacityPanel = new ParameterPanel("Opacity", "100", 0,
100, 100);
// create a check box for selecting rounded caps
JCheckBox roundedCap = new JCheckBox("Use round strokes");
roundedCap.setSelected(true);
JSeparator separator = new JSeparator(JSeparator.VERTICAL);
separator.setMaximumSize(new Dimension(3, 35));
JSeparator separator1 = new JSeparator(JSeparator.VERTICAL);
separator1.setMaximumSize(new Dimension(3, 35));
// create a box layout
this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
this.add(Box.createHorizontalStrut(20));
this.add(toolsLabel);
this.add(Box.createHorizontalStrut(30));
this.add(brushButton);
this.add(Box.createHorizontalStrut(10));
this.add(eraserButton);
this.add(Box.createHorizontalStrut(30));
this.add(separator1);
this.add(Box.createHorizontalStrut(30));
this.add(parametersLabel);
this.add(Box.createHorizontalStrut(20));
this.add(sizePanel);
this.add(Box.createHorizontalStrut(20));
this.add(opacityPanel);
this.add(Box.createHorizontalStrut(25));
this.add(roundedCap);
this.add(Box.createHorizontalStrut(25));
this.add(separator);
this.add(Box.createHorizontalStrut(30));
this.add(colorsLabel);
this.setOpaque(false);
addColorButtons();
this.add(Box.createHorizontalStrut(20));
this.add(adjustColorButton);
this.colorPicker = new ColorPicker();
colorPicker.getSelectionModel().addChangeListener(new ColorChange());
this.colorPopup = new JPopupMenu();
colorPopup.add(colorPicker);
this.setSize(2000, 65);
this.setVisible(true);
}
And here is the snipped from the JFrame constructor
Here is a snippet from the JFrame constructor
desktop = new JDesktopPane();
setContentPane(desktop);
whiteBoards = new HashMap<String, Canvas>();
createFrame("first try", 400, 300);
desktop.add(new OptionsBar(brushStroke,savedBrushStroke),BorderLayout.PAGE_START);
To give an answer to all your questions:
JMenuBar is transparent by default. You can change that setting as follows:
menuBar.setOpaque(true);
You added your JMenuBar to a JDesktopPane container. A JDesktopPane has no layout set by default, to allow positioning of the added JInternalFrame. Thats why your JMenuBar is not visible, if you do not set the size manually.
Usually it is a better idea to let the LayoutManager align your components. To do so, replace your last code snippet with these lines:
desktop = new JDesktopPane();
JPanel basePanel = new JPanel(new BorderLayout());
basePanel.add(desktop, BorderLayout.CENTER);
basePanel.add(new OptionsBar(...), BorderLayout.PAGE_START);
getContentPane().add(basePanel);
This code uses another parent JPanel which allows us to add our JMenuBar to the top area. Aligning and sizing of our JMenuBar is not delegated to the LayoutManager of the JPanel so we can get rid of the getSize(...) in the constructor of the OptionsBar.
I am pretty sure that this change also fixes the thrown IllegalArgumentException.
So I have a bunch of JTables. Each JTable is inside a JScrollPane. I'm then adding each of these JScrollPanes to a JPanel. I'm then adding this JPanel to a JScrollPane then that to another JPanel with BorderLayout. The larger JScrollPane properly resizes with its parent, but each of the smaller JScrollPanes have constant height, which is larger than the window when it is small. How can I get each of the children JScrollPanes to resize with the height of the window/their parent?
I've tried adding more intermediary JPanels with FlowLayout, BorderLayout, and nothing seems to work.
Here's some relevant code:
public class MyPanel extends JPanel
{
public MyPanel()
{
super(new BorderLayout());
JPanel panel = new JPanel();
for (int i = 0; i < 5; i++)
{
// View extends JTable
panel.add(new JScrollPane(new View(new Model())));
}
add(new JScrollPane(panel));
}
}
I'm really just trying to get a bunch of tables with scrollbars horizontally next to each other inside a larger panel with a horizontal scrollbar. And I want all that stuff to resize appropriately when the window size changes.
more code:
final MyPanel panel = new MyPanel();
final JTabbedPane tabView = new JTabbedPane();
tabView.add(...);
tabView.add("foo", panel);
final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, ..., tabView);
this.add(splitPane); // this extends JFrame
You can use a BoxLayout. If you want the opposite: some table being fixed, you can wrap it with constraint Box.createRigidArea(new Dimension(100, 100)) .
I am just trying to add a vertical scroll bar to my TextField and TextArea.
I am using a ScrollPane and it should create avertical/horizontal scroll bar by default.
Problem:
I need a vertical scroll bar to see the data which is not visible.
In the start a vertical scrollbar appears but when the data increases the vertical scrollbar changes to a horizontal scroll bar.
Also the TextField disappears and only a horizontal scrollbar appears in its place.
I guess it is because how I have set the bounds but I tried changing the bounds and it ends up completely doing away with the TextField.
My code snippet:
public JTextField inputField = new JTextField();
public JTextArea talkArea = new JTextArea();
public JScrollPane inputFieldScroll = new JScrollPane(inputField);
public JScrollPane talkAreaScroll = new JScrollPane(talkArea);
talkArea.setEditable(false);
talkArea.setBackground(Color.white);
talkAreaScroll.setBounds(new Rectangle(TALK_LEFT, TALK_TOP, TALK_WIDTH, TALK_HEIGHT));
this.getContentPane().add(talkAreaScroll, null);
//set input area
inputField.setBackground(Color.white);
inputField.setBounds(new Rectangle(INPUT_LEFT, INPUT_TOP, INPUT_WIDTH, INPUT_HEIGHT));
inputFieldScroll.setVerticalScrollBar(new JScrollBar());
inputFieldScroll.setBounds(new Rectangle(INPUT_LEFT, INPUT_TOP, INPUT_WIDTH, INPUT_HEIGHT));
Question:
Is there some parameter I need to set so that it remains a vertical scroll bar?
Why does the input scroll bar occupy the whole inputfield when the data becomes a huge line? It appears as a proper vertical scrollbar in the start.
Any advice appreciated.
Thanks
Below is a small compilable code snippet I mentioned above. I agree with camickr that you should not be using absolute positioning but rather use the layout managers. If you absolutely need to have a horizontal scrollbar for the JTextField, then one way to get it to work is to have it show up always, using the JScrollPane constructor that allows for this. i.e,
JScrollPane inputPane = new JScrollPane(inputField, JScrollPane.VERTICAL_SCROLLBAR_NEVER,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
For e.g.,
import java.awt.*;
import javax.swing.*;
public class FuSwing1b extends JPanel {
private static final int TA_ROWS = 25;
private static final int TA_COLS = 60;
private JTextField inputField = new JTextField();
private JTextArea talkArea = new JTextArea(TA_ROWS, TA_COLS);
public FuSwing1b() {
talkArea.setEditable(false);
talkArea.setFocusable(false);
talkArea.setBackground(Color.white);
//talkArea.setPreferredSize(new Dimension(TALK_WIDTH, TALK_HEIGHT));
JScrollPane talkPane = new JScrollPane(talkArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
JScrollPane inputPane = new JScrollPane(inputField, JScrollPane.VERTICAL_SCROLLBAR_NEVER,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
int gap = 10;
setLayout(new BorderLayout(gap, gap));
add(talkPane, BorderLayout.CENTER);
add(inputPane, BorderLayout.SOUTH);
setBorder(BorderFactory.createEmptyBorder(gap , gap, gap, gap));
}
private static void createAndShowUI() {
JFrame frame = new JFrame("FuSwing1b");
frame.getContentPane().add(new FuSwing1b());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
Don't play with the bounds. Use a layout manager and you won't have to worry about this.
When you create the text field use something like:
JTextField textField = new JTextField(10);
This will create a text field that will hold a minimum of 10 characters. If the number of characters exceeds the display width of the text field the use can see the remaining characters by using the right/left arrow keys. That is the normal UI used by all applications I have ever seen. Don't try to create your own UI by using a horizontal scrollbar. Users are not accustomed to that.
for the text area you can create it using:
JTextArea textArea = new JTextArea(5, 30);
JScrollPane scrollPane = new JScrollPane( textArea );
to create a text area with 5 rows and approximately 30 character per row.
Now add the text field and the scrollpane to your frame "using layout managers" and then pack the frame. The layout managers will determine the best size for the compoents. Scrollbars will automatically appear on the text area as you add text to it and the text exceeds 5 lines.