2015-11-13 54 views
0

我在JFrame中显示组件时出现了一个奇怪的问题。JPanel不显示所有定制组件

我必须编写自己的GUI引擎(按钮,文本框等),而不使用Swing。只允许使用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); 


} 

我在做什么错?

+0

不知道你在做什么。使用组件或绘制图片。如果您使用组件,那么您可以使用所有内置的Swing功能,如MouseListeners。如果您只是绘制图片,那么您还需要实现所有这些功能。那么这项任务的目的是什么? – camickr

+0

这个assigment的目的是创建一个图形用户界面(GUI),例如在某个设备(如旧手机)中没有实现JButton,JLabel等时可以使用的图形用户界面 – BigMacintosh

回答

4

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

说了这话之后,我觉得你最好完全改变路线。相反,考虑...

  • 使您Button类的逻辑和非GUI类(即,没有它扩展JPanel),
  • 有一个单一的非按钮的JPanel举行List<Button>
  • 让这个单一的JPanel通过遍历paintComponent方法中的列表来绘制所有按钮,调用draw(Graphics g)方法,每个按钮都有
  • 让JPanel通过单个MouseListener与Button进行交互。

这将大大简化事情。

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

谢谢你的代码,我刚发明像我自己的东西。我还有一个问题。为什么在主要方法SwingUtilities [...]被使用? – BigMacintosh

+1

@BigMacintosh [this](http://stackoverflow.com/questions/3551542/swingutilities-invokelater-why-is-it-needed)可能会回答你的问题。 – Frakcool

1

此分配新建分配FY的目的是创建一个图形用户界面,其可用于当例如,没有实现的JButton,JLabel的等在一定的设备(如旧移动电话)

那么,这并没有真正回答我的问题。您解决了按钮和标签的自定义绘画问题,但是GUI还有更多的东西,然后只是绘制东西。

我还问是否可以使用AWT的其他功能,如MouseListeners,KeyListeners,TabBbing,布局管理器等。因为如果您可以使用这些功能,那么就没有理由完全重新发明轮子了气垫船的答案。

如果您只需要扩展JPanel并为按钮或标签执行自定义绘画,那么代码的问题在于您没有正确使用布局管理器。这是一个框架的默认布局是一个BorderLayout,你不能将多个组件添加到BorderLayout的中心。

您的发布代码的第二个问题是您没有重写组件的getPreferredSize()方法。因此,大小将为0,布局管理员无法正确执行其工作。