没有布局管理器的可滚动 JPanel

Scrollable JPanel Without a Layout Manager

我想在可垂直和水平滚动的 JPanel 上显示正弦曲线。如果没有布局管理器,我该如何实现?

请看下面的代码。我需要一个垂直滚动条来查看正弦曲线的底部。

不使用布局管理器很重要。

提前致谢。

package drawsinus;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class DrawSinus extends JPanel
{
       private static double[] x;
       private static double[] y;
       private static JFrame frame = new JFrame();
       private static JPanel panel = new DrawSinus(); 
       
       public void paintComponent(Graphics g) 
       {
             super.paintComponent(g);
      
             Image img = generateSinus();
             g.drawImage(img, 20,20, this);
     
       }
       private Image generateSinus() 
       {
      
             BufferedImage bufferedImage = new BufferedImage(600, 600, BufferedImage.TYPE_INT_RGB);
             Graphics g = bufferedImage.getGraphics();
             x = new double[200];
             y = new double[200];
             for (int t=0; t<=199; t++)
             {                 
                 x[t]= (double)t;
                 y[t] = 300*Math.sin(2*Math.PI*1*t/200);              
             }
             for (int t=0; t<x.length; t++)
             {                   
                 g.fillOval((int)x[t] + bufferedImage.getWidth()/2, -1*((int)y[t]) + bufferedImage.getHeight()/2, 20, 20);                         
             }
            
             return bufferedImage;
      
       }
       public static void main(String[] args) 
       {
             frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
             frame.setSize(800,600);
             frame.setLayout(null);
             frame.setLocationRelativeTo(null);
             frame.setVisible(true);

             panel.setLayout(null);
             panel.setBounds(20, 20, 600, 400);
             panel.setBackground(Color.BLACK);

             frame.add(panel);

             JScrollPane scrPane = new JScrollPane(panel);
             scrPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
             scrPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
             frame.add(scrPane);

             new DrawSinus().generateSinus();
            
       }
    
}

这里是如何可以完成的最小示例。

滚动窗格内的组件必须实现 Scrollable 接口或设置首选大小,滚动窗格使用它来确定其视口视图的大小。

我更喜欢覆盖 getPreferredSize,因此它 动态地 如果图像发生变化(在这个最小示例中不可能)并避免使用首选大小 外部setPreferredSize() 更改。

public class DrawSinus2 {

    public static void main(String[] args) {
        // Swing's Thread Police: All Swing components and related classes, unless
        // otherwise documented, must be accessed on the event dispatching thread.
        SwingUtilities.invokeLater(DrawSinus2::initGUI);
    }
    
    private static void initGUI() {
        // Panel to draw image
        JPanel sinusPanel = new JPanel() {
            private final Image image = generateSinus();
            
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                if (image != null) {
                    g.drawImage(image, 0, 0, this);
                }
            }
            
            // Preferred size used by scroll pane
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(image.getWidth(this), image.getHeight(this));
            }
        };

        // Scroll pane containing the image panel
        JScrollPane scrPane = new JScrollPane(sinusPanel);
        scrPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
        scrPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        scrPane.setBounds(0, 0, 600, 400);

        // Main frame displaying the scroll pane
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(null);
        frame.setSize(800, 600);
        frame.add(scrPane);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
    
    private static Image generateSinus() {
        // generate and return some image
    }
}