【问题标题】:How can I add a rectangle in BorderLayout.SOUTH?如何在 BorderLayout.SOUTH 中添加一个矩形?
【发布时间】:2021-08-01 21:56:23
【问题描述】:

我正在尝试在我的音乐播放器应用程序中添加类似 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 布局中添加一个矩形来检查这一点。我该怎么做?

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

【问题讨论】:

  • 我已将矩形添加到 JPanel 并将 JPanel 添加到 JFrame
  • 在添加绘图面板之前,您需要将LayoutManager设置为框架的ContentPane,即frame.getContentPane().setLayoutManager(new BorderLayout())
  • JFrame默认是边框布局,所以不需要添加
  • 自定义绘制的组件需要返回一个足够大的首选尺寸以显示其呈现的内容,作为对布局管理器的提示。侧边栏:在覆盖绘制方法时,始终首先调用super 方法。侧边栏 2:将 frame.setSize(1000,1000); 替换为 frame.pack(); ..

标签: java swing jframe jpanel paintcomponent


【解决方案1】:

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

重要的部分是DrawingPanelLevelMeterModelDrawingPanelLevelMeterModel 获取信息并在JPanel 上绘制条形图。

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

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

}

【讨论】:

    【解决方案2】:

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

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

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

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

    确保它总是足够大以绘制整个矩形。

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

    【讨论】:

    • @VGR 这就是我上面提到的,我想不出任何在南方显示的坐标,你能帮忙。
    • @daniu 你的回答部分正确,我会给你,但我显然不能改变矩形的高度(我可以改变宽度)有什么解决办法吗?
    • @VGR 这很奇怪。我进入了源代码的兔子洞,默认情况下,JFrame 创建了一个使用RootLayoutJRootPane,但它不继承自BorderLayout。它可能表现得像一个,但 IIUC,这样的文档是不正确的。
    • @ThunderKnight 我不明白我的答案是如何不完全正确的。你的问题是如何让矩形出现在 SOUTH 中,我回答了这个问题。如何让它调整大小从来都不是问题的一部分,所以我看不出我怎么能回答这个问题。事实上,这是一个单独的问题,您应该为此打开一个新问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-09
    • 2016-05-28
    • 1970-01-01
    相关资源
    最近更新 更多