简体   繁体   English

在 JScrollPane 的视口上绘制 static 图像

[英]Drawing a static image over the viewport of a JScrollPane

I am trying to draw a red square over a JScrollPane.我正在尝试在 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.我下面的代码在这方面做得很好,但有时当我滚动视口太快时,红色方块会向上或向下跳跃。

在此处输入图像描述

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.这让我觉得很奇怪,因为 JScrollPane 本身是固定的,所以我假设 Swing 不会尝试在其中绘制的组件周围移动。 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();

    Vector<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. JScrollPane 应该画在 JViewport后面,而 JViewport 应该画在列表后面 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.我猜这只是因为你覆盖了paint而不是paintComponent,并且一直在JScrollPane上调用repaint,以便它在绘制其组件后再次绘制自己。

Perhaps you want to use a JLayeredPane and have it hold the JScrollPane, and paint on it.也许您想使用 JLayeredPane 并让它持有 JScrollPane,并在其上绘画。

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.编辑:或者我现在看到的玻璃窗格,mre 建议,但我担心如果你这样做,并将玻璃窗格设置为可见,你将失去与底层滚动窗格交互的能力。

Edit 2编辑 2
For eg,例如,

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();
         }
      });
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM