为什么我的 JComponent paint(Graphics g) 不工作/不被调用?
Why is my JComponent paint(Graphics g) not working/ not being called?
我一直在尝试编写这个用点制作多边形的应用程序。我一开始尝试运行的时候,我以为我的观点有问题。但是当我开始四处寻找问题时,我意识到我在 JComponent 中的 paint 方法甚至没有被调用。我应该怎么做才能解决这个问题?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Line2D;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JToggleButton;
public class PolygonBuilder extends JFrame{
final static int WIDTH = 1280;
final static int HEIGHT = 640;
public static int xPointPos, yPointPos;
public static void main(String[] args) {
new PolygonBuilder();
}
public PolygonBuilder() {
setTitle("Build a Polygon");
this.setSize(WIDTH,HEIGHT);
setResizable(false);
JLabel placeholder = new JLabel();
BuilderDrawingPanel BuilderPanel = new BuilderDrawingPanel();
this.add(BuilderPanel, BorderLayout.CENTER);
JToggleButton DotOnOff = new JToggleButton("Dot");
DotOnOff.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent arg0) {
// TODO Auto-generated method stub
if(DotOnOff.isSelected()) {
System.out.println("ON");
} else {
System.out.println("OFF");
}
}
});
DotOnOff.setBounds(100, 100, 90, 35);
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5);
executor.scheduleAtFixedRate(new RepaintTheBoard(this), 0L, 20L, TimeUnit.MILLISECONDS);
addMouseMotionListener(new MouseMotionListener() {
@Override
public void mouseDragged(MouseEvent arg0) {}
@Override
public void mouseMoved(MouseEvent arg0) {
Point p = MouseInfo.getPointerInfo().getLocation();
xPointPos = (int) p.getX();
yPointPos = (int) p.getY();
System.out.println(xPointPos+","+yPointPos);
}
});
this.add(DotOnOff);
this.add(placeholder);
setVisible(true);
}
}
class RepaintTheBoard implements Runnable {
PolygonBuilder theBuilder;
public RepaintTheBoard(PolygonBuilder theBuilder) {
this.theBuilder = theBuilder;
}
@Override
public void run() {
theBuilder.repaint();
}
}
@SuppressWarnings("serial")
class BuilderDrawingPanel extends JComponent{
static Graphics2D graphicSettings;
static Shape drawLine;
public BuilderDrawingPanel() {
//stuff to draw at start
System.out.println("Drawing..");
drawLine = new Line2D.Float(480,480,0,0);
}
@Override
public void paint(Graphics g) {
graphicSettings = (Graphics2D)g;
System.out.println("Drawing..");
graphicSettings.setColor(Color.RED);
graphicSettings.fillRect(0, 0, getWidth(), getHeight());
graphicSettings.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphicSettings.setPaint(Color.BLUE);
graphicSettings.draw(drawLine);
}
}
虽然 c0der 提供了一些有价值的信息和链接,但我觉得这方面的某些方面应该在答案中解决。
JFrame
(的内容窗格)的默认布局是 BorderLayout
。
- 添加到无约束边框布局的任何组件默认为
CENTER
。
- 边框布局的每个区域(布局约束)只能显示一个组件。
然后我们来到这部分代码:
this.add(DotOnOff);
this.add(placeholder);
JVM 将尝试将它们添加到已添加构建器绘图面板的内容窗格的中心。所以这就是为什么它甚至没有出现(或被涂漆)的原因。
其他提示:
- 在任何
JComponent
中,覆盖自定义绘画的正确方法是 paintComponent(Graphics)
方法。
- 任何覆盖的绘制方法都应立即调用超级方法,以确保绘制背景、边框和其他 'automatic' 元素。
- A
Graphics
对象是瞬态的,因此不应存储为 class 的属性,当然也不应声明为 static
.
- 说到
static
声明,它们(至少在 GUI 中)更经常是问题的来源而不是解决方案。不要将 GUI 属性声明为静态,除非你能解释为什么这样做是有意义的。
- 请学习常见的 Java 命名法(命名约定 - 例如
EachWordUpperCaseClass
、firstWordLowerCaseMethod()
、firstWordLowerCaseAttribute
,除非它是 UPPER_CASE_CONSTANT
)并始终如一地使用它.
更新
这是问题中看到的来源,最直接的问题已解决。它并没有改变推荐的其他内容,也没有触及我在使用代码本身时看到的其他问题。查看评论以了解为使其正常工作所做的更改。
这是这里的样子,有以下变化:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Line2D;
import java.util.concurrent.*;
import javax.swing.*;
public class PolygonBuilder extends JFrame{
final static int WIDTH = 640;
final static int HEIGHT = 320;
public static int xPointPos, yPointPos;
public static void main(String[] args) {
new PolygonBuilder();
}
public PolygonBuilder() {
setTitle("Build a Polygon");
// let's be nice to the user..
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// this is almost certainly not the correct size,
// but in itself could deserve a question
this.setSize(WIDTH,HEIGHT);
setResizable(false);
JLabel placeholder = new JLabel("Label!");
BuilderDrawingPanel BuilderPanel = new BuilderDrawingPanel();
this.add(BuilderPanel, BorderLayout.CENTER);
JToggleButton DotOnOff = new JToggleButton("Dot");
DotOnOff.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent arg0) {
if(DotOnOff.isSelected()) {
System.out.println("ON");
} else {
System.out.println("OFF");
}
}
});
DotOnOff.setBounds(100, 100, 90, 35);
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5);
executor.scheduleAtFixedRate(new RepaintTheBoard(this), 0L, 20L, TimeUnit.MILLISECONDS);
addMouseMotionListener(new MouseMotionListener() {
@Override
public void mouseDragged(MouseEvent arg0) {}
@Override
public void mouseMoved(MouseEvent arg0) {
Point p = MouseInfo.getPointerInfo().getLocation();
xPointPos = (int) p.getX();
yPointPos = (int) p.getY();
System.out.println(xPointPos+","+yPointPos);
}
});
// create a new panel for these buttons..
//this.add(DotOnOff);
//this.add(placeholder);
JPanel buttonPanel = new JPanel(); // default flow layout
buttonPanel.add(DotOnOff);
buttonPanel.add(placeholder);
// now add that panel above the builder panel
this.add(buttonPanel, BorderLayout.PAGE_START);
setVisible(true);
}
}
class RepaintTheBoard implements Runnable {
PolygonBuilder theBuilder;
public RepaintTheBoard(PolygonBuilder theBuilder) {
this.theBuilder = theBuilder;
}
@Override
public void run() {
theBuilder.repaint();
}
}
@SuppressWarnings("serial")
class BuilderDrawingPanel extends JComponent{
static Graphics2D graphicSettings;
static Shape drawLine;
public BuilderDrawingPanel() {
//stuff to draw at start
System.out.println("Drawing..");
drawLine = new Line2D.Float(480,480,0,0);
}
@Override
public void paint(Graphics g) {
graphicSettings = (Graphics2D)g;
System.out.println("Drawing..");
graphicSettings.setColor(Color.RED);
graphicSettings.fillRect(0, 0, getWidth(), getHeight());
graphicSettings.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphicSettings.setPaint(Color.BLUE);
graphicSettings.draw(drawLine);
}
}
我一直在尝试编写这个用点制作多边形的应用程序。我一开始尝试运行的时候,我以为我的观点有问题。但是当我开始四处寻找问题时,我意识到我在 JComponent 中的 paint 方法甚至没有被调用。我应该怎么做才能解决这个问题?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Line2D;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JToggleButton;
public class PolygonBuilder extends JFrame{
final static int WIDTH = 1280;
final static int HEIGHT = 640;
public static int xPointPos, yPointPos;
public static void main(String[] args) {
new PolygonBuilder();
}
public PolygonBuilder() {
setTitle("Build a Polygon");
this.setSize(WIDTH,HEIGHT);
setResizable(false);
JLabel placeholder = new JLabel();
BuilderDrawingPanel BuilderPanel = new BuilderDrawingPanel();
this.add(BuilderPanel, BorderLayout.CENTER);
JToggleButton DotOnOff = new JToggleButton("Dot");
DotOnOff.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent arg0) {
// TODO Auto-generated method stub
if(DotOnOff.isSelected()) {
System.out.println("ON");
} else {
System.out.println("OFF");
}
}
});
DotOnOff.setBounds(100, 100, 90, 35);
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5);
executor.scheduleAtFixedRate(new RepaintTheBoard(this), 0L, 20L, TimeUnit.MILLISECONDS);
addMouseMotionListener(new MouseMotionListener() {
@Override
public void mouseDragged(MouseEvent arg0) {}
@Override
public void mouseMoved(MouseEvent arg0) {
Point p = MouseInfo.getPointerInfo().getLocation();
xPointPos = (int) p.getX();
yPointPos = (int) p.getY();
System.out.println(xPointPos+","+yPointPos);
}
});
this.add(DotOnOff);
this.add(placeholder);
setVisible(true);
}
}
class RepaintTheBoard implements Runnable {
PolygonBuilder theBuilder;
public RepaintTheBoard(PolygonBuilder theBuilder) {
this.theBuilder = theBuilder;
}
@Override
public void run() {
theBuilder.repaint();
}
}
@SuppressWarnings("serial")
class BuilderDrawingPanel extends JComponent{
static Graphics2D graphicSettings;
static Shape drawLine;
public BuilderDrawingPanel() {
//stuff to draw at start
System.out.println("Drawing..");
drawLine = new Line2D.Float(480,480,0,0);
}
@Override
public void paint(Graphics g) {
graphicSettings = (Graphics2D)g;
System.out.println("Drawing..");
graphicSettings.setColor(Color.RED);
graphicSettings.fillRect(0, 0, getWidth(), getHeight());
graphicSettings.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphicSettings.setPaint(Color.BLUE);
graphicSettings.draw(drawLine);
}
}
虽然 c0der 提供了一些有价值的信息和链接,但我觉得这方面的某些方面应该在答案中解决。
JFrame
(的内容窗格)的默认布局是BorderLayout
。- 添加到无约束边框布局的任何组件默认为
CENTER
。 - 边框布局的每个区域(布局约束)只能显示一个组件。
然后我们来到这部分代码:
this.add(DotOnOff);
this.add(placeholder);
JVM 将尝试将它们添加到已添加构建器绘图面板的内容窗格的中心。所以这就是为什么它甚至没有出现(或被涂漆)的原因。
其他提示:
- 在任何
JComponent
中,覆盖自定义绘画的正确方法是paintComponent(Graphics)
方法。 - 任何覆盖的绘制方法都应立即调用超级方法,以确保绘制背景、边框和其他 'automatic' 元素。
- A
Graphics
对象是瞬态的,因此不应存储为 class 的属性,当然也不应声明为static
. - 说到
static
声明,它们(至少在 GUI 中)更经常是问题的来源而不是解决方案。不要将 GUI 属性声明为静态,除非你能解释为什么这样做是有意义的。 - 请学习常见的 Java 命名法(命名约定 - 例如
EachWordUpperCaseClass
、firstWordLowerCaseMethod()
、firstWordLowerCaseAttribute
,除非它是UPPER_CASE_CONSTANT
)并始终如一地使用它.
更新
这是问题中看到的来源,最直接的问题已解决。它并没有改变推荐的其他内容,也没有触及我在使用代码本身时看到的其他问题。查看评论以了解为使其正常工作所做的更改。
这是这里的样子,有以下变化:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Line2D;
import java.util.concurrent.*;
import javax.swing.*;
public class PolygonBuilder extends JFrame{
final static int WIDTH = 640;
final static int HEIGHT = 320;
public static int xPointPos, yPointPos;
public static void main(String[] args) {
new PolygonBuilder();
}
public PolygonBuilder() {
setTitle("Build a Polygon");
// let's be nice to the user..
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// this is almost certainly not the correct size,
// but in itself could deserve a question
this.setSize(WIDTH,HEIGHT);
setResizable(false);
JLabel placeholder = new JLabel("Label!");
BuilderDrawingPanel BuilderPanel = new BuilderDrawingPanel();
this.add(BuilderPanel, BorderLayout.CENTER);
JToggleButton DotOnOff = new JToggleButton("Dot");
DotOnOff.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent arg0) {
if(DotOnOff.isSelected()) {
System.out.println("ON");
} else {
System.out.println("OFF");
}
}
});
DotOnOff.setBounds(100, 100, 90, 35);
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5);
executor.scheduleAtFixedRate(new RepaintTheBoard(this), 0L, 20L, TimeUnit.MILLISECONDS);
addMouseMotionListener(new MouseMotionListener() {
@Override
public void mouseDragged(MouseEvent arg0) {}
@Override
public void mouseMoved(MouseEvent arg0) {
Point p = MouseInfo.getPointerInfo().getLocation();
xPointPos = (int) p.getX();
yPointPos = (int) p.getY();
System.out.println(xPointPos+","+yPointPos);
}
});
// create a new panel for these buttons..
//this.add(DotOnOff);
//this.add(placeholder);
JPanel buttonPanel = new JPanel(); // default flow layout
buttonPanel.add(DotOnOff);
buttonPanel.add(placeholder);
// now add that panel above the builder panel
this.add(buttonPanel, BorderLayout.PAGE_START);
setVisible(true);
}
}
class RepaintTheBoard implements Runnable {
PolygonBuilder theBuilder;
public RepaintTheBoard(PolygonBuilder theBuilder) {
this.theBuilder = theBuilder;
}
@Override
public void run() {
theBuilder.repaint();
}
}
@SuppressWarnings("serial")
class BuilderDrawingPanel extends JComponent{
static Graphics2D graphicSettings;
static Shape drawLine;
public BuilderDrawingPanel() {
//stuff to draw at start
System.out.println("Drawing..");
drawLine = new Line2D.Float(480,480,0,0);
}
@Override
public void paint(Graphics g) {
graphicSettings = (Graphics2D)g;
System.out.println("Drawing..");
graphicSettings.setColor(Color.RED);
graphicSettings.fillRect(0, 0, getWidth(), getHeight());
graphicSettings.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphicSettings.setPaint(Color.BLUE);
graphicSettings.draw(drawLine);
}
}