JScrollPane drawing components under itself - java

I have a JScrollPane inside of a JTabbedPane tab. Into that JScrollPane I place a JPanel whose background is red and whose size is explicitly set.
This is what I get:
Note that in the second image, where the container frame has been resized, the component is being drawn under the scrollbar elements.
What's going on here? I've tried just about every combination of layout managers for all the components involved (as well as components besides JPanel - ultimately I want several JEditorPane here), and I cannot get anything to draw except under a big, blank, rectangle (is it a background? which?)
Code:
In main JFrame subclass:
// Called once on startup/layout.
public void refreshGUIState() {
for (int i = 0; i < client.getFrameStackLength(); i++) {
InferenceFrame frame = client.getFrame(i);
JScrollPane pane = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
JPanel wtf = new JPanel();
pane.setBackground(Color.YELLOW);
wtf.setBackground(Color.red);
wtf.setSize(100,100);
wtf.setPreferredSize(wtf.getSize());
pane.add(wtf);
workspace.addTab(Integer.toString(i), pane);
}
}
public GuiClient() throws CliException, ParticleSourceException {
super("L4 Interactive Prover");
setSize(800,600);
mainArea = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true);
mainArea.setDividerSize(2);
mainArea.setBackground(Color.DARK_GRAY);
getContentPane().add(mainArea);
/* ... menu bar init ... */
toolspace = new JPanel();
workspace = new JTabbedPane();
mainArea.add(toolspace);
mainArea.add(workspace);
this.validate();
refreshGUIState();
}
Edit: under the suspicion that JScrollPane was somehow not creating a viewport when its first child was added, as expected, I also tried the three-argument constructor. Same behavior.
Re-edit: Except I erred and left in the add() call. Whoops. Looks like that's it.

Instead of
pane.add(wtf);
you need
pane.setViewportView(wtf);
You can also do it when initialising the JScrollPane:
JScrollPane pane = new JScrollPane(wtf);
Or, in your case:
JScollPane pane = new JScrollPane(wtf, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);

Related

Java JScrollPane sometimes not successful resized

I have next part of code:
final JList<String> list = new JList<String>(strings);
list.setLayoutOrientation(JList.VERTICAL);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
/* Create scroll pane instance */
JScrollPane scroll = new JScrollPane(list) {
#Override
public Dimension getPreferredSize()
{
BookFrame frame = BookFrame.instance();
Container parent = getParent();
return new Dimension(frame.getWidth(), parent.getHeight() - parent.getComponent(parent.getComponentCount() - 1).getHeight() - 14);
}
};
/* Create button instance */
JButton button = new JButton("Add Directory");
/* Add new panel */
JPanel panel = new JPanel();
panel.add(scroll);
panel.add(button);
This code runs when program starts and sometimes button height is a normal value (ex. 15) but sometimes it's 0. I think the problem is with JScrollPane instance - it was created before JButton instance - but I can't synchronize. I tried also to add JButton button = ... before JScrollPane scroll = ... but it's not working too.
I'm newby in Java so please tell me what I do wrong.
I don't see any reason you need to override the getPreferredSize() method. I would guess this is the problem.
JScrollPane scroll = new JScrollPane(list)
I don't know what "list" is, but assuming you are using a JList then you can use:
list.setVisibleRowCount(...);
to indicate the number of rows for the size of the list. The scrollpane will then be that size and scrollbars will appear if needed.

Have to move screen to get JTextArea to appear

I have a desktop pane program where a user inputs data and a jtextarea appears with their results. Instead of having just the text area, i wanted to add it to a scroll pane, which i did. So I created a new scroll pane, and added the text area to it. Now, when I put in data the text area in the scroll pane does not appear until I move the page. In other words, everything works, but I have to move the page a little in order for the results and the scroll pane to show up on the screen.
Any ideas on why this is happening?
private JTextArea matchListResults = new JTextArea();
private JPanel matchPanelBase = new JPanel(new BorderLayout());
private JScrollPane mResults = new JScrollPane();
private void matchResFrame(String[] matchResultArray) throws IOException, SQLException {
Dimension size = new Dimension();
size.setSize(400, 300);
matchListResults.setPreferredSize(size);
matchListResults.setFont(font);
.
.
.
mResults.getViewport().add(matchListResults);
matchListResults.setVisible(true);
matchPanelBase.add(mResults, BorderLayout.CENTER);
}
When you add components to a visible GUI the basic code is:
panel.add(...);
panel.revalidate();
panel.repaint();
By default all components have a size of (0, 0) so there is nothing to paint. The revalidate() will invoke the layout manager which will determine the components size and location.
After you add the new components, call repaint() on the panel.
matchPanelBase.repaint();

JScrollPane triggering weird AdjustmentEvent when adding components

