【问题标题】:JPanel shows only the first custom JComponent addedJPanel 仅显示添加的第一个自定义 JComponent
【发布时间】:2019-01-20 00:15:43
【问题描述】:

我编写了一个在屏幕上绘制三角形的程序。然而,只显示了第一个三角形。如何使多个自定义 JComponent 可见?

我已经尝试创建类似draw() 方法的东西,但是我无法对这个对象执行任何操作,例如 i。 e.我希望每当我点击它时三角形的颜色就会改变。为此,我需要一个 MouseListener,但它不适用于 draw() 方法。

查看.java文件:

package test;

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

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

public class View extends JPanel {

public View()
{


    setPreferredSize(new Dimension(300, 300));
    add(new Triangle(20, 50, Color.red)); //this one will react to mouseClicked
    add(new Triangle(100, 200, Color.pink)); //this one doesn't appear

}


public static void main(String []args)
{
    JFrame frame = new JFrame("Trianlge test");
    frame.add(new View());
    frame.pack();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);

}


public void paintComponent(Graphics g)
{
    super.paintComponent(g);
    Triangle p3 = new Triangle(60, 120, Color.blue); //this one won't react to mouseClicked()
    p3.draw(g);
}
}

Triangle.java 文件:

    package test;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.GeneralPath;

import javax.swing.JComponent;

public class Triangle extends JComponent implements MouseListener{

private int x,y;
private Color c;
public Triangle(int x, int y, Color c)
{
    this.x = x;
    this.y = y;
    this.c = c;
    setPreferredSize(new Dimension(100, 100));
    addMouseListener(this);
}

public void paintComponent(Graphics g)
{
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;
    GeneralPath path = new GeneralPath();

    g2d.setColor(c);
    path.moveTo(x, y);
    path.lineTo(x, y);
    path.lineTo(x+50, y);
    path.lineTo(x, y-50);
    path.closePath();
    g2d.fill(path);
    repaint();
}

public void draw(Graphics g)
{

    Graphics2D g2d = (Graphics2D) g;
    GeneralPath path = new GeneralPath();

    g2d.setColor(c);
    path.moveTo(x, y);
    path.lineTo(x, y);
    path.lineTo(x+50, y);
    path.lineTo(x, y-50);
    path.closePath();
    g2d.fill(path);
    repaint();
}

@Override
public void mouseClicked(MouseEvent e) {
    c = Color.cyan;
    repaint();

}

@Override
public void mousePressed(MouseEvent e) {
}

@Override
public void mouseReleased(MouseEvent e) {
    // TODO Auto-generated method stub

}

@Override
public void mouseEntered(MouseEvent e) {
    // TODO Auto-generated method stub

}

@Override
public void mouseExited(MouseEvent e) {
    // TODO Auto-generated method stub

}

}

【问题讨论】:

  • BorderLayout 将只管理添加到 5 个可用位置中的任何一个的最后一个组件,如果 JFrame 则更改布局管理器

标签: java swing graphics jpanel jcomponent


【解决方案1】:
JFrame frame = new JFrame();

首先,您的 View 类中的声明是完全没有必要的。您不会在组件的构造函数中创建 JFrame 实例。此外,您的代码从不引用该变量,这很好地表明它是不需要的。

但是,主要问题是您创建自定义组件的概念是错误的:

setPreferredSize(new Dimension(100, 100));

您尝试设置组件的首选大小。

add(new Triangle(100, 200, Color.pink)); //this one doesn't appear

但是您尝试在 (100, 200) 处进行自定义绘画,这超出了组件的大小。所以绘制逻辑被裁剪为组件的大小,所以你看不到任何被绘制的东西。

自定义绘制应该相对于组件的 (0, 0) 进行,而不是相对于父组件。

如果您想在父面板上随机放置组件,那么您需要:

  1. 将父面板设置为使用空布局
  2. 设置您添加到面板的每个组件的位置
  3. 设置添加到面板的每个组件的大小。

基本上你需要接管布局管理器的功能。

您当前的绘画代码的其他问题:

  1. 不要在绘画方法中调用 repaint()。这基本上会导致无限的绘画循环。如果您需要动画,请使用 Swing Timer 来安排动画。

  2. 不要直接调用paintComponent(...)。当组件需要重新绘制时,Swing 会调用 paintComponent()。

但是,我建议如果您想在面板上绘制形状,那么您就忘记了创建自定义组件。相反,您保留要绘制的形状的 ArrayList,然后在面板的 paintComponent() 方法中遍历 ArrayList 以绘制每个形状。

有关此方法的示例,请查看 Custom Painting Approaches 中的 Draw On Component 示例。

注意:

如果您真的希望能够处理鼠标事件,那么您需要使用 Shape 对象来表示您的形状以进行正确的命中检测。如果您只是将您的形状显示为一个组件,那么如果您单击组件矩形区域中的任意位置,将检测到鼠标点击,而不仅仅是您实际绘制的三角形部分。 Shape 类有一个 contains(...) 方法,您可以使用该方法来确定您是否实际单击了 Shape。

查看Playing With Shapes 了解有关此概念的更多信息。

【讨论】:

    【解决方案2】:

    Triangle 组件设置边框,如下所示:

    public Triangle(int x, int y, Color c)
    {
      this.x = x;
      this.y = y;
      this.c = c;
      setPreferredSize(new Dimension(100, 100));
      addMouseListener(this);
      // Set this border to see the boundaries of this component.
      // When you are done, you may remove this.
      setBorder(BorderFactory.createLineBorder(Color.black));
    }
    

    这样你就可以更好地理解组件的边界了。

    粉红色的三角形不可见,因为它超出了组件的边界。

    p3三角形不会对鼠标点击做出反应,因为它只是一个绘图。只有组件对鼠标和其他事件做出反应。

    请注意,组件的形状是矩形。因此,您添加的鼠标侦听器可以在组件的任何位置工作;不仅在三角形的面积上。

    您在此程序中以两种方式绘制三角形。
    1. 通过添加三角形组件。 (如“添加(新三角形(20, 50, Color.red));”)
    2.通过在paintComponent()方法中绘制p3

    从软件设计的角度来看,最好坚持一种方法。否则,它可能会令人困惑并容易出错。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多