Java JComponent paint - 几乎可以工作

时间:2013-11-17 22:31:28

标签: java swing

我几乎让repaint()Jcomponent正常工作。我让它工作,然后尝试进行绝对定位,现在它不起作用。

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;

public class DDHGenericFrame {
        private static final long serialVersionUID = 1L;
        DDHGenericPanel d = new DDHGenericPanel(); 
        //DDHCircleOne o = new DDHCircleOne();

        public DDHGenericFrame() {
            initUI();
        }

        public final void initUI() {
              JFrame frame = new JFrame("AbsoluteLayoutDemo");
              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              frame.setTitle("Draw Circle");
              frame.setBackground(Color.green);
              frame.setLayout(null);
              frame.setSize(300,425);
              frame.add(d);
//            frame.add(o);//didn't work neither
              frame.setVisible(true);
        }

        public static void main(String[] args) {
            DDHGenericFrame ex = new DDHGenericFrame();
        }
}

第2类:(这是我试图设置的JComponent)

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

import javax.swing.JComponent;

public class DDHTestDraw extends JComponent {
    public DDHTestDraw () {
        settPreferredSize();
    }

    public void settPreferredSize() {
        Dimension d = new Dimension(25,25);
        setPreferredSize(d);
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawString("Text",20,20);
    }
}

我将我的组件添加到Container,然后将容器添加到JPanel,然后将JPanel添加到JFrame。我认为这应该有效。我有一个首选大小。我让它工作一次,现在它不起作用。

我希望能够制作一个圆形的组件。我希望能够在Jframe上的任何位置绘制该圆,然后我希望该圆能够基于一定的时间长度移动。我打算制作一个圆圈从顶部掉落然后掉到底部的游戏。当我开始工作时,我确实将圆圈写入了JPanel,这是一段复杂的代码。但我不得不回到编写单个图形词的简单方法。

3 个答案:

答案 0 :(得分:2)

  • 当您使用空布局时,完全负责确保添加的组件具有正确的位置并设置 size (而不是preferredSize)。
  • 你几乎不应该使用null布局。
  • 通过创建一个逻辑类来表示Circle而不是组件,这种事情会不会更好?然后你的绘图JPanel可以包含一个逻辑圆的集合,并且绘图JPanel可以负责在其paintComponent方法中绘制每个Circle。

修改
您的意见/我的回复:

  

当你说从不使用绝对布局时,我工作的公司总是只使用绝对布局。

有时它很有用,但不适用于创建典型的组件填充GUI。否则,GUI变得非常难以修改和维护。

  

当你的意思是一个逻辑类时,你指的是一个只创建一个圆的类。

是的,它包含该圈子的所有必要属性,例如颜色,位置,移动等。

  

然后Jpanel将绘制每个圆圈。

是。我想象绘图JPanel有ArrayList<MyCircle>个,而paintComponent方法通过这个List迭代。

  

当你说Size这是JComponent中的属性时。

我认为它是Component,JComponent的父级的属性。如果使用null布局,则所有组件必须指定其大小和位置。否则,组件默认为[0,0]的位置和[0,0]的大小。


修改2

public Dimension Size(int a, int b) { 
   Dimension d = new Dimension(); 
   d.width = a; 
   d.height = b; 
   return d; 
}
     

这是我用于首选大小的代码。我迷失了为什么这不起作用。

此代码对Component / JComponent的size或preferredSize属性没有影响。它不会让我感到惊讶,它对你没有帮助。您必须覆盖getSize()getPreferredSize()或明确调用setSize(...)getPreferredSize(...)才能更改属性的状态。

  

我将尝试使用不同的布局管理器,但是我会看到一个布局管理器或另一个布局管理器之间的区别。

我不知道如何解释这个。


编辑3
你说:

  

我在一家公司工作,我们一直使用绝对布局。如果绝对布局不如BorderLayout()那么好。对我而言,BorderLayout()更难实现。或者是您使用带有BorderLayout的Jframe(),然后将Jpanel插入已经存在且已经是BorderLayout()的现有位置。我总是难以在与BorderLayout()不同的布局中使我的错位和位置正确。你能发布一个比

更容易使用的例子吗?

我猜你想要一个使用布局管理器比使用绝对定位更容易的例子。

我们以一个非常简单的计算器为例,一个带有数字输入和简单操作的按钮。此示例再次是非常基本,并且不起作用,但用于说明布局的使用。我可以轻松地将我的按钮放在GridLayout中 - 使用JPanel,然后将该按钮JPanel放入BorderLayout-使用边界的Layout.CENTER位置使用JPanel,显示,放置在BorderLayout.PAGE_START的相同BorderLayout-JPanel中位置:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.*;

public class CalcEg {
   private static final float BTN_FONT_SIZE = 20f; 
   private static final String[][] BTN_LABELS = {
      {"7", "8", "9", "-"},
      {"4", "5", "6", "+"},      
      {"1", "2", "3", "/"},
      {"0", ".", " ", "="}
   };
   private static final int GAP = 4;
   private JPanel mainPanel = new JPanel(new BorderLayout(GAP, GAP));
   private JPanel buttonPanel = new JPanel();
   private JTextField display = new JTextField();

