如何在 BorderLayout.SOUTH 中添加一个矩形?

How can I add a rectangle in BorderLayout.SOUTH?

我正在尝试在我的 swing 音乐播放器应用程序中添加类似 this 的内容。

我试图向 BorderLayout.SOUTH 添加一个矩形,但它从未出现在屏幕上。这是我做了什么

public class MyDrawPanel extends JPanel {

    @Override
    public void paintComponent(Graphics g) {
        g.setColor(Color.GREEN);
        g.fillRect(200,200,200,200);

    }


    public static void main(String[] args) {
        JFrame frame = new JFrame();
        MyDrawPanel a = new MyDrawPanel();
        frame.getContentPane().add(BorderLayout.SOUTH,a);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(1000,1000);
        frame.setVisible(true);
    }

}

我只是没有尝试 200,200,200,200,但我尝试了很多值,即使在 for 循环的帮助下,但它从未出现在屏幕上。如果我使用 CENTER 而不是 SOUTH 它就会出现。我阅读了文档以检查 fillRect 是如何工作的,但它只是说它添加了 x+width 和 y+height。 (0,0) 点是左上角。我通过向 CENTER 布局添加一个矩形来检查。我是怎么做到的?

我没有分享输出,因为它只是一个空白屏幕。

您给 fillRect 的值是错误的。前两个是左上角的坐标,相对于您正在绘制的组件;在你的例子中 MyDrawPanel。使用您发布的代码,此绘图区域位于放置面板的容器之外。您想要做的

g.fillRect(0,0,200,200);

注意:您通常希望在添加完所有组件后调用 frame.pack(),以便它可以自行布局。在您的情况下,这会导致 window 很小,因为系统不知道它应该有多大。您可能想添加一个方法

public Dimension getPreferredSize() {
    System.out.println("getting pref size");
    return new Dimension(200, 200);
}

确保它始终足够大以绘制整个矩形。

还有,你应该先打电话给frame.getContentPane().setLayout(new BorderLayout())。您可以在不设置的情况下将其打印出来,以查看它是否不是默认设置。编辑:正如 VGR 指出的那样,文档说它实际上是一个 BorderLayout。我无法确认是这种情况 - 它实际上是 RootLayout。不过,这似乎表现得像 BorderLayout

我认为这可能会成为一个快速的小项目。这是我想出的电平表。

重要的部分是 DrawingPanelLevelMeterModelDrawingPanelLevelMeterModel 获取信息并在 JPanel.

上绘制条形图

LevelMeterModel 是一个整型数组,包含最低级别和最高级别。可以计算最大音量,但我假设音乐有一定的音量和频率范围。

JFrame持有DrawingPanel。 Swing Timer 会随机改变级别。随机数在一个小范围内,因此条形高度不会突然改变。

这是完整的可运行代码。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class LevelMeterGUI implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new LevelMeterGUI());
    }
    
    private final DrawingPanel drawingPanel;
    
    private final LevelMeterModel model;
    
    public LevelMeterGUI() {
        this.model = new LevelMeterModel();
        this.drawingPanel = new DrawingPanel(model);
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Level Meter GUI");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.add(drawingPanel, BorderLayout.CENTER);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
        
        System.out.println("Frame size: " + frame.getSize());
        
        Timer timer = new Timer(250, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                model.setRandomLevels();
                drawingPanel.repaint();
            }
        });
        timer.start();
    }
    
    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;
        
        private final int drawingWidth, drawingHeight, margin, rows;
        
        private final Dimension barDimension;
        
        private final LevelMeterModel model;
        
        public DrawingPanel(LevelMeterModel model) {
            this.model = model;
            this.margin = 10;
            this.rows = 20;
            this.barDimension = new Dimension(50, 10);
            
            int columns = model.getLevels().length;
            drawingWidth = columns * barDimension.width + (columns + 1) * margin;
            drawingHeight = rows * barDimension.height + (rows + 1) * margin;
            
            this.setBackground(Color.WHITE);
            this.setPreferredSize(new Dimension(drawingWidth, drawingHeight));
        }
        
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            
            int maximum = model.getMaximumLevel();
            double increment = (double) maximum / rows;
            
            int peak = rows * 75 / 100;
            int x = margin;
            for (int level : model.getLevels()) {
                int steps = (int) Math.round((double) level / increment);
                int y = drawingHeight - margin - barDimension.height;
                for (int index = 0; index < steps; index++) {
                    if (index < peak) {
                        g.setColor(Color.GREEN);
                    } else {
                        g.setColor(Color.RED);
                    }
                    g.fillRect(x, y, barDimension.width, barDimension.height);
                    y = y - margin - barDimension.height;
                }
                x += margin + barDimension.width;
            }
        }
        
    }
    
    public class LevelMeterModel {
        
        private final int minimumLevel, maximumLevel;
        
        private int[] levels;
        
        private final Random random;
        
        public LevelMeterModel() {
            this.minimumLevel = 100;
            this.maximumLevel = 999;
            this.levels = new int[8];
            this.random = new Random();
            setRandomLevels();
        }
        
        public void setRandomLevels() {
            for (int index = 0; index < levels.length; index++) {
                levels[index] = getRandomLevel(levels[index]);
            }
        }
        
        private int getRandomLevel(int level) {
            if (level == 0) {
                return random.nextInt(maximumLevel - minimumLevel) + minimumLevel;
            } else {
                int minimum = Math.max(level * 90 / 100, minimumLevel);
                int maximum = Math.min(level * 110 / 100, maximumLevel);
                return random.nextInt(maximum - minimum) + minimum;
            }
        }

        public int[] getLevels() {
            return levels;
        }

        public int getMinimumLevel() {
            return minimumLevel;
        }

        public int getMaximumLevel() {
            return maximumLevel;
        }
        
    }

}