我正在尝试创建一个绘制矩形(实际上是两个矩形)的程序,这个矩形根据每50ms产生的随机数上下移动。基本上,程序一遍又一遍地添加一个-5到5之间的随机数,直到它达到-85和85的阈值限制。我试图使paint()方法工作,但我从未看到矩形。我已经附加了我的基础程序,没有任何油漆的东西。我刚刚开始,所以我相信有更简单的方法来做所有事情。 基本上,我希望dialNum指示水平矩形的Y值,以便每次更新dialNum时它都会移动。现在我让它显示int dialNum,但它将被矩形取代。 (对于counterNum来说相同)
public class runDrones {
public static int counterNum = 0;
public static int dialNum = 0;
public runDrones() {
final JFrame display = new JFrame();
display.setSize(800,400);
display.setLayout(new GridLayout());
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
display.setLocationRelativeTo(null);
display.setVisible(true);
Thread viewDial = new Thread(){
public void run() {
try {
runDial();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void runDial() throws InterruptedException {
JLabel dialStatus = new JLabel("OOPS");
dialStatus.setFont(new Font("Verdana",1,86));
display.add(dialStatus);
while(dialNum >=-85 && dialNum <= 60){
dialNum += getRandom();
dialStatus.setText(Integer.toString(dialNum));
Thread.sleep(50);
}
dialStatus.setText("ALARM!!");
}
};
Thread viewCounter = new Thread(){
public void run(){
try {
runCounter();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void runCounter() throws InterruptedException {
JLabel counterStatus = new JLabel("OOPS");
counterStatus.setFont(new Font("Verdana",1,86));
display.add(counterStatus);
while(counterNum >=-75 && counterNum <= 75){
counterNum += getRandom();
counterStatus.setText(Integer.toString(counterNum));
Thread.sleep(50);
}
counterStatus.setText("ALARM!!");
}
};
viewDial.start();
viewCounter.start();
}
public static int getRandom(){
int firstNum = new Random().nextInt(5) + 1;
int secondNum = new Random().nextInt(5) + 1;
return firstNum - secondNum;
}
}
答案 0 :(得分:1)
Swing不是线程安全的,这意味着除了从事件调度线程的上下文之外,不应该以任何方式更新或修改UI。有关详细信息,请参阅Concurrency in Swing。
对于Swing中的动画,请考虑使用javax.swing.Timer
。
以下示例使用javax.swing.Timer
代替Thread
s。通常情况下,我更喜欢使用单Timer
,因为它减少了EDT的开销,但我想创建一个模仿你自己的例子的演示......
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RunDrones {
public static int counterNum = 0;
final JFrame display;
private final JLabel counterStatus;
private final JLabel dialStatus;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
new RunDrones();
}
});
}
public RunDrones() {
display = new JFrame();
display.setLayout(new GridLayout());
dialStatus = new JLabel("OOPS");
dialStatus.setFont(new Font("Verdana", 1, 86));
display.add(dialStatus);
counterStatus = new JLabel("OOPS");
counterStatus.setFont(new Font("Verdana", 1, 86));
display.add(counterStatus);
display.setSize(800, 400);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
display.setLocationRelativeTo(null);
display.setVisible(true);
Timer dialTimer = new Timer(50, new Dial());
dialTimer.setInitialDelay(0);
Timer counterTimer = new Timer(50, new Counter());
dialTimer.start();
counterTimer.start();
}
public static int getRandom() {
int firstNum = new Random().nextInt(5) + 1;
int secondNum = new Random().nextInt(5) + 1;
return firstNum - secondNum;
}
public class Dial implements ActionListener {
private int dialNum;
@Override
public void actionPerformed(ActionEvent e) {
if (dialNum >= -85 && dialNum <= 60) {
dialNum += getRandom();
dialStatus.setText(Integer.toString(dialNum));
} else {
((Timer) e.getSource()).stop();
dialStatus.setText("ALARM!!");
}
}
}
public class Counter implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if (counterNum >= -75 && counterNum <= 75) {
counterNum += getRandom();
counterStatus.setText(Integer.toString(counterNum));
} else {
((Timer) e.getSource()).stop();
counterStatus.setText("ALARM!!");
}
}
}
}
您可能还希望阅读Performing Custom Painting
更新了粗略的示例
这是绘制矩形的一个粗略示例......现在,就个人而言,如果我这样做,我会建立某种范围模型并从中生成一个百分比值,可以用来显示矩形一个给定的可视区域,它只会让生活更轻松,但那就是我......
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RunDrones {
public static int counterNum = 0;
final JFrame display;
private final JLabel counterStatus;
private RectanglePane dialPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
new RunDrones();
}
});
}
public RunDrones() {
display = new JFrame();
display.setLayout(new GridLayout());
dialPane = new RectanglePane();
display.add(dialPane);
counterStatus = new JLabel("OOPS");
counterStatus.setFont(new Font("Verdana", 1, 86));
display.add(counterStatus);
display.setSize(800, 400);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
display.setLocationRelativeTo(null);
display.setVisible(true);
Timer dialTimer = new Timer(50, new Dial(dialPane));
dialTimer.setInitialDelay(0);
Timer counterTimer = new Timer(50, new Counter());
dialTimer.start();
counterTimer.start();
}
public static int getRandom() {
int firstNum = new Random().nextInt(5) + 1;
int secondNum = new Random().nextInt(5) + 1;
return firstNum - secondNum;
}
public class RectanglePane extends JPanel {
private int yPos;
public void setYPos(int yPos) {
this.yPos = yPos;
repaint();
}
public int getYPos() {
return yPos;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
int y = (getHeight() / 2) - 85;
int x = (getWidth() - 20) / 2;
g.drawRect(x, y, 40, 165);
// y = (getHeight() + getYPos()) / 2;
y = (getHeight() / 2) + getYPos();
g.setColor(getForeground());
g.fillRect(x, y, 40, 40);
}
}
public class Dial implements ActionListener {
private int dialNum;
private RectanglePane pane;
public Dial(RectanglePane pane) {
this.pane = pane;
pane.setForeground(Color.GREEN);
}
@Override
public void actionPerformed(ActionEvent e) {
if (dialNum >= -85 && dialNum <= 60) {
dialNum += getRandom();
pane.setYPos(dialNum);
} else {
pane.setForeground(Color.RED);
((Timer) e.getSource()).stop();
}
}
}
public class Counter implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if (counterNum >= -75 && counterNum <= 75) {
counterNum += getRandom();
counterStatus.setText(Integer.toString(counterNum));
} else {
((Timer) e.getSource()).stop();
counterStatus.setText("ALARM!!");
}
}
}
}
简单RangeModel
public class RangeModel {
private final int min;
private final int max;
private int value;
public RangeModel(int min, int max) {
this.min = min;
this.max = max;
}
public int getMin() {
return min;
}
public int getMax() {
return max;
}
public int getValue() {
return value;
}
public void setValue(int newValue) {
newValue = Math.max(getMin(), newValue);
newValue = Math.min(getMax(), newValue);
this.value = newValue;
}
public double getProgress() {
int range = getMax() - getMin();
int normalValue = getValue() - getMin();
return (double)normalValue / ((double)range - 1);
}
}
使用示例......
RangelModel model = new RangelModel(-85, 85);
for (int i = model.getMin(); i < model.getMax(); i++) {
model.setValue(i);
System.out.println(NumberFormat.getPercentInstance().format(model.getProgress()));
}
答案 1 :(得分:0)
好的,关于绘画:
你不能用负x或y坐标绘画 - 它们必须是正面的(不能转到-85)
问题的解决方案:要在屏幕上再次绘画,您希望线程调用:
重绘();
在扩展JFrame或任何其他JComponent的情况下,这是一个继承的方法。如果没有,请在您已有的JFrame对象上调用它(不确定是否可能 - 重绘可能是受保护的方法)
答案 2 :(得分:0)
作为MadProgrammer mentioned,对于Swing中的动画,请考虑使用javax.swing.Timer而不是Thread。
对于问题中发布的代码,您可以按如下方式显示矩形:
创建一个扩展JPanel的类,并覆盖paintComponent
class RectanglePanel extends JPanel{
int y; //<<---The Y coordinate, which will be modified externally
public void setY(int y) { //<<---The setter method to change the Y-coord
this.y = y;
repaint(); //<<---To repaint the rectangle after the Y coordinate is changed
}
protected void paintComponent(Graphics g) { //<<---Override the paintComponent
super.paintComponent(g);
g.setColor(Color.black); //<<---set the color of rectangle
g.drawRect(20, y, 100, 60); //<<---use the y-value to paint the rect
}
}
2. 创建类的对象并将其添加到JFrame
public static int counterNum = 0;
public static int dialNum = 0;
RectanglePanel panel = new RectanglePanel(); //<<---Create the object here
//<<---rest of the code -->>
display.setLayout(new GridLayout());
display.add(panel); //<<---Add the object to the JPanel before setVisible
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
3. 定期更改Y值
counterNum += getRandom();
counterStatus.setText(Integer.toString(counterNum));
panel.setY(counterNum); //<<---Change the Y value of rectangle