   public CalcEg() {
      int rows = BTN_LABELS.length;
      int cols = BTN_LABELS[0].length;
      buttonPanel.setLayout(new GridLayout(rows, cols, GAP, GAP));
      for (String[] btnLabelRow : BTN_LABELS) {
         for (String btnLabel : btnLabelRow) {
            if (btnLabel.trim().isEmpty()) {
               buttonPanel.add(new JLabel());
            } else {
               JButton btn = createButton(btnLabel);
               buttonPanel.add(btn);
            }
         }
      }
      display.setFont(display.getFont().deriveFont(BTN_FONT_SIZE));
      display.setEditable(false);
      display.setFocusable(false);
      display.setBackground(Color.white);

      mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
      mainPanel.add(buttonPanel, BorderLayout.CENTER);
      mainPanel.add(display, BorderLayout.PAGE_START);
   }

   private JButton createButton(String btnLabel) {
      JButton button = new JButton(btnLabel);
      button.setFont(button.getFont().deriveFont(BTN_FONT_SIZE));
      return button;
   }

   public JComponent getMainComponent() {
      return mainPanel;
   }

   private static void createAndShowGui() {
      CalcEg mainPanel = new CalcEg();

      JFrame frame = new JFrame("CalcEg");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel.getMainComponent());
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

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

这将导致计算器看起来像这样:

Basic Calculator

现在,确定你可以说你可以使用null布局和setbounds(...)生成这个,这一切都很好,但现在说你对这个计算器不满意,现在希望它有一些科学的计算功能。假设您现在想要为方形,平方根,指数和对数添加按钮,但不仅如此,您还希望在显示屏下方和数字和基本操作按钮上方添加按钮。如果您使用null布局执行此操作,则必须重新定位所添加的任何新组件的下方和右侧的所有组件,并且您必须扩展JTextField的大小,所有计算都是单调且易于进行的错误。

如果你使用了布局管理器,你只需要添加一行代码,实际上是一个数组的附加行:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.*;

public class CalcEg {
   private static final float BTN_FONT_SIZE = 20f; 
   private static final String[][] BTN_LABELS = {
      {"sqr", "sqrt", "exp", "log"}, // ******* Line Added Here *********
      {"7", "8", "9", "-"},
      {"4", "5", "6", "+"},      
      {"1", "2", "3", "/"},
      {"0", ".", " ", "="}
   };
   private static final int GAP = 4;
   private JPanel mainPanel = new JPanel(new BorderLayout(GAP, GAP));
   private JPanel buttonPanel = new JPanel();
   private JTextField display = new JTextField();

   public CalcEg() {
      int rows = BTN_LABELS.length;
      int cols = BTN_LABELS[0].length;
      buttonPanel.setLayout(new GridLayout(rows, cols, GAP, GAP));
      for (String[] btnLabelRow : BTN_LABELS) {
         for (String btnLabel : btnLabelRow) {
            if (btnLabel.trim().isEmpty()) {
               buttonPanel.add(new JLabel());
            } else {
               JButton btn = createButton(btnLabel);
               buttonPanel.add(btn);
            }
         }
      }
      display.setFont(display.getFont().deriveFont(BTN_FONT_SIZE));
      display.setEditable(false);
      display.setFocusable(false);
      display.setBackground(Color.white);

      mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
      mainPanel.add(buttonPanel, BorderLayout.CENTER);
      mainPanel.add(display, BorderLayout.PAGE_START);
   }

   private JButton createButton(String btnLabel) {
      JButton button = new JButton(btnLabel);
      button.setFont(button.getFont().deriveFont(BTN_FONT_SIZE));
      return button;
   }

   public JComponent getMainComponent() {
      return mainPanel;
   }

   private static void createAndShowGui() {
      CalcEg mainPanel = new CalcEg();

      JFrame frame = new JFrame("CalcEg");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel.getMainComponent());
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

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

会导致此GUI:

Enhanced Calculator

同样,这是一个非常简单的示例,但一般原则适用于任何包含JButtons,JTextComponents等组件的GUI。

答案 1 :(得分:1)

使用Swing动画,Timer类是一个特殊选项。

//this class is a JPanel that implements ActionListener`
Timer t = new Timer(1000,this);//the first arg is how many times it repeats in milliseconds
//Then in the constructor...
t.start();
//the ActionPerformed function normally increments a variable then calls the repaint method.
rectangle_x++;
repaint(); //calls paintComponent 

另一个好主意是将g转换为Graphics2D对象 - 它更安全,更强大。

答案 2 :(得分:1)

使用Timer类的另一种方法:

Timer t = new Timer(510, new ActionListener()
{
    @Override
    public void actionPerformed(ActionEvent e)
    {
        rectangle_x++;
        repaint();
    }
})
...
t.start();

你仍然需要在主类中覆盖actionPerformed()。