5

I have a JScrollPane containing a JPanel. I fill this JPanel with many buttons.

Is there any possibility to get the currently shown buttons?

I know I can access the children of a JPanel via jpanel.getComponents() but those are all components in this pane; I want only the ones that are currently on screen.

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Leon
  • 87
  • 6

4 Answers4

9

As already commented to @mKorbel's answer:

  • it's correct that you need the child bounds
  • it's correct that you need to intersect those bounds with "something"
  • it's wrong that you need the containing viewport (nor the scrollpane)

JComponents have an API to get their currently visible part independently of how/where exactly they are currently shown, so the "something" is the JComponent's visibleRect:

Rectangle visibleRect = myPanel.getVisibleRect();
for (Component child : myPanel.getComponents()) {
   Rectangle childBounds = child.getBounds();
   if (childBounds.intersects(visibleRect)) {
       // do stuff
   }
}
Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
kleopatra
  • 51,061
  • 28
  • 99
  • 211
  • IMHO this is the best answer. I was surprised to find it on the bottom! – Jack Aug 24 '12 at 06:39
  • c) `it's wrong that you need the containing viewport (nor the scrollpane)`, [not you can to use reshape](http://docs.oracle.com/javase/7/docs/api/javax/swing/JViewport.html#reshape%28int,%20int,%20int,%20int%29), then `JViewport` can returns different `Rectangle` as came /delegated from/by `JScrollPane` – mKorbel Mar 02 '13 at 18:53
  • @mKorbel Sunday morning head-scratching - as so often I don't quite understand what you are saying :-) Where in my code do you see a viewport? It not being there is the whole point: it doesn't matter who is the parent, internals will take of the nitty details. – kleopatra Mar 03 '13 at 11:21
  • So there's no callback available somwhere to get notified when components are getting hidden by the scroll pane? Looping through all components each time it scolls sounds inefficient... (PS: +1 :-)) – Matthieu Oct 04 '18 at 08:41
  • 1
    @Matthieu didn't lay my hands on swing for a while, but afaik there isn't any api. If you really need it (can't imagine a use-case) you might implement a custom component that keeps track of the "showing" state of its children, and fires some notification whenever that state changes. JViewPort might be good for starters, but is a nasty one iirc ;) – kleopatra Oct 04 '18 at 09:34
  • @kleopatra I was afraid you would reply that ;) A use case would be triggering a load when components of a scroll pane are shown (a few out of several thousand) and freeing that memory when those components scroll beyond visibility. – Matthieu Oct 04 '18 at 14:27
7

I assume that this container is already visible on the screen, then I suggest

1) to extract JViewPort from JScrollPane,

2) addChangeListener to JViewPort

3) each visible JComponent(s) returns Rectangle

4) and Rectangle#intersects returns Boolean value if is JComponent(s) visible or not in JViewPort

mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • enjoying detours, don't you :-) nothing of that is needed, except bullet 3 and the first part of bullet 4 ... – kleopatra Dec 13 '11 at 11:29
1

How about asking the components if they're visible:

for ( Component component : jpanel.getComponents() ) {
    if ( component instanceof JButton && component.isShowing() ) {
        // We've found a button that is showing...
    }
}
Nate W.
  • 9,141
  • 6
  • 43
  • 65
  • 1
    this will not work becouse if i scroll the scrollpane there are components that are currently not visible the function isShowing will for every component return true even if there are not visible for the user... sry – Leon Dec 13 '11 at 09:45
  • simply wrong - the OP clearly stated "not all .. [but only] currently on screen" (okay, maybe slightly misunderstandable :-) – kleopatra Dec 13 '11 at 11:07
0
scrollPane.getViewport().getView()
scrollPane.getViewport().getViewRect()
StanislavL
  • 56,971
  • 9
  • 68
  • 98