简体   繁体   English

Java JComponent绘制-几乎可以正常工作

[英]Java JComponent paint --Almost working

I almost have the repaint() Jcomponent working. 我几乎让repaint()Jcomponent工作了。 I had it working and then tried to make an absolute positioning and now it doesn't work. 我让它正常工作,然后尝试进行绝对定位,但现在不起作用。

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();
        }
}

Class 2: (This is the JComponent that I am trying to set) 第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);
    }
}

I added my component to the Container and then added the container to the JPanel and then the JPanel is added to the JFrame. 我将组件添加到Container,然后将容器添加到JPanel,然后将JPanel添加到JFrame。 I would think that this should work. 我认为这应该可行。 I have a set preferred size. 我有设定的首选尺寸。 I had it working once and now it doesn't work. 我曾经使它工作一次,但现在不起作用。

I want to be able to make a component that is a circle. 我希望能够制作一个圆形的组件。 I want that circle to be able to be drawn any where on a Jframe, and then I want that circle to be able to move based on aa certain length of time. 我希望该圆能够在Jframe上的任何位置绘制,然后希望该圆能够基于一定的时间长度移动。 I am going to make a game that has circles dropping from the top and then falling to the bottom. 我要制作一个游戏,该游戏的圆圈从顶部下降,然后下降到底部。 When I had it working I did have the circle being written to the JPanel which is a complex piece of code. 当我工作时,确实将圆写到了JPanel,这是一段复杂的代码。 But I have had to go back to the old simple method of writing a single graphical word. 但是我不得不回到以前写一个图形单词的简单方法。

  • When you use null layout, you are completely responsible for making sure that components added have proper location and size (not preferredSize) set. 当使用空布局时, 完全有责任确保所添加的组件设置了正确的位置和大小 (而不是preferredSize)。
  • You should almost never use null layout. 您几乎永远不应使用空布局。
  • Wouldn't this sort of thing work better by creating a logical class to represent the Circle, not a component? 通过创建一个逻辑类来表示Circle,而不是组件,这种事情会更好吗? Then your drawing JPanel could hold a collection of logical circles, and the drawing JPanel could be responsible for drawing each Circle in its paintComponent method. 然后,您的绘图JPanel可以容纳逻辑圆的集合,并且绘图JPanel可以负责在其paintComponent方法中绘制每个Circle。

Edit 编辑
Your comments/my replies: 您的评论/我的回复:

when you say never use an absolute layout, the company that I worked for always used a absolute layout only. 当您说从不使用绝对布局时,我所服务的公司始终仅使用绝对布局。

There are times when it is useful, but not for creating a typical component-filled GUI. 有时它很有用,但对于创建典型的组件填充GUI却没有用。 Otherwise the GUI becomes very hard to modify and maintain. 否则,GUI变得很难修改和维护。

When you mean a logical class you mean a class that just creates one circle. 当您指的是逻辑类时,您的意思是仅创建一个圆的类。

Yes, and that holds all the necessary properties of that circle such as its Color, location, movement, etc.. 是的,并且拥有该圆的所有必要属性,例如其颜色,位置,运动等。

Then the Jpanel would draw each circle. 然后,Jpanel将绘制每个圆。

Yes. 是。 I would imagine the drawing JPanel having an ArrayList<MyCircle> of them, and the paintComponent method iterating througgh this List. 我可以想象一下,其中的ArrayList<MyCircle>具有ArrayList<MyCircle> ,并且paintComponent方法通过此List进行迭代。

when you say Size this is a property in JComponent. 当您说Size时,这是JComponent中的一个属性。

I think that it is a property of Component, JComponent's parent. 我认为这是JComponent的父组件Component的属性。 If you use null layout, then all components must have their size and location specified. 如果使用空布局,则所有组件都必须指定其大小和位置。 Otherwise the component defaults to a location of [0, 0] and a size of [0, 0]. 否则,组件默认为[0,0]的位置,大小为[0,0]。


Edit 2 编辑2

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

This is the code that I used for the preferred size. 这是我用于首选大小的代码。 I am at a lost why this doesn't work. 我不知道为什么这行不通。

This code has no effect on either the size or the preferredSize properties of Component/JComponent. 此代码对Component / JComponent的大小或preferredSize属性都没有影响。 It doesn't surprise me that it will not help you. 它不会帮助您,这并不令我感到惊讶。 You would either have to override getSize() or getPreferredSize() or explicitly call setSize(...) or getPreferredSize(...) to change the state of the properties. 您可能必须重写getSize()getPreferredSize()或显式调用setSize(...)getPreferredSize(...)才能更改属性的状态。

