Set the vertical scroll to current position after revalidate - java

I know that this question might have been asked before, but I just can't get by head around this, and hopefully we could produce a complete answer to a somewhat tricky interface.
The GUI could be described as follows:
Application extends JFrame. Application adds a JPanel mPanel. mPanel adds a JScrollPane ml containing a MoviePanel extending JPanel.
The JScrollPane ml has vertical scrolling. My goal is that once the content of MoviePanel changes, and a run a revalidate() on it, the scroll pane should not, as it currently does, scroll to the bottom. Rather I'd like it to scroll to what ever position it had before the change to MoviePanel. Giving the feel that it never scrolled at all.
I have tried to manually set the scroll position after I run the revalidate() method:
removeAll(); // Removes all components from the JPanel MoviePanel
add(mList()); // Adds a bunch of content (other JPanels) to MoviePanel
revalidate();
ml.getVerticalScrollBar().setValue(0); // Scroll to top (don't work) - and I'd like this value to be the position of the scroll before these lines started to run
but it seems it really doesn't do anything.
I would be so grateful if someone might help me with this!

Add the scrolling code to a SwingUtilities.invokeLater:
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
ml.getVerticalScrollBar().setValue(0);
}
});

Related

JScrollPane does not scroll properly: scrollRectToVisible acting up?

I have got the following basic setup on a Part of my GUI:
A JScrollPane
On it, a JPanel with a BoxLayout (new BoxLayout(tablePanel, BoxLayout.PAGE_AXIS))
And on this Panel, a Bunch ob Panels.
I am trying to scroll to the Panel that has been highlighted... this works ALMOST.
Currenly, if a Panel is only half-visible on the bottom Part, the ScrollPane scrolls to make it fully visible.. great.
If it is half-visible on the TOP part, it does not... I could live with that.
But if a totally invisible Panel at the very bottom is highlighted, the system does not comment, but neither does it scroll there!
if(selectedPanel!=null){
Rectangle targetRectangle = new Rectangle(selectedPanel.getX(), selectedPanel.getY(), selectedPanel.getWidth(), selectedPanel.getHeight());
Rectangle r = scrollPane.getVisibleRect();
if (!r.contains(targetRectangle)) {
tablePanel.scrollRectToVisible(targetRectangle);
}
}
I am unfortunately not 100% sure how it behaves when the second-to-last panel is selected while not visible, because I cannot make that happen without some code-gymnastics; perhaps someone can help with the information I can give at this point.
you have to compare Rectangle from/returns JViewport(visible rectangle from JScrollPane), not from JScrollPane
use selectedPanel.getBounds instead of (selectedPanel.getX(), selectedPanel.getY(), selectedPanel.getWidth(), selectedPanel.getHeight());
still isn't centerred, have to divide JVievports and selectedPanel with 2
the same result as to use single code line JComponentPlacedIntoJScrollPane.scrollRectToVisible(selectedPanel.getBounds())
for better help sooner post an SSCCE/MCVE, short, runnable, compilable

Swing components overlapping when content in changed

I'm having a problem when an event will change the content of a component, like changing a JLabel's name, removing buttons from a Jpanel then adding another component.
Here is my initial JFrame.
Here is what my JFrame looks when components overlaps every time there is an event.
I'm using this code to temporarily solve my problem, but of course this is not a good idea by just resizing.
setSize(panelWidth + 1, panelHeight + 1);
setSize(panelWidth, panelHeight);
I'm wondering what causes this problem and how can I address this?
NOTE: I'm using layout manager. The panel with buttons is using Grid Layout and most of other is using Grid Bag Layout.
UPDATE:Removing setOpaque(true) fix the overlapping on the panel at top. What remains is the panel with the buttons. I'm using GridLayout with only 1 column.
Here is some of my code for displaying the buttons at pnlButtons.
private void initializeShoppingModeButtons() {
pnlButtons.removeAll();
pnlButtons.add(btnSearchProduct);
pnlButtons.add(btnManualInput);
pnlButtons.add(btnCheckOut);
}
private void initializeProductMenuButtons() {
pnlButtons.removeAll();
pnlButtons.add(btnSearchProduct);
pnlButtons.add(btnViewIndividual);
pnlButtons.add(btnAlternative);
pnlButtons.add(btnDisplayInfo);
pnlButtons.add(btnCancel);
}
one of possible issues is very simple code snipped
private void initializeProductMenuButtons() {
pnlButtons.removeAll();
pnlButtons.add(btnSearchProduct);
pnlButtons.add(btnViewIndividual);
pnlButtons.add(btnAlternative);
pnlButtons.add(btnDisplayInfo);
pnlButtons.add(btnCancel);
}
should be
private void initializeProductMenuButtons() {
pnlButtons.removeAll();
pnlButtons.add(btnSearchProduct);
pnlButtons.add(btnViewIndividual);
pnlButtons.add(btnAlternative);
pnlButtons.add(btnDisplayInfo);
pnlButtons.add(btnCancel);
pnlButtons.revalidate();
pnlButtons.repaint();
}
Swings APIs haven't any notifier that content of container is changed
e.g. JComponents are removed, removed and added, some kinds of relayout (change ordering of, e.i.)
revalidate(); and repaint(); will notify used LayoutManager, use that as last code lines, after all changes to Swing GUI are done
nothing cleaver without your SSCCE, MCVE/MCTRE
Edit 1st.
have look at use CardLayout for switching between views

