有没有更好的方法来设置JPanel图形的初始位置?) [英] Is there a better way to set an initial position for a JPanel graphic?)
问题描述
在Liang的Java编程简介(第7版)的第15章中,他介绍了一个在JPanel上制作(2-D)球的程序,并在点击放大/缩小按钮。我修改了程序,它也可以1)放大/缩小球,如果用户点击/选项+点击,2)允许你通过按一下按钮选择球的颜色,3)允许你移动通过用鼠标拖动圈子。
最后一个修改是什么让我麻烦了一段时间,因为我想把球放在一开始,然后允许用户用鼠标移动球。我想出的解决方案是使paintComponent方法仅在第一次绘制时设置相对于getWidth()和getHeight()的球的x坐标和y坐标。为此,我向BallCanvas类添加了一个paintCount变量,并创建了一个if语句,以便它只会在第一次执行。当我试图弄清楚如何做到这一点,我看到其他解决方案,如这里给出的:为什么我无法访问我的面板的getWidth()和getHeight()函数?,但我发现我的解决方案更简单。
所以问题是:我是否认为坏的编码风格?专业程序员会否嘲笑这个解决方案?还是可以吗?
更重要的是,有没有一个更好的(但也是相对简单的)这样做,不涉及设置一个计数器?
以下是相关的代码段:
BallCanvas的开始: p>
public static class BallCanvas extends JPanel {
private int radius = 20;
私人颜色color = Color.BLACK;
private int ballX;
private int ballY;
private int paintCount = 0;
...
移动方法(响应MouseDragged事件):
public void move(MouseEvent e){
ballX = e.getX()半径;
ballY = e.getY() - radius;
repaint();
}
paintComponent方法:
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(color);
if(paintCount< 1){
ballX = getWidth()/ 2 - radius;
ballY = getHeight()/ 2 - radius;
}
g.fillOval(ballX,ballY,2 * radius,2 * radius);
paintCount ++;
}
完整程序:
//参考:Liang的Java编程简介
import javax.swing。*;
import java.awt。*;
import java.awt.event。*;
public class ControlBall extends JFrame {
private JButton jbtRed = new JButton(Red);
private JButton jbtGreen = new JButton(Green);
private JButton jbtBlue = new JButton(Blue);
private JButton jbtBlack = new JButton(Black);
private BallCanvas canvas = new BallCanvas();
private JMenuBar menuBar = new JMenuBar();
private JMenu menu = new JMenu(Edit);
private JMenuItem miEnlarge = new JMenuItem(Enlarge);
private JMenuItem miShrink = new JMenuItem(Shrink);
public ControlBall(){
menuBar.add(menu);
menu.add(miEnlarge);
menu.add(miShrink);
JPanel panel = new JPanel();
panel.add(jbtRed);
panel.add(jbtGreen);
panel.add(jbtBlue);
panel.add(jbtBlack);
this.add(canvas,BorderLayout.CENTER);
this.add(panel,BorderLayout.SOUTH);
this.add(menuBar,BorderLayout.NORTH);
jbtRed.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
canvas.setColor(Color.RED);
}
});
jbtGreen.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
canvas.setColor(Color.GREEN);
}
});
jbtBlue.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
canvas.setColor(Color.BLUE);
}
});
jbtBlack.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
canvas.setColor(Color.BLACK);
}
});
miEnlarge.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
canvas.enlarge();
}
}) ;
miShrink.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
canvas.shrink();
}
}) ;
canvas.addMouseListener(new MouseListener(){
public void mouseClicked(MouseEvent e){
canvas.changeSize(e);
}
public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
});
canvas.addMouseMotionListener(new MouseMotionAdapter(){
public void mouseDragged(MouseEvent e){
canvas.move(e);
}
});
}
public static void main(String [] args){
JFrame frame = new ControlBall();
frame.setTitle(ControlBall);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,200);
frame.setVisible(true);
}
public static class BallCanvas扩展JPanel {
private int radius = 20;
私人颜色color = Color.BLACK;
private int ballX;
private int ballY;
private int paintCount = 0;
public BallCanvas(){
System.out.println(getWidth()++ getHeight());
}
public BallCanvas(int initialRadius){
radius = initialRadius;
}
public void setColor(Color color){
this.color = color;
repaint();
}
public void changeSize(MouseEvent e){
int numClicks = e.getClickCount();
if(e.isAltDown()){
if(radius> = 6){
this.radius - = 5 * numClicks;
} else {
// do nothing
}
} else {
this.radius + = 5 * numClicks;
}
repaint();
}
public void enlarge(){
this.radius + = 5;
repaint();
}
public void shrink(){
if(radius> = 10){
this.radius - = 5 ;
}
repaint();
}
public void move(MouseEvent e){
ballX = e.getX() - radius;
ballY = e.getY() - radius;
repaint();
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(color);
if(paintCount< 1){
ballX = getWidth()/ 2 - radius;
ballY = getHeight()/ 2 - radius;
}
g.fillOval(ballX,ballY,2 * radius,2 * radius);
paintCount ++;
}
}
}
值得注意的几件事:
-
覆盖
getPreferredSize()
以建立面板的初始几何。 -
调用
pack()
和然后设置位置& -
使用
Action
来封装菜单和控件共享的代码。 -
使用适配器。
-
使用初始线程正确。
-
看到这个 Q& A ,从几个角度审视了一个相关的例子。
< img src =https://i.stack.imgur.com/iwscr.pngalt =image>
import javax.swing。*;
import java.awt。*;
import java.awt.event。*;
public class ControlBall extends JFrame {
private JButton jbtRed = new JButton(Red);
private JButton jbtGreen = new JButton(Green);
private JButton jbtBlue = new JButton(Blue);
private JButton jbtBlack = new JButton(Black);
private BallCanvas canvas = new BallCanvas();
private JMenuBar menuBar = new JMenuBar();
private JMenu menu = new JMenu(Edit);
private JMenuItem miEnlarge = new JMenuItem(Enlarge);
private JMenuItem miShrink = new JMenuItem(Shrink);
public ControlBall(){
menuBar.add(menu);
menu.add(miEnlarge);
menu.add(miShrink);
JPanel panel = new JPanel();
panel.add(jbtRed);
panel.add(jbtGreen);
panel.add(jbtBlue);
panel.add(jbtBlack);
this.add(canvas,BorderLayout.CENTER);
this.add(panel,BorderLayout.SOUTH);
this.add(menuBar,BorderLayout.NORTH);
jbtRed.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
canvas.setColor(Color.RED);
}
});
jbtGreen.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
canvas.setColor(Color.GREEN);
}
});
jbtBlue.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
canvas.setColor(Color.BLUE);
}
});
jbtBlack.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
canvas.setColor(Color.BLACK);
}
});
miEnlarge.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
canvas.enlarge();
}
});
miShrink.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
canvas.shrink();
}
});
canvas.addMouseListener(new MouseAdapter(){
@Override
public void mouseClicked(MouseEvent e){
canvas.changeSize(e);
}
@Override
public void mouseDragged(MouseEvent e){
canvas.move(e);
}
});
}
public static void main(String [] args){
EventQueue.invokeLater(new Runnable(){
@Override
public void run(){
JFrame frame = new ControlBall();
frame.setTitle(ControlBall);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
框架.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class BallCanvas extends JPanel {
private static final int SIZE = 400;
private int radius = 20;
私人颜色color = Color.BLACK;
private int ballX = SIZE / 2 - radius;
private int ballY = SIZE / 2 - radius;
public BallCanvas(){
System.out.println(getWidth()++ getHeight());
}
public BallCanvas(int initialRadius){
radius = initialRadius;
}
public void setColor(Color color){
this.color = color;
repaint();
}
public void changeSize(MouseEvent e){
int numClicks = e.getClickCount();
if(e.isAltDown()){
if(radius> = 6){
this.radius - = 5 * numClicks;
} else {
// do nothing
}
} else {
this.radius + = 5 * numClicks;
}
repaint();
}
public void enlarge(){
this.radius + = 5;
repaint();
}
public void shrink(){
if(radius> = 10){
this.radius - = 5 ;
}
repaint();
}
public void move(MouseEvent e){
ballX = e.getX() - radius;
ballY = e.getY() - radius;
repaint();
}
@Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(color);
g.fillOval(ballX,ballY,2 *半径,2 *半径);
}
@Override
public Dimension getPreferredSize(){
return new Dimension(SIZE,SIZE);
}
}
}
In Chapter 15 of Liang's Intro to Java Programming (7th ed.), he introduces a program to make a (2-D) ball on a JPanel and enlarge it upon clicking enlarge/shrink buttons. I've modified the program so that it also 1) enlarges/shrinks the ball if the user clicks/option+clicks, 2) allows you to pick the color of the ball by pressing a button, and 3) allows you to move the circle by dragging it with your mouse.
The last modification is what was giving me trouble for a while, because I wanted to center the ball at the beginning, but then allow the user to move the ball around with the mouse. The solution I came up with was to have the paintComponent method only set the x- and y-coordinates of the ball relative to getWidth() and getHeight() the first time it paints. To do that, I added a paintCount variable to the BallCanvas class and made an if statement so that it would only execute the first time around. When I was trying to figure out how to do this initially, I saw other solutions, like the ones given here: Why can't I access my panel's getWidth() and getHeight() functions? , but I find my solution much simpler.
So the question is: is what I did considered bad coding style? Would a professional programmer scoff at this solution? Or is it OK?
More importantly, is there a better (but also, relatively simple) way to do this that doesn't involve setting up a counter?
Here are the relevant bits of code:
The beginning of BallCanvas:
public static class BallCanvas extends JPanel {
private int radius = 20;
private Color color = Color.BLACK;
private int ballX;
private int ballY;
private int paintCount = 0;
...
The move method (which responds to a MouseDragged event):
public void move(MouseEvent e){
ballX = e.getX() - radius;
ballY = e.getY() - radius;
repaint();
}
The paintComponent method:
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(color);
if(paintCount < 1){
ballX = getWidth()/2 - radius;
ballY = getHeight()/2 - radius;
}
g.fillOval(ballX, ballY, 2*radius, 2*radius);
paintCount++;
}
Full program:
// Reference: Liang's Intro to Java Programming
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ControlBall extends JFrame{
private JButton jbtRed = new JButton("Red");
private JButton jbtGreen = new JButton("Green");
private JButton jbtBlue = new JButton("Blue");
private JButton jbtBlack = new JButton("Black");
private BallCanvas canvas = new BallCanvas();
private JMenuBar menuBar = new JMenuBar();
private JMenu menu = new JMenu("Edit");
private JMenuItem miEnlarge = new JMenuItem("Enlarge");
private JMenuItem miShrink = new JMenuItem("Shrink");
public ControlBall(){
menuBar.add(menu);
menu.add(miEnlarge);
menu.add(miShrink);
JPanel panel = new JPanel();
panel.add(jbtRed);
panel.add(jbtGreen);
panel.add(jbtBlue);
panel.add(jbtBlack);
this.add(canvas, BorderLayout.CENTER);
this.add(panel, BorderLayout.SOUTH);
this.add(menuBar, BorderLayout.NORTH);
jbtRed.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
canvas.setColor(Color.RED);
}
});
jbtGreen.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
canvas.setColor(Color.GREEN);
}
});
jbtBlue.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
canvas.setColor(Color.BLUE);
}
});
jbtBlack.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
canvas.setColor(Color.BLACK);
}
});
miEnlarge.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
canvas.enlarge();
}
});
miShrink.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
canvas.shrink();
}
});
canvas.addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent e){
canvas.changeSize(e);
}
public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
});
canvas.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
canvas.move(e);
}
});
}
public static void main(String[] args){
JFrame frame = new ControlBall();
frame.setTitle("ControlBall");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 200);
frame.setVisible(true);
}
public static class BallCanvas extends JPanel {
private int radius = 20;
private Color color = Color.BLACK;
private int ballX;
private int ballY;
private int paintCount = 0;
public BallCanvas(){
System.out.println(getWidth() + " " + getHeight());
}
public BallCanvas(int initialRadius){
radius = initialRadius;
}
public void setColor(Color color){
this.color = color;
repaint();
}
public void changeSize(MouseEvent e){
int numClicks = e.getClickCount();
if(e.isAltDown()){
if(radius >= 6){
this.radius -= 5*numClicks;
} else{
// do nothing
}
} else{
this.radius += 5*numClicks;
}
repaint();
}
public void enlarge(){
this.radius += 5;
repaint();
}
public void shrink(){
if(radius >= 10){
this.radius -= 5;
}
repaint();
}
public void move(MouseEvent e){
ballX = e.getX() - radius;
ballY = e.getY() - radius;
repaint();
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(color);
if(paintCount < 1){
ballX = getWidth()/2 - radius;
ballY = getHeight()/2 - radius;
}
g.fillOval(ballX, ballY, 2*radius, 2*radius);
paintCount++;
}
}
}
Several things merit attention:
Override
getPreferredSize()
to establish the panel's initial geometry.Use that geometry to establish the ball's initial position.
Invoke
pack()
and then set the location & visibility.Use
Action
to encapsulate code shared by menus and controls.Use adapters consistently.
Use initial threads correctly.
See this Q&A, which examines a related example from several perspectives.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ControlBall extends JFrame {
private JButton jbtRed = new JButton("Red");
private JButton jbtGreen = new JButton("Green");
private JButton jbtBlue = new JButton("Blue");
private JButton jbtBlack = new JButton("Black");
private BallCanvas canvas = new BallCanvas();
private JMenuBar menuBar = new JMenuBar();
private JMenu menu = new JMenu("Edit");
private JMenuItem miEnlarge = new JMenuItem("Enlarge");
private JMenuItem miShrink = new JMenuItem("Shrink");
public ControlBall() {
menuBar.add(menu);
menu.add(miEnlarge);
menu.add(miShrink);
JPanel panel = new JPanel();
panel.add(jbtRed);
panel.add(jbtGreen);
panel.add(jbtBlue);
panel.add(jbtBlack);
this.add(canvas, BorderLayout.CENTER);
this.add(panel, BorderLayout.SOUTH);
this.add(menuBar, BorderLayout.NORTH);
jbtRed.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
canvas.setColor(Color.RED);
}
});
jbtGreen.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
canvas.setColor(Color.GREEN);
}
});
jbtBlue.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
canvas.setColor(Color.BLUE);
}
});
jbtBlack.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
canvas.setColor(Color.BLACK);
}
});
miEnlarge.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
canvas.enlarge();
}
});
miShrink.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
canvas.shrink();
}
});
canvas.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
canvas.changeSize(e);
}
@Override
public void mouseDragged(MouseEvent e) {
canvas.move(e);
}
});
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new ControlBall();
frame.setTitle("ControlBall");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class BallCanvas extends JPanel {
private static final int SIZE = 400;
private int radius = 20;
private Color color = Color.BLACK;
private int ballX = SIZE / 2 - radius;
private int ballY = SIZE / 2 - radius;
public BallCanvas() {
System.out.println(getWidth() + " " + getHeight());
}
public BallCanvas(int initialRadius) {
radius = initialRadius;
}
public void setColor(Color color) {
this.color = color;
repaint();
}
public void changeSize(MouseEvent e) {
int numClicks = e.getClickCount();
if (e.isAltDown()) {
if (radius >= 6) {
this.radius -= 5 * numClicks;
} else {
// do nothing
}
} else {
this.radius += 5 * numClicks;
}
repaint();
}
public void enlarge() {
this.radius += 5;
repaint();
}
public void shrink() {
if (radius >= 10) {
this.radius -= 5;
}
repaint();
}
public void move(MouseEvent e) {
ballX = e.getX() - radius;
ballY = e.getY() - radius;
repaint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(color);
g.fillOval(ballX, ballY, 2 * radius, 2 * radius);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(SIZE, SIZE);
}
}
}
这篇关于有没有更好的方法来设置JPanel图形的初始位置?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!