Im wondering if anyone can help me replicate the below screenshot.
im tring to display a counter that will count in increments of 20 up to 100 the will count up 1 on the left hand side number then keep counting in increments and replicate..
eg:000 > 0/0/20 0/1/60
> 0/0/40 0/1/80
> 0/0/60 0/2/00
> 0/0/80 0/2/20
> 0/1/00 >>>>
> 0/1/20 0/9/80
> 0/1/40 1/0/00
etc...
This is an incredibly basic example. There is a lot of room for improvement in it's range checking.
The linear scroller is really simple. In the end I used the same basic concept as I did for the circular scroller, simply creating a BufferedImage with all the values marked on it, and based on the value, calculate the appropriate layout position.
The circular scroller took a little longer to bring about. The end result is really rather basic, the trouble is in calculating the under and overflow values.
The circular scroll simple creates a BufferedImage of all the available values. Based on it's display position, we either paint another copy of it before or after it, to give the illusion of flow...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.BoundedRangeModel;
import javax.swing.DefaultBoundedRangeModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class Altimiter {
public static void main(String[] args) {
new Altimiter();
}
public Altimiter() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private AltPane altPane;
public TestPane() {
JButton up = new JButton("+");
JButton down = new JButton("-");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
add(up, gbc);
gbc.gridy++;
add(down, gbc);
gbc.gridx++;
gbc.gridy = 0;
gbc.gridheight = GridBagConstraints.REMAINDER;
altPane = new AltPane();
add(altPane, gbc);
up.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
altPane.setSpeed(25);
}
});
down.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
altPane.setSpeed(-25);
}
});
altPane.setValue(0);
}
}
public class AltPane extends JPanel {
private LinearScrollerPane major;
private CircularScrollerPane minor;
private int altitude = 0;
private int direction = 0;
private Timer timer;
public AltPane() {
major = new LinearScrollerPane();
minor = new CircularScrollerPane();
major.setOpaque(false);
minor.setOpaque(false);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.VERTICAL;
gbc.weighty = 1;
add(major, gbc);
gbc.gridx++;
add(minor, gbc);
setBorder(new LineBorder(Color.BLUE));
timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
altitude += direction;
if (altitude < 0) {
((Timer) e.getSource()).stop();
altitude = 0;
} else if (altitude > 20000) {
((Timer) e.getSource()).stop();
altitude = 20000;
}
System.out.println("value = " + altitude);
setValue(altitude);
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.setInitialDelay(0);
}
public void setSpeed(int speed) {
this.direction = speed;
timer.start();
}
public void setValue(int value) {
int hnds = value / 100;
int units = value - (hnds * 100);
if (units == 0) {
if (hnds > 0 && direction > 0) {
units = 100;
} else if (hnds > 0 && direction < 0) {
units = -1;
} else {
units = 0;
}
}
major.setValue(hnds);
minor.setValue(units);
invalidate();
repaint();
}
public int getValue() {
int ths = major.getValue();
int hnds = minor.getValue();
return (ths * 100) + hnds;
}
#Override
public void paint(Graphics g) {
super.paint(g);
Insets insets = getInsets();
int width = getWidth() - (insets.left + insets.top);
int height = getHeight() - (insets.top + insets.bottom);
g.setColor(new Color(255, 0, 0, 128));
int centerY = insets.top + (height / 2);
g.drawLine(insets.left, centerY, insets.left + width, centerY);
}
}
public class CircularScrollerPane extends JPanel {
private BufferedImage baseView;
private BoundedRangeModel model;
private float startValue = 0;
private float currentValue = 0;
private float targetValue = 0;
private int rowCount = 3;
private Timer timer;
private long startTime;
private int runTime = 1000;
public CircularScrollerPane() {
setModel(new DefaultBoundedRangeModel(0, 20, 0, 100));
timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
long now = System.currentTimeMillis();
long diff = now - startTime;
if (diff >= runTime) {
((Timer) (e.getSource())).stop();
diff = runTime;
}
float progress = (float) diff / (float) runTime;
currentValue = calculateProgress(startValue, targetValue, progress);
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(false);
}
public int getValue() {
return getModel().getValue();
}
public void setValue(int value) {
timer.stop();
BoundedRangeModel model = getModel();
if (value < model.getMinimum()) {
value = model.getMaximum() + (value + 1);
currentValue += model.getMaximum(); // overflow
} else if (value > model.getMaximum() - model.getExtent()) {
value = model.getMinimum() + (value - model.getMaximum());
currentValue -= model.getMaximum(); // underflow
}
startValue = currentValue;
targetValue = value;
model.setValue(value);
startTime = System.currentTimeMillis();
timer.start();
}
#Override
public Dimension getPreferredSize() {
FontMetrics fm = getFontMetrics(getFont());
return fm == null ? super.getPreferredSize() : new Dimension(fm.stringWidth("MMM"), fm.getHeight() * getRowCount());
}
public void setRowCount(int value) {
if (value != rowCount) {
int old = rowCount;
rowCount = value;
invalidate();
repaint();
firePropertyChange("rowCount", old, rowCount);
}
}
public int getRowCount() {
return rowCount;
}
public void setModel(BoundedRangeModel value) {
if (value != null) {
BoundedRangeModel old = model;
model = value;
if (model != null) {
currentValue = model.getValue();
targetValue = model.getValue();
} else {
currentValue = 0;
targetValue = 0;
}
baseView = null;
firePropertyChange("model", old, model);
}
}
public BoundedRangeModel getModel() {
return model;
}
#Override
public void invalidate() {
super.invalidate();
baseView = null;
}
public float getViewOffSet(float value) {
Font font = getFont();
FontMetrics fm = getFontMetrics(font);
int rowHeight = fm.getHeight();
int extent = model.getExtent();
int min = model.getMinimum();
int max = model.getMaximum();
int viewRange = max - min;
int ticks = viewRange / extent;
float p = value / (float) viewRange;
return ((rowHeight * ticks) * p) + ((fm.getAscent() + fm.getDescent()) / 2);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
BufferedImage masterView = getMasterView();
if (masterView != null) {
Insets insets = getInsets();
int width = getWidth() - (insets.left + insets.right);
int height = getHeight() - (insets.top + insets.bottom);
int centerY = height / 2;
FontMetrics fm = g.getFontMetrics();
int yOffset = centerY - (int) getViewOffSet(currentValue);
g.drawImage(masterView, insets.left, insets.top + yOffset, this);
// Heading image...
if (yOffset > 0) {
g.drawImage(masterView, insets.left, insets.top + yOffset - masterView.getHeight(), this);
}
// Tailing image...
if (yOffset + masterView.getHeight() < height) {
g.drawImage(masterView, insets.left, insets.top + yOffset + masterView.getHeight(), this);
}
}
}
protected String pad(int value) {
StringBuilder sb = new StringBuilder(value);
sb.ensureCapacity(3);
sb.append(value);
while (sb.length() < 3) {
sb.insert(0, "0");
}
return sb.toString();
}
protected BufferedImage getMasterView() {
if (baseView == null) {
Insets insets = getInsets();
int width = getWidth() - (insets.left + insets.right);
int height = getHeight() - (insets.top + insets.bottom);
BoundedRangeModel model = getModel();
int extent = model.getExtent();
int min = model.getMinimum();
int max = model.getMaximum();
int viewRange = max - min;
int ticks = viewRange / extent;
Font font = getFont();
FontMetrics fm = getFontMetrics(font);
baseView = new BufferedImage(width, fm.getHeight() * ticks, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = baseView.createGraphics();
g2d.setFont(font);
g2d.setColor(Color.BLACK);
int yPos = 0;
for (int index = min; index < max; index += extent) {
String value = pad(index);
g2d.drawString(value, width - fm.stringWidth(value), yPos + fm.getAscent());
yPos += fm.getHeight();
}
}
return baseView;
}
}
public class LinearScrollerPane extends JPanel {
private BufferedImage baseView;
private BoundedRangeModel model;
private float startValue = 0;
private float currentValue = 0;
private float targetValue = 0;
private int rowCount = 3;
private Timer timer;
private long startTime;
private int runTime = 1000;
public LinearScrollerPane() {
Font font = UIManager.getFont("Label.font");
setFont(font.deriveFont(Font.BOLD, font.getSize() + 4));
setModel(new DefaultBoundedRangeModel(0, 0, 0, 20));
timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
long now = System.currentTimeMillis();
long diff = now - startTime;
if (diff >= runTime) {
((Timer) (e.getSource())).stop();
diff = runTime;
}
float progress = (float) diff / (float) runTime;
currentValue = calculateProgress(startValue, targetValue, progress);
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(false);
}
public int getValue() {
return getModel().getValue();
}
public void setValue(int value) {
timer.stop();
BoundedRangeModel model = getModel();
if (value < model.getMinimum()) {
value = model.getMinimum();
} else if (value > model.getMaximum() - model.getExtent()) {
value = model.getMaximum() - model.getExtent();
}
startValue = currentValue;
targetValue = value;
model.setValue(value);
startTime = System.currentTimeMillis();
timer.start();
}
#Override
public Dimension getPreferredSize() {
FontMetrics fm = getFontMetrics(getFont());
return fm == null ? super.getPreferredSize() : new Dimension(fm.stringWidth("MM"), fm.getHeight() * getRowCount());
}
public void setRowCount(int value) {
if (value != rowCount) {
int old = rowCount;
rowCount = value;
invalidate();
repaint();
firePropertyChange("rowCount", old, rowCount);
}
}
public int getRowCount() {
return rowCount;
}
public void setModel(BoundedRangeModel value) {
if (value != null) {
BoundedRangeModel old = model;
model = value;
if (model != null) {
currentValue = model.getValue();
targetValue = model.getValue();
} else {
currentValue = 0;
targetValue = 0;
}
baseView = null;
firePropertyChange("model", old, model);
}
}
public BoundedRangeModel getModel() {
return model;
}
#Override
public void invalidate() {
super.invalidate();
baseView = null;
}
public float getViewOffSet(float value) {
Font font = getFont();
FontMetrics fm = getFontMetrics(font);
int rowHeight = fm.getHeight();
int min = model.getMinimum();
int max = model.getMaximum();
int viewRange = max - min;
int ticks = getTicks();
float p = value / (float) viewRange;
return ((rowHeight * ticks) * p) + ((fm.getAscent() + fm.getDescent()) / 2);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
BufferedImage masterView = getMasterView();
if (masterView != null) {
Insets insets = getInsets();
int width = getWidth() - (insets.left + insets.right);
int height = getHeight() - (insets.top + insets.bottom);
int centerY = height / 2;
FontMetrics fm = g.getFontMetrics();
int yOffset = centerY - (int) getViewOffSet(currentValue);
g.drawImage(masterView, insets.left, insets.top + yOffset, this);
}
}
protected String pad(int value) {
StringBuilder sb = new StringBuilder(value);
sb.ensureCapacity(3);
sb.append(value);
while (sb.length() < 3) {
sb.insert(0, "0");
}
return sb.toString();
}
protected int getTicks() {
BoundedRangeModel model = getModel();
int extent = model.getExtent();
int min = model.getMinimum();
int max = model.getMaximum();
int viewRange = max - min;
int ticks = viewRange;
if (extent > 0) {
ticks = viewRange / extent;
}
return ticks;
}
protected BufferedImage getMasterView() {
if (baseView == null) {
Insets insets = getInsets();
int width = getWidth() - (insets.left + insets.right);
int height = getHeight() - (insets.top + insets.bottom);
BoundedRangeModel model = getModel();
int extent = model.getExtent();
int min = model.getMinimum();
int max = model.getMaximum();
int ticks = getTicks() + 1;
Font font = getFont();
FontMetrics fm = getFontMetrics(font);
baseView = new BufferedImage(width, fm.getHeight() * ticks, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = baseView.createGraphics();
g2d.setFont(font);
g2d.setColor(Color.BLACK);
int yPos = 0;
for (int index = min; index < max + 1; index += Math.max(1, extent)) {
String value = String.valueOf(index);
g2d.drawString(value, width - fm.stringWidth(value), yPos + fm.getAscent());
yPos += fm.getHeight();
}
g2d.dispose();
}
return baseView;
}
}
public static float calculateProgress(float startValue, float endValue, double fraction) {
float value = 0;
float distance = endValue - startValue;
value = (float) (distance * fraction);
value += startValue;
return value;
}
}
You can do this with a custom SliderUI, shown here, is a JSlider having a VERTICAL orientation. The example calls drawLine () in paintThumb(), but you can use TextLayout, illustrated here, to render the numbers.
Related
My Task:
Create an application that displays a Hangman graphic for 10 steps. This graphic should be controllable via a text field and a slider (in the range 0-10) for test purposes. The text box updates the graph as soon as the value is changed and does not wait until the Enter key is pressed. If an invalid value is entered in the text field, then an error message is displayed instead of the graphic (with the method drawString text can also be "drawn"), if there should be no value there, then the graphic should remain empty.
In my program, the change of the graphics on the JSlider works fine, but the input via the text field causes no change and the check when entering an incorrect value, I tried, but then nothing is displayed. I do not understand what's wrong because the JTextField approach is the same as JSlider ...
I have put the source code of both classes down below.
First Class:
Imports, Package...
public class HangmanFrame extends JFrame{
public HangmanFrame(){
super("Hangman");
HangmanPanel panel = new HangmanPanel();
JPanel mainPanel = new JPanel();
this.add(mainPanel);
mainPanel.setLayout(new BorderLayout());
JTextField t = new JTextField();
t.getDocument().addDocumentListener(new DocumentListener(){
#Override
public void changedUpdate(DocumentEvent arg0) {
try{
Integer.parseInt(t.getText());
}
catch(NumberFormatException ex){
System.out.println(ex.getMessage());
}
panel.repaint();
}
#Override
public void insertUpdate(DocumentEvent arg0) {
try{
Integer.parseInt(t.getText());
}
catch(NumberFormatException ex){
System.out.println(ex.getMessage());
}
panel.repaint();
}
#Override
public void removeUpdate(DocumentEvent arg0) {
try{
Integer.parseInt(t.getText());
}
catch(NumberFormatException ex){
System.out.println(ex.getMessage());
}
panel.repaint();
}
});
JSlider s = new JSlider(JSlider.HORIZONTAL, 0, 10, 0);
s.addChangeListener(new ChangeListener(){
#Override
public void stateChanged(ChangeEvent arg0) {
panel.repaint();
}
});
panel.setSlider(s);
panel.setTextField(t);
mainPanel.add(panel, BorderLayout.CENTER);
mainPanel.add(s, BorderLayout.PAGE_END);
mainPanel.add(t, BorderLayout.PAGE_START);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setSize(300,500);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public static void main(String[] args) {
new HangmanFrame();
}
}
Second Class:
public class HangmanPanel extends JPanel {
private JSlider slider;
private JTextField field; //Height 500, Width 300
public void paintComponent(Graphics g){
super.paintComponent(g);
int sliderValue = slider.getValue();
String fieldValue = field.getText();
//int fieldInt = Integer.parseInt(fieldValue);
g.drawLine(0, super.getWidth() + 99, super.getHeight(), super.getWidth() + 99);
if(sliderValue == 0 || fieldValue.equals("0")){
return;
}
g.setColor(new Color(205,133,63));
int xArc = this.getWidth() / 20;
int yArc = this.getHeight() - this.getHeight() / 5;
int arcWidth = this.getWidth() / 2;
int arcHeight = this.getHeight() / 5;
g.fillArc(xArc, yArc, arcWidth, arcHeight, 0, 180);
if(sliderValue == 1 || fieldValue.equals("1")){
return;
}
g.setColor(Color.BLACK);
int x1Line = xArc + arcWidth / 2;
int x2Line = x1Line;
int y1Line = yArc;
int y2Line = this.getHeight() / 6;
g.drawLine(x1Line, y1Line, x2Line, y2Line);
if(sliderValue == 2 || fieldValue.equals("2")){
return;
}
int x3Line = x1Line;
int x4Line = x3Line + (this.getWidth() / 3) + 20;
int y3Line = y2Line;
int y4Line = y3Line;
g.drawLine(x3Line, y3Line, x4Line, y4Line);
if(sliderValue == 3 || fieldValue.equals("3")){
return;
}
int x5Line = x4Line;
int x6Line = x5Line;
int y5Line = y4Line;
int y6Line = y5Line + this.getWidth() / 5; // + 60
g.drawLine(x5Line, y5Line, x6Line, y6Line);
if(sliderValue == 4 || fieldValue.equals("4")){
return;
}
g.setColor(new Color(255, 221, 204));
g.fillOval(x6Line - this.getHeight() / 20, y6Line, this.getHeight() / 10, this.getHeight() / 10); // -25, ...,50, 50
if(sliderValue == 5 || fieldValue.equals("5")){
return;
}
g.setColor(Color.BLUE);
g.fillOval((int) ((int) x6Line - this.getHeight() / 14.7) , (int) (y6Line + this.getHeight() / 10.41), (int)(this.getHeight() / 7.14), (int)(this.getHeight() / 4.16)); // 34, 48, 70, 120
if(sliderValue == 6 || fieldValue.equals("6")){
return;
}
int x7Line = x6Line + (int)(this.getHeight() / 17.85); // 28
int x8Line = x7Line + (int)(this.getHeight() / 12.5); // 40
int y7Line = y6Line + (int)(this.getHeight() / 7.14); // 70
int y8Line = y7Line - (int)(this.getHeight() / 14.28); // 35
g.setColor(Color.BLACK);
g.drawLine(x7Line, y7Line, x8Line, y8Line);
if(sliderValue == 7 || fieldValue.equals("7")){
return;
}
int x9Line = x7Line - (int)(this.getHeight() / 9.43); // 53
int x10Line = x9Line - (int)(this.getHeight() / 14.28); // 35
int y9Line = y7Line;
int y10Line = y8Line;
g.drawLine(x9Line, y9Line, x10Line, y10Line);
if(sliderValue == 8 || fieldValue.equals("8")){
return;
}
int x11Line = x7Line;
int x12Line = x8Line;
int y11Line = y7Line + (int)(this.getHeight() / 6.66); // 75
int y12Line = y8Line + (int)(this.getHeight() / 3.33); // 150
g.drawLine(x11Line, y11Line, x12Line, y12Line);
if(sliderValue == 9 || fieldValue.equals("9")){
return;
}
int x13Line = x9Line;
int x14Line = x10Line;
int y13Line = y11Line;
int y14Line = y12Line;
g.drawLine(x13Line, y13Line, x14Line, y14Line);
}
public void setSlider(JSlider slider){
this.slider = slider;
}
public void setTextField(JTextField field){
this.field = field;
}
}
Your JTextField reading works, but a problem is that you're first checking for the slider's value, and so if the slider if check is true, the method short circuits. To prove that it's working, move the slider all the way to the right, and then enter 1 or 2 into the JTextField.
If this were my project and I wanted to test this effect, I'd get all logic out of the painting method and instead allow my controllers to change a state value of the observed class, call repaint() and then draw the image based on that state.
For example, something like so:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
#SuppressWarnings("serial")
public class HangmanGUI2 extends JPanel {
private HangmanModel model = new HangmanModel();
private HangmanPanel2 panel2 = new HangmanPanel2(model);
private JSlider slider = new JSlider(0, HangmanModel.MAX_VALUE, 0);
private JTextField textField = new JTextField(10);
public HangmanGUI2() {
textField.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void removeUpdate(DocumentEvent e) {
updateModel(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
updateModel(e);
}
#Override
public void changedUpdate(DocumentEvent e) {
updateModel(e);
}
private void updateModel(DocumentEvent e) {
Document doc = e.getDocument();
int length = doc.getLength();
try {
String text = doc.getText(0, length);
int value = Integer.parseInt(text.trim());
setModelValue(value);
} catch (BadLocationException e1) {
e1.printStackTrace();
} catch (NumberFormatException e1) {
// Do Nothing
}
}
});
slider.setMajorTickSpacing(1);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.addChangeListener(e -> {
int value = slider.getValue();
setModelValue(value);
});
setLayout(new BorderLayout());
add(panel2);
add(textField, BorderLayout.PAGE_START);
add(slider, BorderLayout.PAGE_END);
// new Timer(1000, e -> {
// model.increment();
// repaint();
// }).start();
}
protected void setModelValue(int value) {
model.setValue(value);
repaint();
}
private static void createAndShowGui() {
HangmanGUI2 mainPanel = new HangmanGUI2();
JFrame frame = new JFrame("HangmanGUI2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class HangmanModel {
public static final int MAX_VALUE = 9;
private int value = 0;
public int getValue() {
return value;
}
public void increment() {
setValue(getValue() + 1);
}
public void setValue(int value) {
this.value = Math.min(value, MAX_VALUE);
this.value = Math.max(this.value, 0);
}
}
#SuppressWarnings("serial")
class HangmanPanel2 extends JPanel {
private HangmanModel model;
private List<Image> images = ImageCreator.getImages();
public HangmanPanel2(HangmanModel model) {
this.model = model;
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || images.size() == 0) {
return super.getPreferredSize();
}
int w = images.get(0).getWidth(this);
int h = images.get(0).getHeight(this);
return new Dimension(w, h);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(images.get(model.getValue()), 0, 0, this);
}
}
class ImageCreator {
private static final int W = 284;
private static final int H = 425;
private static final Color BASE_COLOR = new Color(205, 133, 63);
public static List<Image> getImages() {
List<Image> images = new ArrayList<>();
BufferedImage img = new BufferedImage(W, H, BufferedImage.TYPE_INT_ARGB);
images.add(createImageCopy(img));
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(BASE_COLOR);
int xArc = W / 20;
int yArc = H - H / 5;
int arcWidth = W / 2;
int arcHeight = H / 5;
g2.fillArc(xArc, yArc, arcWidth, arcHeight, 0, 180);
images.add(createImageCopy(img));
// -----------------------------------------
g2.setColor(Color.BLACK);
int x1Line = xArc + arcWidth / 2;
int x2Line = x1Line;
int y1Line = yArc;
int y2Line = H / 6;
g2.drawLine(x1Line, y1Line, x2Line, y2Line);
images.add(createImageCopy(img));
// -----------------------------------------
int x3Line = x1Line;
int x4Line = x3Line + (W / 3) + 20;
int y3Line = y2Line;
int y4Line = y3Line;
g2.drawLine(x3Line, y3Line, x4Line, y4Line);
images.add(createImageCopy(img));
// -----------------------------------------
int x5Line = x4Line;
int x6Line = x5Line;
int y5Line = y4Line;
int y6Line = y5Line + W / 5; // + 60
g2.drawLine(x5Line, y5Line, x6Line, y6Line);
// -----------------------------------------
g2.setColor(new Color(255, 221, 204));
g2.fillOval(x6Line - H / 20, y6Line, H / 10,
H / 10); // -25, ...,50, 50
images.add(createImageCopy(img));
// -----------------------------------------
g2.setColor(Color.BLUE);
g2.fillOval((int) ((int) x6Line - H / 14.7),
(int) (y6Line + H / 10.41), (int) (H / 7.14),
(int) (H / 4.16)); // 34, 48, 70, 120
images.add(createImageCopy(img));
// -----------------------------------------
int x7Line = x6Line + (int) (H / 17.85); // 28
int x8Line = x7Line + (int) (H / 12.5); // 40
int y7Line = y6Line + (int) (H / 7.14); // 70
int y8Line = y7Line - (int) (H / 14.28); // 35
g2.setColor(Color.BLACK);
g2.drawLine(x7Line, y7Line, x8Line, y8Line);
images.add(createImageCopy(img));
// -----------------------------------------
int x9Line = x7Line - (int) (H / 9.43); // 53
int x10Line = x9Line - (int) (H / 14.28); // 35
int y9Line = y7Line;
int y10Line = y8Line;
g2.drawLine(x9Line, y9Line, x10Line, y10Line);
images.add(createImageCopy(img));
// -----------------------------------------
int x11Line = x7Line;
int x12Line = x8Line;
int y11Line = y7Line + (int) (H / 6.66); // 75
int y12Line = y8Line + (int) (H / 3.33); // 150
g2.drawLine(x11Line, y11Line, x12Line, y12Line);
images.add(createImageCopy(img));
// -----------------------------------------
int x13Line = x9Line;
int x14Line = x10Line;
int y13Line = y11Line;
int y14Line = y12Line;
g2.drawLine(x13Line, y13Line, x14Line, y14Line);
images.add(createImageCopy(img));
g2.dispose();
return images;
}
private static Image createImageCopy(BufferedImage img) {
int w = img.getWidth();
int h = img.getHeight();
BufferedImage img2 = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics g = img2.getGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
return img2;
}
}
So I have been trying to follow a tutorial
But it isn't working. It is a tutorial on making a sprite sheet with JFrame. I could get other things to work, but for some reason this won't. It is supposed to display a tiled image, but instead it displays a black screen.
Game.java
package ca.colescheler.game;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import javax.swing.JFrame;
import ca.colescheler.game.gfx.Screen;
import ca.colescheler.game.gfx.SpriteSheet;
#SuppressWarnings("unused")
public class Game extends Canvas implements Runnable {
/**
*
*/
private static final long serialVersionUID = 9086760045199246082L;
private BufferedImage image = new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB);
private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
public boolean running;
private static final long serialVesionUID = 1;
public static final int WIDTH = 160;
public static final int HEIGHT = WIDTH/12*9;
public static final int SCALE=3;
public static final String NAME="Game";
private JFrame frame;
int tickCount=1;
private SpriteSheet spriteSheet = new SpriteSheet("/sprite_sheet.png");
private Screen screen;
public static long getSerialvesionuid() {
return serialVesionUID;
}
public Game() {
setMinimumSize(new Dimension(WIDTH*SCALE,HEIGHT*SCALE));
setMaximumSize(new Dimension(WIDTH*SCALE,HEIGHT*SCALE));
setPreferredSize(new Dimension(WIDTH*SCALE,HEIGHT*SCALE));
frame = new JFrame(NAME);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void init() {
screen = new Screen(WIDTH,HEIGHT,new SpriteSheet("/sprite_sheet.png"));
}
public void tick() {
tickCount++;
}
long now = System.nanoTime();
public synchronized void stop() {
// TODO Auto-generated method stub
}
public synchronized void start() {
// TODO Auto-generated method stub
//new Thread(this).start();
running = true;
run();
frames = 1;
ticks = 1;
}
static int frames = 0;
static int ticks = 0;
public void run() {
long lastTime = System.nanoTime();
double nsPerTick = 1000000000d/60d;
long lastTimer = System.currentTimeMillis();
double delta=0;
while (running) {
init();
long now = System.nanoTime();
delta += (now - lastTime) / nsPerTick;
lastTime = now;
boolean shouldRender = false;
while (delta >= 1) {
ticks++;
tick();
delta -= 1;
shouldRender = true;
}
if (shouldRender) {
render();
}
if (System.currentTimeMillis() - lastTimer > 1000) {
lastTimer += 1000;
System.out.println(frames + ", " + ticks);
frames=0;
ticks=0;
}
}
}
public void render() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
this.createBufferStrategy(3);
return;
}
screen.render(pixels, 0, WIDTH);
Graphics g = bs.getDrawGraphics();
//g.drawRect(0, 0, getWidth(), getHeight());
//g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
g.dispose();
bs.show();
}
public static void main(String args[]) {
new Game().start();
}
}
SpriteSheet.java
package ca.colescheler.game.gfx;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
public class SpriteSheet {
public String path;
public int width;
public int height;
public int[] pixels;
public SpriteSheet(String path) {
BufferedImage image = null;
try {
image = ImageIO.read(SpriteSheet.class.getResourceAsStream(path));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (image == null) {
return;
}
this.path = path;
this.width = image.getWidth();
this.height = image.getHeight();
pixels = image.getRGB(0, 0, width, height, null, 0, width);
//AARRGGBB
for (int i=0; i<pixels.length;i++) {
pixels[i] = (pixels[i] & 0xff)/64;
}
for(int i=0; i<8;i++) {
System.out.println(pixels[i]);
}
//85*0
}
}
Screen.java
package ca.colescheler.game.gfx;
public class Screen {
public static final int MAP_WIDTH = 64;
public static final int MAP_WIDTH_MASK = MAP_WIDTH - 1;
public int[] tiles = new int[MAP_WIDTH * MAP_WIDTH];
public int[] colours = new int[MAP_WIDTH * MAP_WIDTH * 4];
public int xOffset = 0;
public int yOffset = 0;
public int width;
public int height;
public SpriteSheet sheet;
public Screen(int width, int height, SpriteSheet sheet) {
this.width = width;
this.height = height;
this.sheet = sheet;
for (int i=1;i<MAP_WIDTH*MAP_WIDTH;i++) {
colours[i*4+0] = 0xff00ff;
colours[i*4+1] = 0x00ffff;
colours[i*4+2] = 0xffff00;
colours[i*4+3] = 0xffffff;
}
}
public void render(int[] pixels, int offset, int row) {
for (int yTile = yOffset>>3;yTile <-(yOffset + height) >>3; yTile++) {
int yMin = yTile * 8 - yOffset;
int yMax = yMin + 8;
if (yMin < 0) yMin = 0;
if (yMax > height) yMax = height;
for (int xTile = xOffset >>3; xTile <=(xOffset+width) >>3; xTile++) {
int xMin = xTile * 8 - xOffset;
int xMax = xMin + 8;
if (xMin < 0) xMin = 0;
if (xMax > width) xMax = height;
int tileIndex = (xTile &(MAP_WIDTH_MASK)) + (yTile & (MAP_WIDTH_MASK)) * MAP_WIDTH;
for (int y = yMin;y<yMax;y++) {
int sheetPixel = ((y+yOffset) & 7) * sheet.width + ((xMin + xOffset) & 7);
int tilePixel = offset + xMin + y * row;
for (int x=xMin; x<xMax;x++) {
int colour = tileIndex * 4 + sheet.pixels[sheetPixel++];
pixels[tilePixel++]=colours[colour];
}
}
}
}
}}
Link to tutorial
In the file Screen.java, there is a typo. You should change height to width in the following line:
if (xMax > width) xMax = height;
I have a small problem with the layout diagonalLayout proposed on the site of oracle ...
In fact I would just stretch the last button on the width of my screen while keeping the layout and I can not, but I've tried this code:
public void stretchLastComponent(Container container){
int nComps = container.getComponentCount();
Component c = container.getComponent(nComps-1);
c.setSize(container.getWidth(), c.getHeight());
I also use repaint () and revalidate (), but without result.
Here is the class used (it was an imposed job I can not change the layout):
DiagonalLayout.java
And I also supplied in code for simplicity in the forum:
package layout;
/*
* 1.2+ version. Used by CustomLayoutDemo.java.
*/
import java.awt.*;
public class DiagonalLayout implements LayoutManager {
private int vgap;
private int minWidth = 0, minHeight = 0;
private int preferredWidth = 0, preferredHeight = 0;
private boolean sizeUnknown = true;
public DiagonalLayout() {
this(5);
}
public DiagonalLayout(int v) {
vgap = v;
}
/* Required by LayoutManager. */
public void addLayoutComponent(String name, Component comp) {
}
/* Required by LayoutManager. */
public void removeLayoutComponent(Component comp) {
}
private void setSizes(Container parent) {
int nComps = parent.getComponentCount();
Dimension d = null;
//Reset preferred/minimum width and height.
preferredWidth = 0;
preferredHeight = 0;
minWidth = 0;
minHeight = 0;
for (int i = 0; i < nComps; i++) {
Component c = parent.getComponent(i);
if (c.isVisible()) {
d = c.getPreferredSize();
if (i > 0) {
preferredWidth += d.width/2;
preferredHeight += vgap;
} else {
preferredWidth = d.width;
}
preferredHeight += d.height;
minWidth = Math.max(c.getMinimumSize().width,
minWidth);
minHeight = preferredHeight;
}
}
}
/* Required by LayoutManager. */
public Dimension preferredLayoutSize(Container parent) {
Dimension dim = new Dimension(0, 0);
int nComps = parent.getComponentCount();
setSizes(parent);
//Always add the container's insets!
Insets insets = parent.getInsets();
dim.width = preferredWidth
+ insets.left + insets.right;
dim.height = preferredHeight
+ insets.top + insets.bottom;
sizeUnknown = false;
return dim;
}
/* Required by LayoutManager. */
public Dimension minimumLayoutSize(Container parent) {
Dimension dim = new Dimension(0, 0);
int nComps = parent.getComponentCount();
//Always add the container's insets!
Insets insets = parent.getInsets();
dim.width = minWidth
+ insets.left + insets.right;
dim.height = minHeight
+ insets.top + insets.bottom;
sizeUnknown = false;
return dim;
}
/* Required by LayoutManager. */
/*
* This is called when the panel is first displayed,
* and every time its size changes.
* Note: You CAN'T assume preferredLayoutSize or
* minimumLayoutSize will be called -- in the case
* of applets, at least, they probably won't be.
*/
public void layoutContainer(Container parent) {
Insets insets = parent.getInsets();
int maxWidth = parent.getWidth()
- (insets.left + insets.right);
int maxHeight = parent.getHeight()
- (insets.top + insets.bottom);
int nComps = parent.getComponentCount();
int previousWidth = 0, previousHeight = 0;
int x = 0, y = insets.top;
int rowh = 0, start = 0;
int xFudge = 0, yFudge = 0;
boolean oneColumn = false;
// Go through the components' sizes, if neither
// preferredLayoutSize nor minimumLayoutSize has
// been called.
if (sizeUnknown) {
setSizes(parent);
}
if (maxWidth <= minWidth) {
oneColumn = true;
}
if (maxWidth != preferredWidth) {
xFudge = (maxWidth - preferredWidth)/(nComps - 1);
}
if (maxHeight > preferredHeight) {
yFudge = (maxHeight - preferredHeight)/(nComps - 1);
}
for (int i = 0 ; i < nComps ; i++) {
Component c = parent.getComponent(i);
if (c.isVisible()) {
Dimension d = c.getPreferredSize();
// increase x and y, if appropriate
if (i > 0) {
if (!oneColumn) {
x += previousWidth/2 + xFudge;
}
y += previousHeight + vgap + yFudge;
}
// If x is too large,
if ((!oneColumn) &&
(x + d.width) >
(parent.getWidth() - insets.right)) {
// reduce x to a reasonable number.
x = parent.getWidth()
- insets.bottom - d.width;
}
// If y is too large,
if ((y + d.height)
> (parent.getHeight() - insets.bottom)) {
// do nothing.
// Another choice would be to do what we do to x.
}
// Set the component's size and position.
c.setBounds(x, y, d.width, d.height);
previousWidth = d.width;
previousHeight = d.height;
}
}
}
public String toString() {
String str = "";
return getClass().getName() + "[vgap=" + vgap + str + "]";
}
}
Thank you in advance.
You can't/shouldn't change the size/position of any component which under the control of a layout manager, the next time the container is validated (laid out) those values will be rest by the layout manager...
Now having said that, since you have access to the source code of the layout manager, you have the ability to effect how it makes it's decisions...
By simply adding this into the layoutContainer method, right before c.setBounds(x, y, d.width, d.height);
if (i == nComps - 1) {
d.width = parent.getWidth();
x = 0;
}
I was able to achieve this...
UPDATED after feedback
I've fudged the layout code a little to allow the layout to perform the way you image suggest...
public class TestLayout14 {
public static void main(String[] args) {
new TestLayout14();
}
public TestLayout14() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JPanel content = new JPanel(new BorderLayout());
LayoutPane layoutPane = new LayoutPane();
content.add(layoutPane);
content.add(new ControlPane(layoutPane), BorderLayout.SOUTH);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(content);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class LayoutPane extends JPanel {
public LayoutPane() {
setLayout(new DiagonalLayout());
add(new JLabel("Test 01"));
add(new JLabel("Test 02"));
add(new JLabel("Test 03"));
add(new JButton("Test 04"));
}
}
public class ControlPane extends JPanel {
private JTextField fieldGap;
private JCheckBox majorDiag;
private JCheckBox streatchLast;
private LayoutPane layoutPane;
public ControlPane(LayoutPane pane) {
layoutPane = pane;
setBorder(new CompoundBorder(new EmptyBorder(4, 0, 0, 0), new MatteBorder(1, 0, 0, 0, Color.GRAY)));
fieldGap = new JTextField(Integer.toString(((DiagonalLayout)layoutPane.getLayout()).getVgap()), 4);
majorDiag = new JCheckBox("Major Diagnal");
streatchLast = new JCheckBox("Last Component Stretched");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 4, 4, 4);
gbc.anchor = GridBagConstraints.WEST;
gbc.gridx = 0;
gbc.gridy = 0;
add(new JLabel("Diagnal Gap: "), gbc);
gbc.gridx++;
add(fieldGap, gbc);
gbc.gridx = 0;
gbc.gridy++;
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(majorDiag, gbc);
gbc.gridy++;
add(streatchLast, gbc);
fieldGap.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
((DiagonalLayout) layoutPane.getLayout()).setVgap(Integer.parseInt(fieldGap.getText()));
layoutPane.invalidate();
layoutPane.revalidate();
} catch (Exception exp) {
exp.printStackTrace();
}
}
});
streatchLast.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
((DiagonalLayout) layoutPane.getLayout()).setStreatchLast(streatchLast.isSelected());
layoutPane.invalidate();
layoutPane.revalidate();
}
});
}
}
public class DiagonalLayout implements LayoutManager {
private int vgap;
private int minWidth = 0, minHeight = 0;
private int preferredWidth = 0, preferredHeight = 0;
private boolean sizeUnknown = true;
private boolean streatchLast = false;
public DiagonalLayout() {
this(5);
}
public DiagonalLayout(int v) {
vgap = v;
}
public void setVgap(int vgap) {
this.vgap = vgap;
}
public int getVgap() {
return vgap;
}
public void setStreatchLast(boolean streatchLast) {
this.streatchLast = streatchLast;
}
public boolean isStreatchLast() {
return streatchLast;
}
/* Required by LayoutManager. */
public void addLayoutComponent(String name, Component comp) {
}
/* Required by LayoutManager. */
public void removeLayoutComponent(Component comp) {
}
private void setSizes(Container parent) {
int nComps = parent.getComponentCount();
Dimension d = null;
//Reset preferred/minimum width and height.
preferredWidth = 0;
preferredHeight = 0;
minWidth = 0;
minHeight = 0;
for (int i = 0; i < nComps; i++) {
Component c = parent.getComponent(i);
if (c.isVisible()) {
d = c.getPreferredSize();
if (i > 0) {
preferredWidth += d.width / 2;
preferredHeight += vgap;
} else {
preferredWidth = d.width;
}
preferredHeight += d.height;
minWidth = Math.max(c.getMinimumSize().width,
minWidth);
minHeight = preferredHeight;
}
}
}
/* Required by LayoutManager. */
public Dimension preferredLayoutSize(Container parent) {
Dimension dim = new Dimension(0, 0);
int nComps = parent.getComponentCount();
setSizes(parent);
//Always add the container's insets!
Insets insets = parent.getInsets();
dim.width = preferredWidth
+ insets.left + insets.right;
dim.height = preferredHeight
+ insets.top + insets.bottom;
sizeUnknown = false;
return dim;
}
/* Required by LayoutManager. */
public Dimension minimumLayoutSize(Container parent) {
Dimension dim = new Dimension(0, 0);
int nComps = parent.getComponentCount();
//Always add the container's insets!
Insets insets = parent.getInsets();
dim.width = minWidth
+ insets.left + insets.right;
dim.height = minHeight
+ insets.top + insets.bottom;
sizeUnknown = false;
return dim;
}
/* Required by LayoutManager. */
/*
* This is called when the panel is first displayed,
* and every time its size changes.
* Note: You CAN'T assume preferredLayoutSize or
* minimumLayoutSize will be called -- in the case
* of applets, at least, they probably won't be.
*/
public void layoutContainer(Container parent) {
Insets insets = parent.getInsets();
int maxWidth = parent.getWidth()
- (insets.left + insets.right);
int maxHeight = parent.getHeight()
- (insets.top + insets.bottom);
int nComps = parent.getComponentCount();
int previousWidth = 0, previousHeight = 0;
int x = 0, y = insets.top;
int rowh = 0, start = 0;
int xFudge = 0, yFudge = 0;
boolean oneColumn = false;
// Go through the components' sizes, if neither
// preferredLayoutSize nor minimumLayoutSize has
// been called.
if (sizeUnknown) {
setSizes(parent);
}
if (maxWidth <= minWidth) {
oneColumn = true;
}
// if (maxWidth != preferredWidth) {
// xFudge = (maxWidth - preferredWidth) / (nComps - 1);
// }
//
// if (maxHeight > preferredHeight) {
// yFudge = (maxHeight - preferredHeight) / (nComps - 1);
// }
for (int i = 0; i < nComps; i++) {
Component c = parent.getComponent(i);
if (c.isVisible()) {
Dimension d = c.getPreferredSize();
// increase x and y, if appropriate
if (i > 0) {
if (!oneColumn) {
x += previousWidth / 2 + xFudge;
}
y += previousHeight + vgap + yFudge;
}
// If x is too large,
if ((!oneColumn)
&& (x + d.width)
> (parent.getWidth() - insets.right)) {
// reduce x to a reasonable number.
x = parent.getWidth()
- insets.bottom - d.width;
}
// If y is too large,
if ((y + d.height)
> (parent.getHeight() - insets.bottom)) {
// do nothing.
// Another choice would be to do what we do to x.
}
if (isStreatchLast() && i == nComps - 1) {
d.width = parent.getWidth() - x;
}
// Set the component's size and position.
c.setBounds(x, y, d.width, d.height);
previousWidth = d.width;
previousHeight = d.height;
}
}
}
public String toString() {
String str = "";
return getClass().getName() + "[vgap=" + vgap + str + "]";
}
}
}
I created a class that draws a ball on a screen and my goal is to move it with the keys, but the ball stays in one spot. the coordinates of the ball change according to the key presses but not the actual ball itself
import java.applet.Applet;
import java.awt.Color;
import java.awt.Component;
import java.awt.Event;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
public class game extends Applet implements Runnable
{
static final int WIDTH = 450;
static final int HEIGHT = 450;
private Image dbImage;
private Graphics dbg;
public static long NEW_DOT_FREQ = TimeUnit.SECONDS.toMillis(3);
public long lastUpdateTime;
public long timeSinceLastNewDot;
public ArrayList<Ball> BALLS;
Color[] color = {Color.red, Color.blue, Color.green, Color.yellow, Color.magenta, Color.black};
int colorIndex;
static final int NUM_OF_BALLS = 4;
int i;
int t;
MainBall mainBall = new MainBall(100, 100, 10, 10, 100, 100, 0, 0);
Thread updateTime = new updateTime();
public void start()
{
lastUpdateTime = System.currentTimeMillis();
Thread th = new Thread(this);
th.start();//start main game
updateTime.start();
}
public void updateGame()
{
//Get the current time
long currentTime = System.currentTimeMillis();
//Calculate how much time has passed since the last update
long elapsedTime = currentTime - lastUpdateTime;
//Store this as the most recent update time
lastUpdateTime = currentTime;
//Create a new dot if enough time has passed
//Update the time since last new dot was drawn
timeSinceLastNewDot += elapsedTime;
if (timeSinceLastNewDot >= NEW_DOT_FREQ)
{
int newX = randomNumber();
int newY = randomNumber();
debugPrint("New dot created at x:" + newX + ", y:" + newY + ".");
BALLS.add(new Ball(newX, newY, 20, 20));
timeSinceLastNewDot = 0;
}
}
private void debugPrint(String value)
{
System.out.println(value);
}
public class updateTime extends Thread implements Runnable
{
public void run()
{
for(t = 0; ; t++)
{
try
{
Thread.sleep(1000);
}
catch(InterruptedException e){}
}
}
}
public int randomNumber()
{
return (int)(Math.random() * 400);
}
public int getRandomColor()
{
return (int)(Math.random() * 6);
}
public class MainBall
{
int x;
int y;
int width;
int height;
int xpos = 100;
int ypos = 100;
int xspeed = 0;
int yspeed = 0;
public MainBall(int x, int y, int width, int height, int xpos, int ypos, int xspeed, int yspeed)
{
this.x = 100;
this.y = 100;
this.width = 10;
this.height = 10;
this.xpos = 100;
this.ypos = 100;
this.xspeed = 0;
this.yspeed = 0;
}
public void paintMainBall(Graphics g)
{
g.setColor(Color.black);
g.fillOval(x, y, width, height);
g.drawString(xpos + ", " + ypos, 20, 40);
}
}//mainBall
class Ball
{
int x;
int y;
int width;
int height;
public Ball(int x, int y, int width, int height)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}//end ball
public void paint(Graphics g)
{
g.setColor(color[getRandomColor()]);
g.fillOval(x, y, width, height);
}//end paint
}//ball class
public void update(Graphics g)//double buffer don't touch!!
{
if(dbImage == null)
{
dbImage = createImage(this.getSize().width, this.getSize().height);
dbg = dbImage.getGraphics();
}
dbg.setColor(getBackground());
dbg.fillRect(0, 0, this.getSize().width, this.getSize().height);
dbg.setColor(getForeground());
paint(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public boolean keyDown (Event e, int key)
{
if(key == Event.LEFT)
{
mainBall.xspeed = -5;
mainBall.yspeed = 0;
}
if(key == Event.RIGHT)
{
mainBall.xspeed = 5;
mainBall.yspeed = 0;
}
if(key == Event.UP)
{
mainBall.yspeed = -5;
mainBall.xspeed = 0;
}
if(key == Event.DOWN)
{
mainBall.yspeed = 5;
mainBall.xspeed = 0;
}
return true;
}
public void run()
{
while(true)
{
repaint();
if (mainBall.xpos < 1)
{
mainBall.xpos = 449;
}
if (mainBall.xpos > 449)
{
mainBall.xpos = 1;
}
if (mainBall.ypos < 1)
{
mainBall.ypos = 449;
}
if (mainBall.ypos > 449)
{
mainBall.ypos = 1;
}
mainBall.ypos += mainBall.yspeed;
mainBall.xpos += mainBall.xspeed;
try
{
Thread.sleep(20);
}
catch(InterruptedException ex){}
}
}
public void init()
{
this.setSize(WIDTH, HEIGHT);
BALLS = new ArrayList<Ball>();
}
public void paint(Graphics g)
{
g.drawString("time: " + t, 20, 20);
mainBall.paintMainBall(g);
for (Ball ball : BALLS)
{
ball.paint(g);
}
updateGame();
}
}
You update the xPos/yPos values of the ball, but never the x/y values
public void paintMainBall(Graphics g) {
System.out.println("PaintMainBall");
g.setColor(Color.RED);
g.fillOval(x, y, width, height);
g.drawString(xpos + ", " + ypos, 20, 40);
}
I need to draw a curve, knowing that I receive points every x milliseconds or x seconds, and that the curve is moving to the left by one pixel each time I receive a new point. I'm using the Bezier algorithm to draw the curve from the points I receive, so I need at least three points to start. I would like to know how to proceed to draw the curve bit by bit on an image.
This is what I'm doing right now:
int xPos = 0;
Point2D.Double[] points = new Point2D.Double[listYpos.size()];
for (int i = 0; i < listYpos.size(); i++) {
points[i] = new Point2D.Double(i, listYpos.get(i));
}
if (curveImg == null) {
curveImg = gc.createCompatibleImage(imageWidth, imageHeight, Transparency.BITMASK);
}
if (points.length > 3) {
Graphics2D gImg = (Graphics2D) curveImg.getGraphics();
renderCurve(gImg, Arrays.copyOfRange(points, listYpos.size() - 4, listYpos.size() - 1));
gImg.dispose();
}
AffineTransform at = g.getTransform();
at.scale(-1, 1);
at.translate(-xPos++, listYpos.get(listYpos.size() - 1));
g.drawImage(curveImg, at, null);
This method is called each time a new point is received every x milliseconds or x seconds.
I think that gImg.dispose();
maybe this code can help you with that (from old.forums.sun.com)
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
import javax.swing.*;
public class BezierTest {
private class Animator implements ActionListener {
private double distance = 0;
private boolean moveTo = true;
private ArrayList<Point2D> points = new ArrayList<Point2D>();
private double step = -1;
private double steps;
private Timer timer = new Timer(0, this);
#Override
public void actionPerformed(ActionEvent e) {
step++;
if (step <= steps) {
double t = step / steps;
Point2D newPoint = computeBezierPoint(new Point2D.Double(), t, curvePoints);
marks[marks.length - 1].setFrame(newPoint.getX() - 5, newPoint.getY() - 5, 10, 10);
points.add(newPoint);
if (moveTo) {
path.moveTo(newPoint.getX(), newPoint.getY());
moveTo = false;
} else {
path.lineTo(newPoint.getX(), newPoint.getY());
}
lines[3] = new Line2D.Double(computePointOnLine(lines[0], t), computePointOnLine(lines[1], t));
lines[4] = new Line2D.Double(computePointOnLine(lines[1], t), computePointOnLine(lines[2], t));
lines[5] = new Line2D.Double(computePointOnLine(lines[3], t), computePointOnLine(lines[4], t));
// The maximum distance encountered between the results of two calculation methods.
// newPoint from computeBezierPoint() the other via the lines method
distance = Math.max(distance, newPoint.distance(computePointOnLine(lines[5], t)));
demoComponent.repaint();
} else {
timer.stop();
animationButton.setEnabled(true);
if (distance > 0d) {
System.out.println("Maximum difference " + distance);
}
}
}
public void init() {
timer.stop();
animationButton.setEnabled(false);
steps = sliderStep.getValue();
step = -1;
distance = 0;
moveTo = true;
path = new Path2D.Double();
int sleepTime = (int) Math.round(1000d * sliderDuration.getValue() / steps);
timer.setDelay(sleepTime);
timer.setInitialDelay(0);
timer.start();
}
private Point2D computeBezierPoint(Point2D rv, double t,
Point2D... curve) {
if (rv == null) {
rv = new Point2D.Double();
} else {
rv.setLocation(0, 0);
}
int n = curve.length - 1;
double oneMinusT = 1.0 - t;
for (int index = 0; index < curve.length; index++) {
double multiplier = index == 0 || index == n ? 1 : StrictMath.min(n - index, index) * n;
multiplier *= StrictMath.pow(t, index) * StrictMath.pow(oneMinusT, n - index);
rv.setLocation(rv.getX() + multiplier * curve[index].getX(), rv.getY() + multiplier * curve[index].getY());
}
return rv;
}
private Point2D computePointOnLine(Line2D line, double t) {
return new Point2D.Double((line.getX2() - line.getX1()) * t + line.getX1(), (line.getY2() - line.getY1()) * t + line.getY1());
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new BezierTest().createGUI();
}
});
}
private final JButton animationButton = new JButton(new AbstractAction("Start animation") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
animator.init();
}
});
private final Animator animator = new Animator();
private Point2D[] curvePoints = new Point2D[]{new Point(10, 50), new Point(190, 10), new Point(190, 190), new Point(10, 150)};
private JComponent demoComponent = new JComponent() {
private static final long serialVersionUID = 1L;
{
setPreferredSize(new Dimension(400, 400));
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
int w = getWidth();
int h = getHeight();
recalculateAfterResize(w, h);
}
});
}
#Override
protected void paintComponent(Graphics g) {
if (isVisible()) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
paintBezier(g);
}
}
};
private Line2D[] lines = new Line2D[6];
private final Ellipse2D[] marks;
private Path2D path;
private final JSlider sliderDuration = createSlider(1, 20, 2, "Duration in seconds", 9, 1);
private final JSlider sliderStep = createSlider(8, 128, 64, "Animation steps", 16, 1);
private Path2D totalCurve;
{
marks = new Ellipse2D[curvePoints.length + 1];
for (int index = 0; index < marks.length; index++) {
marks[index] = new Ellipse2D.Double();
}
}
private void createGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(demoComponent, BorderLayout.CENTER);
JToolBar toolBar = new JToolBar();
toolBar.add(animationButton);
toolBar.add(sliderStep);
toolBar.add(sliderDuration);
frame.add(toolBar, BorderLayout.PAGE_START);
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
}
private JSlider createSlider(int min, int max, int value, String title, int major, int minor) {
JSlider slider = new JSlider(min, max, value);
slider.setBorder(BorderFactory.createTitledBorder(title));
slider.setMajorTickSpacing(major);
// slider.setMinorTickSpacing(minor);
slider.setPaintLabels(true);
slider.setPaintTicks(true);
return slider;
}
private void paintBezier(Graphics g) {
Path2D path1 = this.path;
if (path1 != null) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.GREEN);
for (Shape mark : marks) {
g2.fill(mark);
}
g2.setStroke(new BasicStroke(2f));
g2.setColor(Color.BLACK);
for (Shape mark : marks) {
g2.draw(mark);
}
g2.setStroke(new BasicStroke(0f));
g2.draw(totalCurve);
g2.setStroke(new BasicStroke(1f));
g2.setColor(Color.RED);
g2.draw(path1);
g2.setStroke(new BasicStroke(.5f));
g2.setColor(Color.BLACK);
for (Line2D line : lines) {
if (line != null) {
g2.draw(line);
}
}
}
}
private void recalculateAfterResize(int w, int h) {
curvePoints = new Point2D[]{new Point2D.Double(10, h / 4.0), new Point2D.Double(w - 10, 10), new Point2D.Double(w - 10, h - 10), new Point2D.Double(10, h - h / 4.0)};
totalCurve = new Path2D.Double();
totalCurve.moveTo(curvePoints[0].getX(), curvePoints[0].getY());
totalCurve.curveTo(curvePoints[1].getX(), curvePoints[1].getY(), curvePoints[2].getX(), curvePoints[2].getY(), curvePoints[3].getX(), curvePoints[3].getY());
for (int index = 0; index < curvePoints.length; index++) {
marks[index].setFrame(curvePoints[index].getX() - 5, curvePoints[index].getY() - 5, 10, 10);
}
marks[marks.length - 1].setFrame(marks[0].getFrame());
for (int index = 0; index < curvePoints.length - 1; index++) {
lines[index] = new Line2D.Double(curvePoints[index], curvePoints[index + 1]);
}
lines[3] = null;
lines[4] = null;
lines[5] = null;
animator.init();
}
}