JScrollPane does not update scrollbar

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)

JScrollBar Doesn't Do Anything

I'm trying to put a vertical JScrollBar on top of a JPanel. I can add the scoll bar easily enough, but when I run the program, my scroll bar doesn't have any effect. I can drag it up and down, but the contents of the JPanel don't move. I've read all what I can find about how to do this, and it seems very straightforward, but I'm obviously missing something.
Please note that my JPanel layout is set to NULL. Here is the relevant code. Thanks!
public JDlgResults(ArrayList<AnsweredProblem> probList) {
initComponents();
pnlResults.setLayout(null); //allows free form placing of JLabels
/* Iterate over the ArrayList and add each problem to the results table */
Iterator iter = probList.iterator();
int row = 1;
while(iter.hasNext()) {
addRow(row, iter.next());
row++;
}
JScrollBar jScrollResults = new javax.swing.JScrollBar();
pnlResults.add(jScrollResults);
jScrollResults.setBounds(590, 0, 17, 196);
}
I assume that your initComponents() method sets up a bunch of components and adds them to your contentPane and establishes your dialog (whether it be dialog or a frame).
Simply adding your JScrollPane to that panel wont do the trick.
Instead, add your pnlResults to the JScrollPane instance and make that your contentPane.
That's by design. It would be kind of bad if the scroll bar magically tried to pick up panels in its vicinity and started scrolling them.
On a low level, you can add listeners to the scroll bar and implement scrolling yourself. You would also have to tell the scroll bar how much there is to scroll.
However, this is not what you want. You want a JScrollPane that you wrap around your panel. In that way, you never instantiate the scroll bars directly and do not have to deal with the low-level mechanics of scrolling (which is quite complicated).

Resize JScrollPane client without scrollbars rolling

I have a JScrollpane which contains a scrollable client that changes its size dynamically while using the application. I want the JScrollPane to be aware of the changes without moving the viewport when the client size changes.
To clarify what I mean:
Refer to the Java Webstart example ScrollDemo2 from the article How to use scroll panes by Sun. When clicking at the bottom of the window, a circle appears partly outside the window and the scrollbars move. It's the latter behavior I want to avoid.
My guess is that it's just a matter of setting a simple flag in one of the many components that are involved in a scroll pane solution, but I just can't find where it is. Does anyone know?
I managed to solve this problem by overriding the standard behavior of the viewport in my JScrollPane. This might be a solution that is not suitable for all, but in my GUI this works like a charm.
JScrollPane pane = new JScrollPane();
pane.setViewport(
new JViewport(){
/**
* An empty override implementation to prevent undesired scrolling on
* size changes of the client.
*/
#Override
public void scrollRectToVisible(Rectangle rect){}
});
I would try something like:
Point p = scrollPane.getViewport().getViewportPosition();
revalidate();
scrollPane.getViewport().setViewportPosition(p);
You may need to wrap the last line of code in a SwingUtilities.invokeLater.
If that doesn't work then maybe you can disable/enable the viewport before and after the revalidate()?

Categories

Resources