【问题标题】:JPanel doesn't display all custom made componentsJPanel 不显示所有定制组件
【发布时间】:2016-02-15 15:37:31
【问题描述】:

我在 JFrame 中显示组件时遇到了一个奇怪的问题。

我必须在不使用 Swing 的情况下编写自己的 GUI 引擎(按钮、文本框等)。只允许使用 JFrame/JPanel。

假设我想放置 3 个按钮。

我的按钮类:

public class Button extends JPanel implements MouseListener {

Rectangle r = new Rectangle();
String text;

int X,Y,W,H;


public Button(int x, int y, int w, int h, String t)
{
    X=x;
    Y=y;
    W=w;
    H=h;

    this.setBackground(Color.CYAN);
    addMouseListener(this);

    r.setSize(w, h);
    r.setLocation(x, y);
    this.text = t;
}



@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D)g;
    g2d.draw(r);
    g2d.drawString(text, X+W/2, Y+H/2);


}

@Override
public void mouseClicked(MouseEvent arg0) {
    // TODO Auto-generated method stub

    if((arg0.getButton()==1) && r.contains(arg0.getPoint())) 
        System.out.println(arg0.getPoint().toString()); 

}


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

}


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

}


@Override
public void mousePressed(MouseEvent arg0) {
    // TODO Auto-generated method stub

}


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

}

}

在主类中,我创建了一个 JFrame 和 JPanel。我添加到 JPanel 3 按钮,最后将 JPanel 添加到 JFrame,但只显示最后一个声明的按钮。

public static void main(String[] args) {
    // TODO Auto-generated method stub


    JFrame f = new JFrame("Demo");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setBackground(Color.cyan);

    JPanel j = new JPanel(new BorderLayout());

    j.add(new Button(10,10,100,50,"text"));
    j.add(new Button(10,100,100,50,"text2"));
    j.add(new Button(300,10,100,50,"text3"));

    f.add(j);
    f.pack();
    f.setSize(640, 400);;
    f.setVisible(true);


}

我做错了什么?

【问题讨论】:

  • 不确定您要做什么。使用组件或绘画。如果您使用组件,那么您可以使用所有内置的 Swing 功能,例如 MouseListeners。如果您只是绘制图片,那么您还需要实现所有这些功能。那么作业的目的是什么?

标签: java swing jframe jpanel


【解决方案1】:

您的代码不遵守 BorderLayout 规则。当使用容器将 3 个组件添加到 BorderLayout 而不指定 BorderLayout 位置时,它们都会被添加到默认的 BorderLayout.CENTER 位置,最后添加的一个会覆盖其他 3. 在添加组件或使用另一个布局管理器时考虑使用 BorderLayout 常量(s )。

话虽如此,我认为你最好完全改变路线。而是考虑...

  • 使您的 Button 类成为逻辑类和非 GUI 类(即,不让它扩展 JPanel),
  • 让一个非按钮 JPanel 持有一个List<Button>
  • 让这个单一的 JPanel 通过在其 paintComponent 方法中迭代列表来绘制所有 Button,调用每个 Button 具有的 draw(Graphics g) 方法
  • 让 JPanel 通过单个 MouseListener 与按钮交互。

这将大大简化事情。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.*;

public class FooGui extends JPanel {
    private static final int PREF_W = 640;
    private static final int PREF_H = 400;
    private List<MyButton> btnList = new ArrayList<>();

    public FooGui() {
        addMouseListener(new MyMouse());
    }

    public void addButton(MyButton btn) {
        btnList.add(btn);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (MyButton myButton : btnList) {
            myButton.draw(g);
        }
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }

    private class MyMouse extends MouseAdapter {
        @Override
        public void mousePressed(MouseEvent e) {
            for (MyButton myButton : btnList) {
                if (myButton.getRect().contains(e.getPoint())) {
                    System.out.println("Text: " + myButton.getText());
                }
            }
        }
    }

    private static void createAndShowGui() {
        FooGui fooGui = new FooGui();
        fooGui.addButton(new MyButton(10,10,100,50,"text"));
        fooGui.addButton(new MyButton(10,100,100,50,"text2"));
        fooGui.addButton(new MyButton(300,10,100,50,"text3"));

        JFrame frame = new JFrame("FooGui");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(fooGui);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui();
            }
        });
    }
}

class MyButton {
    private static final Color BK = Color.CYAN;
    private static final Color TEXT_COLOR = Color.BLACK;
    private int x;
    private int y;
    private int w;
    private int h;
    private String text;
    private Rectangle rect;

    public MyButton(int x, int y, int w, int h, String t) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.text = t;
        rect = new Rectangle(x, y, w, h);
    }

    public void draw(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        g2.setColor(BK);
        g2.fill(rect);
        g2.setColor(TEXT_COLOR);
        FontMetrics metrics = g2.getFontMetrics();
        Rectangle2D bounds = metrics.getStringBounds(text, g2);
        int textX = (int) (x + (w - bounds.getWidth()) / 2);
        int textY = (int) (y + (h + bounds.getHeight()) / 2);

        g2.drawString(text, textX, textY);
    }

    public Rectangle getRect() {
        return rect;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getW() {
        return w;
    }

    public int getH() {
        return h;
    }

    public String getText() {
        return text;
    }
}

【讨论】:

  • 谢谢你的代码,我自己发明了类似的东西。我还有一个问题。为什么在 main 方法中使用 SwingUtilities[...]?
  • @BigMacintosh this 可能会回答您的问题。
【解决方案2】:

这个赋值的目的是创建一个GUI,例如在某个设备(如旧手机)没有实现JButton、JLabel等时可以使用该GUI

嗯,这并不能真正回答我的问题。您解决了按钮和标签的自定义绘制问题,但 GUI 不仅仅是绘制内容。

我还问你是否可以使用 AWT 的其他功能,例如 MouseListeners、KeyListeners、tabbing、布局管理器等。因为如果你可以使用这些功能,那么就没有理由像在用气垫船回答。

如果您需要做的只是扩展 JPanel 并为按钮或标签进行自定义绘制,那么您的代码的问题是您没有正确使用布局管理器。也就是说框架的默认布局是BorderLayout,不能在BorderLayout的CENTER添加多个组件。

您发布的代码的第二个问题是您没有覆盖组件的getPreferredSize() 方法。因此大小将为 0,布局管理器无法正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多