首页 > 解决方案 > 在面板上绘制图形

问题描述

我正在尝试在面板上绘制图形,但我不确定我将如何去做。

我尝试创建一个扩展 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);

    }

}

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

标签: javaswinglayoutjframejpanel

解决方案


错误 #1

contentPane.setLayout(null);

panel.setLayout(null);

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

首先花时间了解在容器中布置组件

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

事实上,你真的不需要,因为apanel的默认值已经设置为使用.contentPaneJFrameBorderLayout

这意味着你可以摆脱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中最复杂的布局管理器,但也是最灵活的。您也不局限于单一的布局管理器,您可以使用复合布局来创建非常高级的界面


推荐阅读