【问题标题】:Drawing graphics on a panel在面板上绘制图形
【发布时间】:2019-07-15 21:22:12
【问题描述】:

我正在尝试在面板上绘制图形,但我不知道该怎么做。

我尝试创建一个扩展 JPanel 并覆盖paintComponent 的类以及其他一些方法,但根本没有渲染任何内容。

这是我的代码:

edit:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Lesson1 extends JFrame {

    private static final long serialVersionUID = -198253288329146091L;
    private JPanel contentPane;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    Lesson1 frame = new Lesson1();
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public Lesson1() {

        contentPane = new JPanel();
        setContentPane(contentPane);

        JPanel panel = new JPanel() {

            private static final long serialVersionUID = -5974584127539186578L;

            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setColor(Color.GREEN);
                g.fillRect(0, 0, 500, 500);
            }

            @Override
            public Dimension getPreferredSize() {
                return new Dimension(500, 500);
            }

        };

        contentPane.add(panel);

        JPanel panel_1 = new JPanel() {

            private static final long serialVersionUID = 123456789L;

            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setColor(Color.PINK);
                g.fillRect(0, 0, 200, 200);
            }

            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }

        };

        panel.setLayout(new BorderLayout());
        panel_1.setLayout(new BorderLayout());
        panel.add(panel_1);

    }

}

我不确定我在这里做错了什么,但我已尽我所能。谢谢!

【问题讨论】:

  • 阅读 Custom Painting 上的 Swing 教程中的部分以获取工作示例。从工作示例开始,根据需要自定义绘制代码。

标签: java swing layout jframe jpanel


【解决方案1】:

错误 #1

contentPane.setLayout(null);

panel.setLayout(null);

在你做任何其他事情之前,你需要学习和理解布局管理器实际上做了什么以及为什么null 布局是幼稚的并且不被推荐(尤其是当你刚刚学习时)。

先花时间浏览Laying Out Components Within a Container

删除contentPane.setLayout(null); 并将panel.setLayout(null); 更改为panel.setLayout(new BorderLayout());,您将立即看到更改。

事实上,你真的不需要panel,因为JFrame 的默认contentPane 已经设置为使用BorderLayout

这意味着你可以摆脱panel.setBounds(73, 52, 231, 143);

错误 #2

好吧,这更像是一个疏忽,但是,当您开始自定义组件时,您需要提供尺寸提示,这允许布局管理器决定如何最好地布局您的组件与其他组件的关系并基于这是自己的内部规则。

为此,您至少应该重写getPreferredSize 方法(避免使用setXxxSize 方法,因为如果使用不当可能会导致意外结果)

添加...

@Override
public Dimension getPreferredSize() {
    return new Dimension(1001, 1001);
}

panel_1

这意味着你现在可以做一些类似...的事情

Lesson1 frame = new Lesson1();
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);

并且窗口会自动将其包裹在组件周围(并在屏幕上居中),您可以摆脱setBounds(100, 100, 450, 300);

好吧,无论如何我尝试了但没有成功,所以我可以将面板设置在特定位置:/

GUI 环境中的布局管理部分是科学,部分是巫术,部分是黑魔法

像素完美定位是现代 UI 开发中的一种错觉。决定组件“如何”放置在单个平台上的因素太多了,更不用说跨多个平台了,你会在余生中不断添加“hacks”来解决无限数量的可能边缘情况。

这就是为什么任何体面的 UI 框架都会抽象概念的原因,Swing 使用布局管理器 API 来实现此目的,iOS(和 MacOS)使用自动布局等......

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Lesson1 {

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        new Lesson1();
    }

    public Lesson1() {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    JFrame frame = new JFrame();
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new GridBagLayout());

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.anchor = GridBagConstraints.NORTHWEST;

            add(new RectPane(), gbc);

            gbc.gridx = 2;
            gbc.anchor = GridBagConstraints.NORTHEAST;
            add(new RectPane(), gbc);

            gbc.gridx = 1;
            gbc.gridy = 1;
            gbc.anchor = GridBagConstraints.CENTER;
            gbc.weightx = 1;
            gbc.weighty = 1;
            add(new RectPane(), gbc);

            gbc.weightx = 0;
            gbc.weighty = 0;
            gbc.gridx = 0;
            gbc.gridy = 2;
            gbc.anchor = GridBagConstraints.SOUTHWEST;
            add(new RectPane(), gbc);

            gbc.gridx = 2;
            gbc.anchor = GridBagConstraints.SOUTHEAST;
            add(new RectPane(), gbc);
        }

        // This is just to demonstrate how the layout works when the avaliable
        // space is larger then the desired space, you don't need this
        // and should get rid of it and just let the layout manager calculate
        // it's desired size based on it's content
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(500, 500);
        }

    }

    public class RectPane extends JPanel {

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.GREEN);
            g.fillRect(0, 0, 100, 100);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(100, 100);
        }

    }

}

了解,GridBagLayout 是标准 API 中最复杂的布局管理器,但却是最灵活的。您也不局限于单一的布局管理器,您可以使用复合布局来创建非常高级的界面

【讨论】:

  • 感谢您的提示,我已经更新了我的代码并将其发布在问题上供您查看:) 另外,我还有 1 个问题。当我添加 setLayout 时,它不会将组件添加到面板中,它只会显示组件。但是当我删除布局设置时,它可以通过显示父(容器)然后是其上的组件来正常工作。所以我删除了它们,对吗?以及如何禁用居中面板?例如这个prntscr.com/modba4
  • 首先,我采用了最简单的方法来“让它工作”。大多数布局管理器实际上以一种或另一种方式将其组件居中,如果您想要不同的位置,那么您可能需要寻找更灵活的布局管理器,例如GridBagLayout,它可以为您提供更多控制,但它也是标准 API 中可用的最复杂的布局管理器
  • @o6707448 另外,请注意更改您的问题,因为现在我的答案与原始问题不匹配
  • 好吧,无论如何我都试过了,但没有成功,所以我可以将面板设置在特定位置:/
  • @o6707448 你没抓住重点——像素完美定位是现代 UI 开发中的一种错觉。决定组件“如何”放置在单个平台上的因素太多了,更不用说跨多个平台了,你会在余生中不断添加“hacks”来解决无限数量的可能边缘情况。这就是为什么任何体面的 UI 框架都会抽象概念的原因,Swing 使用布局管理器 API 来达到此目的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-15
相关资源
最近更新 更多