Java/Swing:无法让 JScrollPane 显示整个元素

问题描述 投票:0回答:1

目标是在 JPanel 上绘制一堆圆圈(每个圆圈都是一个单独的 JComponent 实例),并且能够在任何方向上滚动足够远以查看所有圆圈。

这是“主要”代码:

JFrame frame = new JFrame();
JPanel panel = new JPanel(new BorderLayout());
panel.add(new Circle(-100, 0, 200));
panel.add(new Circle(-25, 0, 650));
JScrollPane scrollPane = new JScrollPane (panel);
frame.add(scrollPane);
frame.setSize(600, 600);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);

这是 Circle 类:

public class Circle extends JComponent {
        private int x;
        private int y;
        private int width;

    public Circle(int x, int y, int width) {
        this.x = x;
        this.y = y;
        this.width = width;
    }
    
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.RED);
        g.fillOval(this.x, this.y, this.width, this.width);
    }
}

有几个我似乎无法解决的问题:

  1. JPanel 除非其布局设置为 BorderLayout,否则不会显示任何圆圈;当它设置为 BorderLayout 时,它只显示最后添加到其中的圆。
  2. 我尝试使用 JScrollPane 使 JPanel 可滚动。但是,当我绘制一个超大圆圈来检查它是否有效时,JScrollPane 不会显示滚动条来查看全部内容。 (见下图)

不可滚动,看不到整个组件。

希望这是可以理解的,我对 Swing 非常陌生。任何想法都将受到高度赞赏!

java swing user-interface jpanel jscrollpane
1个回答
0
投票

诊断: 第一个问题是没有考虑到尺寸 您正在使用的屏幕。 第二个问题是您将 JScrollPane 分配给 Frame 而不是 JPanel,JPanel 必须滚动才能显示绘制的对象。 第三个问题是使用BorderLayout,它限制你只能表示中心的对象,这一点已被一位同事在他的评论中提到。虽然这可能是最不严重的。

为什么要考虑屏幕尺寸? 因为你必须想象你有一张纸或画布,你想在上面画一个圆圈,所述布的尺寸为 1x1 米,而你的圆圈的半径为 0.75 米,这将得到 1.50 米的直径,这显然是它不会完全适合纸张或画布。

正如您所解释的,您是新手,我建议将对象(JFrame、JPanel 和 Circle)分成不同的类,以便您更轻松地识别任何问题、使用元素的值并了解其中每一个如何他们有效。 。 这种类的分离不是强制性的,但强烈建议这样做,尤其是当您的项目不断增长时。请放心,您不想遇到执行很多操作(包括让您感到困惑)的庞大类。

考虑到这一点,我写了一个解决方案,希望对你有帮助:

主课

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

import circlepanel.CirclePanel;

public class Main {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("Circles in a JPanel");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            CirclePanel circlePanel = new CirclePanel();
            JScrollPane scrollPane = new JScrollPane(circlePanel);
            scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
            scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

            frame.add(scrollPane);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

圆形面板类

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JPanel;

import circle.Circle;

public class CirclePanel extends JPanel {
    
    private static final long serialVersionUID = 6595277960964126231L;
    private List<Circle> circles;

    public CirclePanel() {
        
        circles = new ArrayList<>();
        
        // Examples of circles
        circles.add(new Circle(50, 50, 30));
        circles.add(new Circle(150, 100, 20));
        circles.add(new Circle(800, 800, 650));
       
        /*
        // Calculate panel size based on circles and window size
        int maxX = circles.stream().mapToInt(c -> c.getX() + c.getRadius()).max().orElse(0);
        int maxY = circles.stream().mapToInt(c -> c.getY() + c.getRadius()).max().orElse(0);
        int preferredWidth = Math.max(maxX + 10, 1800); // Adjust the width to 1880 depending on the desired window size
        int preferredHeight = Math.max(maxY + 10, 1400); // Adjust the height to 1400 according to the desired window size
        setPreferredSize(new Dimension(preferredWidth, preferredHeight));
        */
        
     // Calculate panel size based on circles and window size            
        int maxX = 0;
        int maxY = 0;
        for (Circle circle : circles) {
            maxX = Math.max(maxX, circle.getX() + circle.getRadius());
            maxY = Math.max(maxY, circle.getY() + circle.getRadius());
        }
        int preferredWidth = Math.max(maxX + 10, 1880); // Adjust the width to 1880 depending on the desired window size
        int preferredHeight = Math.max(maxY + 10, 1400); // Adjust the height to 1400 according to the desired window size
        setPreferredSize(new Dimension(preferredWidth, preferredHeight));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // Draw the circles
        for (Circle circle : circles) {
            g.drawOval(circle.getX() - circle.getRadius(), circle.getY() - circle.getRadius(),
                    2 * circle.getRadius(), 2 * circle.getRadius());
            
            g.setColor(Color.RED);
            g.fillOval(circle.getX() - circle.getRadius(), circle.getY() - circle.getRadius(), 2 * circle.getRadius(), 2 * circle.getRadius());
        }
    }
}

圆班

public class Circle {
    private int x;
    private int y;
    private int radius;

    public Circle(int x, int y, int radius) {
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getRadius() {
        return radius;
    }
}

在 CirclePanel 类中,有一部分注释代码,被紧随其后的代码替换。 注释代码正在通过更高效的 Lambda 表达式查找所有示例圆的最大半径、x 轴和 Y 轴尺寸。下面的代码有些更传统,使用 FOR 迭代包含定义为示例的圆形对象的 ArrayList。

希望对你有帮助,作为一个提示,请查阅你所使用的Java版本的API,以对你要使用的组件有更完整的了解,如果可能的话,在你的空闲时间查阅它,将会有很大帮助。扩大你的视野。 .

最后,不要忘记最大化 JFrame,以便出现两个滚动面板。

© www.soinside.com 2019 - 2024. All rights reserved.