I'm using a JScrollPane with a BoxLayout (a Box, although I've tried a GridLayout too) that shows a list of paginated elements, each page has 5 elements and each element has 5 visual components. The data to fulfill the elements is retrieved from a web service, on load an every time the page changes, removing the current elements in the list and adding the new ones (I know this could be optimized but that's what I have for now).
The weird thing here is that, both on load and when changing page, the vertical scroll bar is moved to some position in the middle, not top, not bottom and not exact center. I've tried to move it up programatically after adding the components, but the scroll is put again in that position after the data presentation method finishes. Then, I can use the scroll bar normally, until the next page change.
Actually, I've attached an AdjustmentListener to the JScrollBar and I can count 25 times (5*5, duh!) that an AdjustmentEvent event that moves the scrollbar to that position is triggered - and yes, if I add less components the event is triggered less times.
I have tried calling revalidate() and repaint() on the window before moving the scroll bar but nothing seem to work, it keeps getting moved to that particular position once per added component.
Any ideas? I'm sorry for not posting some piece of code, but it is kind of a mess and it's difficult to extract the essential parts that could be causing the problem.
Thanks a lot.
Update
Responding to #kleopatra, I'll try to make up some code similar to what I'm doing, although maybe I'm skipping something that somehow causes the strange behavior.
public class MyUI extends JPanel {
List<Data> data;
JPanel dataItemsPanel;
JScrollPane scrollPane;
// ...
/**
* Method to build the UI.
*/
void createUI() {
this.setLayout(new BorderLayout());
// ...
JPanel left = new JPanel();
JPanel right = new JPanel(new BorderLayout());
// ...
dataItemsPanel = new JPanel(new GridLayout(0, 1));
// this is the scroll pane that behaves weird
scrollPane = new JScrollPane(dataItemsPanel);
//...
right.add(scrollPane, BorderLayout.CENTER);
JSplitPane splitPane = new JSplitPane(JSPlitPane.HORIZONTAL_SPLIT,
left, right);
splitPane.setResizeWeight(0);
splitPane.setOneTouchExpandable(true);
splitPane.setContinuousLayout(true);
this.add(splitPane, BorderLayout.CENTER);
// ...
loadPage(0);
}
/**
* Method to load a data page. Called when the program starts (to load
* the first page) and whenever the data page is changed.
*/
void loadPage(int page) {
data = retrievePageDataFromWebService(page);
// remove previous data
dataItemsPanel.removeAll();
// add new data
for (Data d : data) {
// build complex data item representation
JPanel description = new JPanel(new FlowLayout(FlowLayout.LEFT));
description.add(new JEditorPane(/*...*/));
JPanel options = new JPanel(new FlowLayout(FlowLayout.LEFT));
options.add(new JButton(/*...*/));
options.add(new JButton(/*...*/));
JPanel leftDataPanel = new JPanel(new BorderLayout());
leftDataPanel.add(new JEditorPane(/*...*/));
JPanel rightDataPanel = new JPanel(new BorderLayout());
rightDataPanel.add(new JEditorPane(/*...*/));
rightDataPanel.add(options, BorderLayout.CENTER);
JPanel data = new JPanel(new GridLayout(1, 2));
data.add(leftDataPanel);
data.add(rightDataPanel);
JPanel dataItemContainer = new JPanel(new BorderLayout());
dataItemContainer.add(description, BorderLayout.NORTH);
dataItemContainer.add(data, BorderLayout.CENTER);
// finally add it to the data panel
dataItemsPanel.add(dataItemContainer);
}
/*
After this method finishes, an AdjustmentEvent is called once per
added component (25 times). Trying to set the scroll bar position
at this point has no effect, as the events are triggered after the
method. I have tried to call revalidate() and repaint() here and
then move the scroll bar but the result is the same.
*/
}
}

JTabbedPane in JPanel?

I have a simple problem when I want to add tabs in my jpanel. The alignment of the tabs get horizontal instead of vertical, wich looks like crap =/.
It looks like this:
If I discard the panel instead and add the tabbedPane directly to the frame, everything works fine.
If you uncomment the three lines of code and remove the getContentPane().add(jtp); you can reproduce my probleme.
working Code:
public class TabbedPane extends JFrame
{
public TabbedPane()
{
setTitle("Tabbed Pane");
setSize(300, 300); // set size so the user can "see" it
JTabbedPane jtp = new JTabbedPane();
// JPanel panel = new JPanel();//uncomment all three lines
// panel.add(jtp);
// getContentPane().add(panel);
getContentPane().add(jtp);//remove me
JPanel jp1 = new JPanel();// This will create the first tab
JPanel jp2 = new JPanel();// This will create the second tab
JLabel label1 = new JLabel();
label1.setText("This is Tab 1");
jp1.add(label1);
jtp.addTab("Tab1", jp1);
jtp.addTab("Tab2", jp2);
JButton test = new JButton("Press");
jp2.add(test);
setVisible(true); // otherwise you won't "see" it
}
public static void main(String[] args)
{
TabbedPane tab = new TabbedPane();
}
}
Thanks a lot!
If I discard the panel instead and add the tabbedPane directly to the frame, everything works fine.
The default layout of JPanel is FlowLayout, which "lets each component assume its natural (preferred) size." The default layout of JFrame is BorderLayout, the CENTER of which ignores preferred size. In either case, invoking setSize() precludes the layout from functioning initially; re-size the frame to see the effect. Instead, use pack(), which "Causes this Window to be sized to fit the preferred size and layouts of its subcomponents."
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setVisible(true); // otherwise you won't "see" it
There are many things I would change in that code, starting with the recommendations of #trashgod. OTOH this is the minimal change needed in order to stretch the tabbed pane to the width/height of the parent container.
// give the panel a layout that will stretch components to available space
JPanel panel = new JPanel(new GridLayout());//uncomment all three lines
panel.add(jtp);
getContentPane().add(panel);
//getContentPane().add(jtp);//remove me
For more details see this answer.
Well firstly you can try this:
JPanel panel = new JPanel();//uncomment all three lines
panel.setLayout(new GridLayout());
JPanel jp1 = new JPanel();// This will create the first tab
JPanel jp2 = new JPanel();// This will create the second tab
JLabel label1 = new JLabel();
label1.setText("This is Tab 1");
jp1.add(label1);
jtp.addTab("Tab1", jp1);
jtp.addTab("Tab2", jp2);
JButton test = new JButton("Press");
jp2.add(test);
getContentPane().add(jtp);
and in the main:
TabbedPane tab = new TabbedPane();
tab.pack();
tab.setVisible(true);
May I suggest using MigLayout to set layouts, it will make your life easier. Hope it helps.
Try GridbagLayout. Once you have mastered it, you can design UI of any sort with this layout.
I agree with prasanth regarding the use of GridBagLayout
I have gone through this problem once and I solved it by adding the JTabbedPaneto the panel via GridBagLayout, make sure you add the JTabbedPane using the ipadx and ipady according to your requirements in your GridBagConstraints object
e.g.
JPanel myPanel=new JPanel();
myPanel.setLayout(new GridBagLayout());
JTabbedPane jTP=new JTabbedPane();
jTP.add("Tab1",new JPanel());//substitute your component instead of "new JPanel"
GridBagConstraints myConstraints=new GridBagConstraints();
myConstraints.ipadx=400;//streches the component being added along x axis - 200 px on both sides
myConstraints.ipady=600;//streches the component being added along y axis - 200 px on both sides
myPanel.add(jTP,myConstraints);
You can adjust both these properties according to what is perfect for your need

How to use the JScrollPane in Java

How can I get the scroller around my JList component in the code given below? It doesn't seem to work properly :(
public class JButtonO extends JFrame{
String[] values = {"henry", "Michael","Uche","John","Ullan","Nelly",
"Ime","Lekan","Austine","jussi","Ossi","Imam","Empo","Austine","Becky",
"Scholar","Ruth", "Anny"};
public JButtonO()
{
super("the button");
this.setSize(400,200);
JPanel panel = new JPanel();
JLabel label = new JLabel("Output Items:");
label.setAlignmentX(1);
label.setAlignmentY(1);
JList conList = new JList(values);
conList.setVisibleRowCount(3);
JScrollPane scroller = new JScrollPane(conList);
panel.add(label);
panel.add(scroller);
panel.add(conList);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(panel);
this.setVisible(true);
}
Adding the JScrollPane scroller that includes the JList conList to the JPanel panel is enough.
The mistake is that you are adding the JList a second time.
JScrollPane scroller = new JScrollPane(conList);
panel.add(label);
panel.add(scroller);
panel.add(conList); // <---THIS LINE SHOULD BE DELETED...
Look, I may not answering what you need, because I don´t remember to much of swing layout. I don´t work with it a long time ago...
But removing setting a layout (I remember) on your JPanel it works with this code:
public JButtonO() {
super("the button");
this.setSize(400, 200);
// Create a panel with a borderlayout
JPanel jpanel = new JPanel(new BorderLayout());
JLabel label = new JLabel("Output Items:");
label.setAlignmentX(1);
label.setAlignmentY(1);
// Add Label to top of layout
jpanel.add(label, BorderLayout.NORTH);
JList conList = new JList(values);
conList.setVisibleRowCount(3);
JScrollPane scroller = new JScrollPane(conList);
//AddScroll to center
jpanel.add(scroller);
//Add Panel to JFrame
this.add(jpanel);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
I think the problems is the default layoutmaneger of JPanel. Because of how it works your scroll was not "srink" enough to create scrolls...
Hope it helps, even without too much explanation...
ACTUALLY: After I post the answer I saw your mistake. Now I can explain what is wrong. You already added your JList inside your JScrollPane here:
JScrollPane scroller = new JScrollPane(conList);
But after that you put it inside the JPanel:
panel.add(conList);
this changes where yout JList will be displayed, and let the JScroll empty again. Without components it will be displayed with size 0x0 and will not be draw (even being there).
Now I think I helped =D
The JScrollPane has settings called the scrollbar policies which say when the scrollbars are to be displayed. You can set them using JScrolPane(Component,int,int) constructor, or by calling setVerticalScrollBarPolicy() and setHorizontalScrollBarPolicy(). The default policies are "as needed", meaning the scrollbar is only displayed if the component is too large to display whole. So if your list fits inside the window, the scrolbars will not be visible, but will become visible when you e.g. make the window smaller using the mouse. You can change one or both policies to "always" using corresponding constants in order to make the scrollbar(s) always visible if that's what you need.

Categories