在JScrollPane的视口上绘制静态图像

Peskal:

我试图在JScrollPane上绘制一个红色正方形。我下面的代码可以很好地完成此工作,但是有时当我过快滚动视口时,红色正方形会上下跳动。

在此处输入图片说明

因为JScrollPane本身是固定的,所以这让我感到很奇怪,因此我认为Swing不会尝试在其中绘制的组件周围移动。我猜测实际发生的是红色正方形与视口相关联,视口显示确实在移动的图形。

无论如何,如何防止红色方块跳来跳去并成功在列表上绘制红色方块?也许我完全采用了错误的方法。

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();
      }
    });
  }
}
充满鳗鱼的气垫船:

JScrollPane应该画 JViewport的后面,而JViewport应该画列表的后面我猜想这仅是有效的,因为您覆盖了paint而不是paintComponent,并且一直在JScrollPane上调用repaint,以便它在绘制其组件之后再次进行自我绘制。

也许您想使用JLayeredPane并让它保持JScrollPane并在其上绘画。

编辑:或者就像我现在看到的那样建议的玻璃窗格,但是如果您这样做,并且将玻璃窗格设置为可见,恐怕您将失去与基础滚动窗格进行交互的能力。

编辑2
例如

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章