开发者

Drawing a static image over the viewport of a JScrollPane

开发者 https://www.devze.com 2023-03-27 06:19 出处:网络
I am trying to draw a red square over a JScrollPane. The code I have below does an okay job of this, but sometimes when I scroll the viewport too fast, the red square jumps up or down.

I am trying to draw a red square over a JScrollPane. The code I have below does an okay job of this, but sometimes when I scroll the viewport too fast, the red square jumps up or down.

Drawing a static image over the viewport of a JScrollPane

This struck me as odd since the JScrollPane itself is stationary, so I assumed Swing would not try to move around the components painted within it. I'm guessing that what's actually happening is that the the red square gets associated with viewport, which display graphics that do move.

Anyway, how do I prevent the red square from jumping around and successfully draw a red square over the list? Maybe I'm taking the wrong approach altogether.

package components;

import java.awt.*;
import java.util.Vector;

import javax.swing.*;
import javax.swing.event.*;

@SuppressWarnings("serial")
public class DialogWithScrollPane extends JFrame {

  public DialogWithScrollPane() {
    super();

    setResizable(false);
    Container pane = getContentPane();

    Vec开发者_Go百科tor<Object> listOfStuff = new Vector<Object>();
    for (int i = 0; i < 100; i++) {
      listOfStuff.add(Integer.toString(i));
    }

    final JScrollPane scrollPane = new JScrollPane() {

      public void paint(Graphics g) {
        System.out.println("JScrollPane.paint() called.");
        super.paint(g);

        g.setColor(Color.red);
        g.fillRect(20, 50, 100, 200);
      }
    };
    JList list = new JList(listOfStuff) {
      public void paint(Graphics g) {
        System.out.println("JList.paint() called.");
        super.paint(g);

        // Well, I could do this...
            //
        // scrollPane.repaint();
        //
        // ...and it would solve the problem, but it would also result in an
        // infinite recursion since JScrollPane.paint() would call this
        // function again.
      }
    };

    // Repaint the JScrollPane any time the viewport is moved or an item in the
    // list is selected.
    scrollPane.getViewport().addChangeListener(new ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        scrollPane.repaint();
      }
    });
    list.addListSelectionListener(new ListSelectionListener() {
      public void valueChanged(ListSelectionEvent e) {
        scrollPane.repaint();
      }
    });

    scrollPane.setViewportView(list);

    pane.add(scrollPane);
    setMinimumSize(new Dimension(300, 300));
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLocation(500, 250);
    setVisible(true);
  }

  public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        new DialogWithScrollPane();
      }
    });
  }
}


The JScrollPane should be painting behind the JViewport which should be painting behind the list. I'm guessing that this is only working because you're overriding paint and not paintComponent and calling repaint on the JScrollPane all the time so that it paints itself again after its components are painted.

Perhaps you want to use a JLayeredPane and have it hold the JScrollPane, and paint on it.

edit: or the glasspane as I now see that mre suggests, but I'm afraid if you do that, and set the glasspane visible, you'll lose the ability to interact with the underlying scrollpane.

Edit 2
For e.g.,

import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Vector;
import javax.swing.*;

@SuppressWarnings("serial")
public class DialogWithScrollPane2 extends JFrame {

   public DialogWithScrollPane2() {
      super();

      //setResizable(false);
      final JPanel pane = (JPanel) getContentPane();

      Vector<Object> listOfStuff = new Vector<Object>();
      for (int i = 0; i < 100; i++) {
         listOfStuff.add(Integer.toString(i));
      }

      final JScrollPane scrollPane = new JScrollPane();
      JList list = new JList(listOfStuff);

      scrollPane.setViewportView(list);

      final JPanel blueRectPanel = new JPanel() {
         @Override
         protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.blue);
            g.fillRect(20, 50, 100, 200);
         }
      };
      blueRectPanel.setOpaque(false);

      final JLayeredPane layeredPane = new JLayeredPane();
      layeredPane.add(scrollPane, JLayeredPane.DEFAULT_LAYER);
      layeredPane.add(blueRectPanel, JLayeredPane.PALETTE_LAYER);

      layeredPane.addComponentListener(new ComponentAdapter() {

         private void resizeLayers() {
            final JViewport viewport = scrollPane.getViewport();
            scrollPane.setBounds(layeredPane.getBounds());
            blueRectPanel.setBounds(viewport.getBounds());
            SwingUtilities.invokeLater(new Runnable() {
               public void run() {
                  blueRectPanel.setBounds(viewport.getBounds());
               }
            });
         }

         @Override
         public void componentShown(ComponentEvent e) {
            resizeLayers();
         }

         @Override
         public void componentResized(ComponentEvent e) {
            resizeLayers();
         }
      });

      pane.add(layeredPane);
      setPreferredSize(new Dimension(300, 300));
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      pack();
      setLocation(500, 250);
      setVisible(true);
   }

   public static void main(String[] args) {
      javax.swing.SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            new DialogWithScrollPane2();
         }
      });
   }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消