5 Replies Latest reply: May 12, 2011 1:08 AM by 806562 RSS

    JScrollBar not working

    806562
      I have a JPanel which displays a list of videos. Each video has basic information (title, description, thumbnails etc) in its own JPanel; these panels are then placed into another JPanel using a BoxLayout. I then put that JPanel into a JScrollPane, and the scrollpane is added to yet another JPanel, which also holds a panel for navigation arrows. The constructor for the main panel doesn't actually add the inidividual video panels: it only adds the navigation panel, the videos display panel, and the JScrollPane:
      public VideosDisplay(int width, int height)
          {
              setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
              setBackground(Color.WHITE);
      
              videosPanel = new JPanel();
              videosPanel.setLayout(new BoxLayout(videosPanel, BoxLayout.Y_AXIS));
              videosPanel.setPreferredSize(new Dimension(width, height));
              videosPanel.setBackground(Color.WHITE);
              videosPanel.setAlignmentX(LEFT_ALIGNMENT);
              videosPanel.setBorder(BorderFactory.createEmptyBorder(VIDEOS_PANEL_BORDER_HEIGHT, VIDEOS_PANEL_BORDER_WIDTH, VIDEOS_PANEL_BORDER_HEIGHT, VIDEOS_PANEL_BORDER_WIDTH));
      
              JScrollPane videoScroll = new JScrollPane(videosPanel);
              videoScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
              videoScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
              add(videoScroll);
      
              navigationPanel = new VideosNavigationPanel();
              navigationPanel.setBackground(Color.WHITE);
              navigationPanel.setAlignmentX(LEFT_ALIGNMENT);
              add(navigationPanel);
          }
      The actual video panels are added by a SwingWorker, whose doInBackground method is thus:
      @Override
              protected Void doInBackground() throws Exception
              {
                  VideoInfoPanel[] panels = new VideoInfoPanel[videos.size()];
                  for(int index = 0; index < videos.size(); index++) //THIS LOADS THE PANELS
                  {
                      VideoInfoPanel panel = new VideoInfoPanel(videos.get(index));
                      Border padding = BorderFactory.createEmptyBorder(PADDING, PADDING, PADDING, PADDING);
                      panel.setBorder(BorderFactory.createCompoundBorder(padding, panel.getBorder()));
                      panels[index] = panel;
                      videosPanel.add(panel);
                  }
      
                  int panelIndex = 0;
                  while(!isCancelled() && panelIndex < panels.length) //THIS LOADS THE INDIVIDUAL THUMBNAILS IN THE PANELS
                  {
                      VideoInfoPanel panel = panels[panelIndex];
                      int thumbnailIndex = 0;
                      boolean thumbnailsToLoad = true;
                      while(!isCancelled() && thumbnailsToLoad)
                      {
                          thumbnailsToLoad = panel.loadThumbnail(thumbnailIndex);
                          thumbnailIndex++;
                      }
      
                      panelIndex++;
                  }
      
                  return null;
              }
      However, while the vertical scrollbar shows up, it is not active, even though only two (or even one-and-a-half) video panels are visible in available space. When I resize the screen and make it smaller, the scroller becomes active, but only allows scrolling to the bottom of the second video panel (or to the bottom of the original displayed area - this might be halfway down the second panel). There are 5 video panels on the page, but the last three appear not to exist.
      Obviously I want the user to be able to scroll to the fifth video. Can anybody spot what I'm doing wrong?

      The code for the individual video panel is below. It's a little more complex than the rest...
      public VideoInfoPanel(VideoData data)
          {
              setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
              setBackground(Color.WHITE);
              Border lineBorder = BorderFactory.createLineBorder(FontsColors.THEME_COLOR);
              Border padding = BorderFactory.createEmptyBorder(BORDER_PADDING, BORDER_PADDING, BORDER_PADDING, BORDER_PADDING);
              setBorder(BorderFactory.createCompoundBorder(lineBorder, padding));
              setAlignmentX(LEFT_ALIGNMENT);
      
              Hyperlink titleLink = new Hyperlink(data.getTitle(), data.getVideoUrls().getPageUrl(), FontsColors.TITLE_FONT, FontsColors.TITLE_COLOR);
              titleLink.setAlignmentX(LEFT_ALIGNMENT);
              titleLink.setBorder(BorderFactory.createEmptyBorder(COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING));
              add(titleLink);
              Hyperlink authorLink = new Hyperlink("By " + data.getAuthor().getName(), data.getAuthor().getPageUrl(), FontsColors.SUBTITLE_FONT, FontsColors.SUBTITLE_COLOR);
              authorLink.setAlignmentY(LEFT_ALIGNMENT);
              authorLink.setBorder(BorderFactory.createEmptyBorder(COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING));
              add(authorLink);
      
              JTextArea descriptionArea = new JTextArea(data.getDescription());
              descriptionArea.setEditable(false);
              descriptionArea.setLineWrap(true);
              descriptionArea.setWrapStyleWord(true);
              descriptionArea.setAlignmentX(LEFT_ALIGNMENT);
              descriptionArea.setBorder(BorderFactory.createEmptyBorder(COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING));
              add(descriptionArea);
      
              JLabel durationLabel = new JLabel("Length:");
              durationLabel.setFont(FontsColors.EMPHASIS_FONT);
              durationLabel.setForeground(FontsColors.EMPHASIS_COLOR);
              durationLabel.setBorder(BorderFactory.createEmptyBorder(COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING));
              JLabel durationValueLabel = new JLabel(data.getDurationMinutesSeconds());
              durationValueLabel.setBorder(BorderFactory.createEmptyBorder(COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING));
      
              JLabel viewsLabel = new JLabel("Views:");
              viewsLabel.setFont(FontsColors.EMPHASIS_FONT);
              viewsLabel.setForeground(FontsColors.EMPHASIS_COLOR);
              viewsLabel.setBorder(BorderFactory.createEmptyBorder(COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING));
              JLabel viewsValueLabel = new JLabel(Long.toString(data.getViews()));
              viewsValueLabel.setBorder(BorderFactory.createEmptyBorder(COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING));
              
              JPanel durationViewsPanel = new JPanel();
              durationViewsPanel.setLayout(new BoxLayout(durationViewsPanel, BoxLayout.X_AXIS));
              durationViewsPanel.setBackground(Color.WHITE);
              durationViewsPanel.setAlignmentX(LEFT_ALIGNMENT);
              durationViewsPanel.add(durationLabel);
              durationViewsPanel.add(durationValueLabel);
              durationViewsPanel.add(viewsLabel);
              durationViewsPanel.add(viewsValueLabel);
              add(durationViewsPanel);
              
              JPanel thumbnailsPanel = new JPanel();
              thumbnailsPanel.setLayout(new BoxLayout(thumbnailsPanel, BoxLayout.X_AXIS));
              thumbnailsPanel.setBackground(Color.WHITE);
              thumbnailsPanel.setAlignmentX(LEFT_ALIGNMENT);
              thumbnailCollection = data.getThumbnails();
              thumbnails = new ThumbnailButton[thumbnailCollection.size()];
              for(int index = 0; index < thumbnailCollection.size(); index++)
              {
                  ThumbnailData thumbnailData = thumbnailCollection.get(index);
                  ThumbnailButton thumbnail = new ThumbnailButton(thumbnailData.getWidth(), thumbnailData.getHeight());
                  JPanel thumbnailPanel = new JPanel();
                  thumbnailPanel.setBackground(Color.WHITE);
                  thumbnailPanel.setBorder(BorderFactory.createEmptyBorder(COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING));
                  thumbnails[index] = thumbnail;
                  thumbnailPanel.add(thumbnail);
                  thumbnailsPanel.add(thumbnailPanel);
              }
              add(thumbnailsPanel);
      
              Hyperlink pageLink = new Hyperlink(data.getVideoUrls().getPageUrl(), data.getVideoUrls().getPageUrl(), FontsColors.SUBTITLE_FONT, FontsColors.SUBTITLE_COLOR);
              pageLink.setAlignmentX(LEFT_ALIGNMENT);
              pageLink.setBorder(BorderFactory.createEmptyBorder(COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING, COMPONENT_PADDING));
              add(pageLink);
          }
        • 1. Re: JScrollBar not working
          793415
          For better help sooner, post an SSCCE with emphasis on the first 'S'. So that would mean no extraneous code (like setting colors).
          • 2. Re: JScrollBar not working
            camickr
            Don't set the preferred size of the videosPanel.

            The layout manager will determine the preferred size dynamically as you add components to the panel.
            • 3. Re: JScrollBar not working
              806562
              Thank you, camickr, you have solved the problem. I set the preferred size of the main JPanel (that holds both the videosPanel and navigationPanel) instead of setting the videosPanel size. However, I now have the navigation panel taking up half the main JPanel.

              Is there any way to tell Swing to make a JPanel as compact as possible, without compressing components, but without specifying an exact size? The navigation panel code is below. I want it to be as wide as the main panel (since there is nothing to the left or right) but I do not want it to be any higher than it needs to be. It only needs to be high enough to fit the navigation buttons, each of which is 75px high. So, with a bit of padding, I would want the box to be ~85px high. I have added vertical struts of that height, but the final height of the panel (which is a horizontal box) is significantly more.

              I would prefer not to have to provide the width of the panel to the Navigation panel, as I have used it multiple times and so would have to alter the code in several places. Is there any way, then, to tell swing to make the Navigation panel take up as little room as possible?

                  public NavigationPanel()
                  {
                      super(BoxLayout.X_AXIS);
                      
                      add(Box.createVerticalStrut(VERTICAL_PADDING));
                      add(Box.createHorizontalGlue());
                      
                      previousButton = new BlobButton(new ImageIcon(ImageFiles.ARROW_BACK));
                      previousButton.setEnabled(false);
                      add(previousButton);
              
                      add(Box.createHorizontalStrut(PADDING_BETWEEN_BUTTONS));
                      
                      nextButton = new BlobButton(new ImageIcon(ImageFiles.ARROW_FORWARD));
                      nextButton.setEnabled(false);
                      add(nextButton);
                      
                      add(Box.createHorizontalGlue());
                      add(Box.createVerticalStrut(VERTICAL_PADDING));
              
                      currentPage = 1;
                      totalPages = 1;
                  }
              • 4. Re: JScrollBar not working
                camickr
                Try different layout managers. Maybe a BorderLayout. Adding a component to the NORTH (or SOUTH) will cause the components width to expand/contract to fill the available space, but the hieght will only be what is required.
                • 5. Re: JScrollBar not working
                  806562
                  Of course. Thank you, camickr