I am going to try it with a different layout manager and see but I would see the difference between one layout manager or another. 我将尝试与其他布局管理器一起尝试,但是我会看到一个或另一个布局管理器之间的区别。

I'm not sure how to interpret this. 我不确定如何解释这一点。


Edit 3 编辑3
You state: 您声明:

I worked at one company and we used absulute layouts all of the time. 我在一家公司工作,我们一直都在使用粗略的布局。 How would an absolute layout not work as good as, say BorderLayout(). 绝对布局如何不如BorderLayout()那样好用。 To me the BorderLayout() are harder to implement. 对我来说,BorderLayout()很难实现。 Or is it that you use a Jframe() with a BorderLayout, and then insert a Jpanel into an already existing position that is already also a BorderLayout(). 还是您将Jframe()与BorderLayout一起使用,然后将Jpanel插入到已经是BorderLayout()的现有位置中。 I always have trouble getting my buttions and positions correct in a layout that is something different than a BorderLayout(). 我总是很难在与BorderLayout()不同的布局中正确设置自己的位置和位置。 Can you post an example that would be easier to use than 您能发布一个比使用起来容易的示例吗?

I'm guessing you want an example of where use of layout managers is easier than using absolute positioning. 我猜想您想要一个示例,其中使用布局管理器比使用绝对定位更容易。

Let's take the example of a very simple calculator, one with buttons for numeric input and simple operations. 让我们以一个非常简单的计算器为例,它带有用于数字输入和简单操作的按钮。 Again this example is very basic, and is non-functional, but serves to illustrate the use of layouts. 同样,该示例非常基础,并且不起作用,但是用于说明布局的使用。 I could easily place my buttons in a GridLayout-using JPanel, and then place that button JPanel into a BorderLayout-using JPanel at the BorderLayout.CENTER position with the JTextField, display, placed in the same BorderLayout-using JPanel at the BorderLayout.PAGE_START position: 我可以轻松地将按钮放置在使用GridLayout的JPanel中,然后将该按钮JPanel放置在BorderLayout.CENTER位置的BorderLayout-使用JPanel中,并显示JTextField,并显示在相同的BorderLayout-使用JPanel的BorderLayout.PAGE_START上位置:

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();
         }
      });
   }
}

This would result in a calculator that looks like so: 这将导致一个计算器如下所示:

基本计算器

Now, sure you could say that you could produce this with null layout and setbounds(...) , and that's all well and good, but now say that you're not satisfied with this calculator, and now desire that it has some scientific calculation functionality. 现在,您可以肯定地说可以使用null布局和setbounds(...)来生成它,这一切都很好,但是现在您对这个计算器不满意,现在希望它具有一定的科学性。计算功能。 Say you now want to add buttons for square, square root, exponential, and logarithm, but not only that, say you wish to add the buttons below the display and above the numeric and basic operations buttons. 假设您现在要添加平方,平方根,指数和对数的按钮,但不仅限于此,请说您希望将按钮添加到显示屏下方,数字和基本操作按钮上方。 If you were to do this with null layout, you would have to reposition all the components below and to the right of any new components added, and you'd have to expand the size of the JTextField, all calculations that are tedious and prone to error. 如果要使用null布局进行此操作,则必须将所有组件重新定位在添加的任何新组件的下方和右侧,并且必须扩展JTextField的大小,所有繁琐且易于计算的计算错误。

If you used layout managers, you would instead only need to add one line of code, actually an additional row to an array: 如果使用布局管理器,则只需要添加一行代码,实际上是向数组添加一行:

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();
         }
      });
   }
}

which would result in this GUI: 这将导致此GUI:

增强型计算器

Again this is a very simplistic example, but the general principles apply to any GUI that holds components such as JButtons, JTextComponents, etc. 再次,这是一个非常简单的示例,但是一般原理适用于任何包含JButtons,JTextComponents等组件的GUI。

With Swing animation, the Timer class is an exceptional option. 对于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 

Another good idea is to cast g to a Graphics2D object- it's a lot safer and more capable. 另一个好主意是将g强制转换为Graphics2D对象-更加安全,功能强大。

Another way to use the Timer class: 使用Timer类的另一种方法:

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

You still need to override actionPerformed() in your main class though. 不过,您仍然需要在主类中重写actionPerformed()。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM