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();
}
}
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;
}
}
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.
I'm working on a Java program that displays a map (inherited from JComponent) within a JScrollPane. When the MouseWheelListener fires, the map zooms and the JScrollPane's viewport is adjusted to center on the location of the mouse.
This all works fine, except that the call to setSize(Dimension d) forces the map to repaint immediately before the view is adjusted, causing a "stutter." However, I cannot adjust the view until after setSize has completed execution or the calculations for "centering" the viewport will be haywire (due to getHeight() and getWidth() calls,) therefore the viewport adjustment is within a runnable called with invokeLater.
I would like to find a way to move directly from the previous map size and viewport location to the new view, without seeing the scene repainted twice.
setIgnoreRepaint(boolean) did not work for me. Is there another way to go about this?
EDIT: Here's what I worked up from your sample code that replicates my issue, although not as noticably as there's far less computation going on in the drawing. If you scroll rapidly over the image, you'll see that there's a brief stutter between the resizing of the hexagons to their new size and the adjustment of the viewport to its new position.
You can see the hexagons being re-drawn twice. (Once when the setSize() method is called and once when the setViewPosition() method is called.)
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class ZoomWithSelectionInViewport implements MouseWheelListener{
private int zoom = 80;
JComponent b;
int hexSize = 3;
public ZoomWithSelectionInViewport() throws Exception{
b = new JComponent() {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(700, 700);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = ((Graphics2D) g);
int vertOffsetX, vertOffsetY, horizOffsetX, horizOffsetY;
vertOffsetX = (int)((double)hexSize* Math.sqrt(3.0f));
vertOffsetY = (int)((double)-hexSize-1* Math.sqrt(3.0f)/2.0f);
horizOffsetX = (int) ((double)hexSize* Math.sqrt(3.0f));
horizOffsetY = (int) ((double)hexSize+1* Math.sqrt(3.0f)/2.0f);
for(int x = 0; x < 50; x++)
{
for(int y = 0; y < 50; y++)
{
int[] xcoords = new int[6]; int[] ycoords = new int[6];
for(int i = 0; i < 6; i++)
{
xcoords[i] = (int)((hexSize+x * horizOffsetX + y * vertOffsetX) + (double)hexSize * Math.cos(i * 2 * Math.PI / 6));
ycoords[i] = (int)(((getSize().height /2 )+ x * horizOffsetY + y * vertOffsetY) + (double)hexSize * Math.sin(i * 2 * Math.PI / 6));
}
g2d.setStroke(new BasicStroke(hexSize/2.5f));
g2d.setColor(Color.GRAY);
g2d.drawPolygon(xcoords, ycoords, 6);
}
}
}
};
JScrollPane view = new JScrollPane(b);
b.addMouseWheelListener(this);
JFrame f = new JFrame();
f.setLocation(10, 10);
f.setDefaultCloseOperation(3);
f.add(view);
f.setSize(500,500);
f.setVisible(true);
view.setWheelScrollingEnabled(false);
}
public void mouseWheelMoved(MouseWheelEvent e) {
zoom = 100*-Integer.signum(e.getWheelRotation());
if(hexSize - Integer.signum(e.getWheelRotation()) > 0)
hexSize-= Integer.signum(e.getWheelRotation());
Dimension targetSize = new Dimension(b.getWidth()+zoom,b.getHeight()+zoom);
b.setPreferredSize(targetSize);
b.setSize(targetSize);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JViewport tempView = (JViewport)b.getParent();
tempView.setViewPosition(new Point(b.getWidth()/2,b.getHeight()/2));
}
});
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
ZoomWithSelectionInViewport example = new ZoomWithSelectionInViewport();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
my curiosity, no idea what's happends, could you please use this SSCCE add there your issues and edit with the code your question
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class ZoomWithSelectionInViewport {
private Point startPoint = new Point(0, 0);
private Point rectLocale = new Point();
private Dimension rectSize = new Dimension();
private int zoom = 80;
private BufferedImage capture = null;
private BufferedImage raw;
public ZoomWithSelectionInViewport() throws Exception {
raw = new Robot().createScreenCapture(new Rectangle(
Toolkit.getDefaultToolkit().getScreenSize()));
MouseBehavior behavior = new MouseBehavior();
JPanel b = new JPanel() {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(500, 500);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = ((Graphics2D) g);
g2d.drawImage(raw, 0, 0, null);
if (capture != null) {
int width2 = (int) (rectSize.width + rectSize.width * (zoom / 500d));
int height2 = (int) (rectSize.height + rectSize.height * (zoom / 500d));
int x2 = rectLocale.x - ((width2 - rectSize.width) / 2);
int y2 = rectLocale.y - ((height2 - rectSize.height) / 2);
Image scaledInstance = capture.getScaledInstance(
width2, height2, Image.SCALE_AREA_AVERAGING);
g2d.drawImage(scaledInstance, x2, y2, null);
g2d.drawRect(x2, y2, width2, height2);
} else {
g2d.draw(new Rectangle(rectLocale, rectSize));
}
}
};
b.addMouseMotionListener(behavior);
b.addMouseListener(behavior);
b.addMouseWheelListener(behavior);
JFrame f = new JFrame();
f.setLocation(10, 10);
f.setDefaultCloseOperation(3);
f.add(b);
f.pack();
f.setVisible(true);
}
private class MouseBehavior extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
startPoint = e.getPoint();
rectLocale = new Point();
rectSize = new Dimension();
capture = null;
if (e.getSource() instanceof JComponent) {
((JComponent) e.getSource()).repaint();
}
}
#Override
public void mouseDragged(MouseEvent e) {
Point currentPoint = e.getPoint();
rectSize.width = Math.abs(currentPoint.x - startPoint.x);
rectSize.height = Math.abs(currentPoint.y - startPoint.y);
if (e.isShiftDown()) {
rectSize.width = rectSize.height = Math.min(rectSize.width, rectSize.height);
int dx = startPoint.x - rectSize.width;
int dy = startPoint.y - rectSize.height;
rectLocale.x = startPoint.x < currentPoint.x ? startPoint.x : Math.max(dx, dy);
rectLocale.y = startPoint.y < currentPoint.y ? startPoint.y : Math.min(dx, dy);
} else {
rectLocale.x = Math.min(currentPoint.x, startPoint.x);
rectLocale.y = Math.min(currentPoint.y, startPoint.y);
}
if (e.getSource() instanceof JComponent) {
((JComponent) e.getSource()).repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (rectSize.width <= 0 || rectSize.height <= 0) {
capture = null;
} else {
capture = raw.getSubimage(Math.max(0, rectLocale.x),
Math.max(0, rectLocale.y), rectSize.width, rectSize.height);
}
if (e.getSource() instanceof JComponent) {
((JComponent) e.getSource()).repaint();
}
}
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
zoom = Math.min(2000, Math.max(0, zoom + e.getUnitsToScroll() * 10));
if (e.getSource() instanceof JComponent) {
((JComponent) e.getSource()).repaint();
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
ZoomWithSelectionInViewport example = new ZoomWithSelectionInViewport();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
an alternative could be
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
public class ZoomDemo {
private PaintSurface canvas = new PaintSurface();
private JFrame frame = new JFrame();
private AffineTransform aT = new AffineTransform();
private Point2D p1 = null;
private Point2D p2 = null;
public ZoomDemo() {
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
ScaleListener scaleListener = new ScaleListener();
canvas.addMouseWheelListener(scaleListener);
canvas.addMouseListener(scaleListener);
frame.add(canvas);
frame.setVisible(true);
}
public class ScaleListener extends MouseAdapter {
private double scale = 1;
#Override
public void mouseClicked(MouseEvent e) {
p1 = e.getPoint();
try {
p2 = aT.inverseTransform(p1, new Point2D.Double());
/*
* p1 is the point relative to canvas where the user physically
* held the mouse.
*
* Since you may want to deal with a virtual mouse location
* relative to an untransformed canvas, you inverse transform p1
* to p2.
*
* For example: when the user held the mouse over, let's say,
* the displayed left upper corner of the red rectangle.
*
* p2 now will point to the upper left corner of the red
* rectangle in an untransformed canvas.
*/
applyScale();
} catch (NoninvertibleTransformException e1) {
e1.printStackTrace();
}
canvas.repaint();
}
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (p1 != null && p2 != null) {
scale -= (0.05 * e.getWheelRotation());
if (scale > 5) {
scale = 5;
}
if (scale < 1) {
scale = 1;
aT.setToIdentity();
} else {
applyScale();
}
canvas.repaint();
}
}
private void applyScale() {
aT.setToIdentity();
// *** variation one (your implementation)
aT.translate(p1.getX(), p1.getY());
aT.scale(scale, scale);
aT.translate(-p2.getX(), -p2.getY());
// *** variation two
// aT.translate(p1.getX(), p1.getY());
// aT.scale(scale, scale);
// aT.translate(-p1.getX(), -p1.getY());
// *** variation three
// aT.translate(p2.getX(), p2.getY());
// aT.scale(scale, scale);
// aT.translate(-p2.getX(), -p2.getY());
}
}
public class PaintSurface extends JComponent {
private static final long serialVersionUID = 1L;
{
this.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
}
/*
* Override paintComponent, not paint!!!
*/
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
try {
g2.setColor(Color.black);
g2.fillRect(0, 0, getWidth(), getHeight());
// g2.setTransform(aT); <<<<<<<<< !!!!!!!
/*
* A transform (translation for example) may already have been
* applied to the Graphics object by a parent. This is removed
* by setTransform.
*/
g2.transform(aT); // <<<<<<<<<< !!!!!!!
g2.setColor(Color.red);
g2.drawRect(50, 50, 100, 100);
g2.setColor(Color.blue);
g2.drawRect(200, 200, 150, 50);
if (p2 != null) {
g2.setColor(Color.green);
g2.fill(new Rectangle2D.Double(p2.getX() - 4, p2.getY() - 4, 8, 8));
}
} finally {
g2.dispose();
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ZoomDemo zoomDemo = new ZoomDemo();
}
});
}
}
same question,
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
//http://stackoverflow.com/questions/6819243/jscrollpane-jumping-when-scrollbars-start-being-used
public class LockViewPortToPoint extends JFrame {
private static final long serialVersionUID = 1L;
public static void main(String[] arg) {
LockViewPortToPoint lockViewPortToPoint = new LockViewPortToPoint();
}
public LockViewPortToPoint() {
initComponents();
setVisible(true);
}
private void initComponents() {
setLayout(new BorderLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(600, 600);
setPreferredSize(new Dimension(600, 600));
add(new TopPanel());
}
private class TopPanel extends JPanel {
private static final long serialVersionUID = 1L;
private JScrollPane scrollPane;
TopPanel() {
setPreferredSize(new Dimension(500, 500));
scrollPane = new JScrollPane(new InteriorPanel());
scrollPane.setPreferredSize(new Dimension(500, 500));
scrollPane.getVerticalScrollBar().setPreferredSize(new Dimension(10, 490));
scrollPane.getHorizontalScrollBar().setPreferredSize(new Dimension(490, 10));
scrollPane.setWheelScrollingEnabled(false);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
add(scrollPane);
}
}
private class InteriorPanel extends JPanel {
private static final long serialVersionUID = 1L;
private double scale = 10.0;
private final double scaleModifier = 0.1;
private final int width = 10;
private Point loc = new Point(0, 0);
private final int SIZE = 10;
private Point orig = new Point(250, 250);
InteriorPanel() {
super(true);
setPreferredSize(new Dimension((int) (scale * width * SIZE), (int) (scale * width * SIZE)));
this.addMouseWheelListener(new MapMouseWheelListener());
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2D.scale(scale, scale);
for (int row = 0; row <= SIZE; row++) {
for (int col = 0; col < SIZE; col++) {
if ((col + row) % 2 == 0) {
g2D.setColor(Color.white);
} else {
g2D.setColor(Color.black);
}
g2D.fillRect(col * width, row * width, width, width);
}
}
}
private void incrementScale(int notches) {
double modifier = 0;
final double prevScale = scale;
if (notches != 0) {
modifier = 1.0 + -notches / Math.abs(notches) * scaleModifier;
}
scale *= Math.pow(modifier, Math.abs(notches));
/*if (scale * width < 1) {
scale = 1.0/width;
} else if (scale * width * 3 > parentHeight || scale * width * 3 > parentWidth) {
if (parentHeight > parentWidth) {
scale = parentWidth / 3.0 / width;
} else {
scale = parentHeight / 3.0 / width;
}
} else if (scale * width * SIZE < parentWidth) {
scale = parentWidth / (double)SIZE / width;
} else if (scale * width * SIZE < parentHeight) {
scale = parentHeight / (double)SIZE / width;
}*/
setPreferredSize(new Dimension((int) (scale * width * SIZE), (int) (scale * width * SIZE)));
orig = new Point(((int) (scale * width * SIZE)) / 2, ((int) (scale * width * SIZE) / 2));
final JViewport viewport = ((JViewport) (getParent().getParent().getComponent(0)));
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
viewport.setViewPosition(new Point(
orig.x - (int) Math.round(loc.x * (1 - scale / prevScale)),
orig.y - (int) Math.round(loc.y * (1 - scale / prevScale))));
}
});
/*viewport.scrollRectToVisible(new Rectangle(new Point(
orig.x - (int) Math.round(loc.x * (1 - scale / prevScale)),
orig.y - (int) Math.round(loc.y * (1 - scale / prevScale))))); */
System.out.println(orig + "\n " + loc + "\n " + (1 - scale / prevScale));
revalidate();
repaint();
}
private class MapMouseWheelListener implements MouseWheelListener {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
loc = e.getPoint();
incrementScale(e.getWheelRotation());
}
}
}
}
another example
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
//http://stackoverflow.com/questions/115103/how-do-you-implement-position-sensitive-zooming-inside-a-jscrollpane
public class FPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private Dimension preferredSize = new Dimension(400, 400);
private Rectangle2D[] rects = new Rectangle2D[50];
public static void main(String[] args) {
JFrame jf = new JFrame("test");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setSize(400, 400);
jf.add(new JScrollPane(new FPanel()));
jf.setVisible(true);
}
public FPanel() {
// generate rectangles with pseudo-random coords
for (int i = 0; i < rects.length; i++) {
rects[i] = new Rectangle2D.Double(
Math.random() * .8, Math.random() * .8,
Math.random() * .2, Math.random() * .2);
}
// mouse listener to detect scrollwheel events
addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
updatePreferredSize(e.getWheelRotation(), e.getPoint());
}
});
}
private void updatePreferredSize(int wheelRotation, Point stablePoint) {
double scaleFactor = findScaleFactor(wheelRotation);
scaleBy(scaleFactor);
Point offset = findOffset(stablePoint, scaleFactor);
offsetBy(offset);
getParent().doLayout();
revalidate();
repaint();
}
private double findScaleFactor(int wheelRotation) {
double d = wheelRotation * 1.08;
return (d > 0) ? 1 / d : -d;
}
private void scaleBy(double scaleFactor) {
int w = (int) (getWidth() * scaleFactor);
int h = (int) (getHeight() * scaleFactor);
preferredSize.setSize(w, h);
}
private Point findOffset(Point stablePoint, double scaleFactor) {
int x = (int) (stablePoint.x * scaleFactor) - stablePoint.x;
int y = (int) (stablePoint.y * scaleFactor) - stablePoint.y;
return new Point(x, y);
}
private void offsetBy(Point offset) {
Point location = getLocation();
setLocation(location.x - offset.x, location.y - offset.y);
}
#Override
public Dimension getPreferredSize() {
return preferredSize;
}
private Rectangle2D r = new Rectangle2D.Float();
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
int w = getWidth();
int h = getHeight();
for (Rectangle2D rect : rects) {
r.setRect(rect.getX() * w, rect.getY() * h,
rect.getWidth() * w, rect.getHeight() * h);
((Graphics2D) g).draw(r);
}
}
}
I have displayed an image(ball) inside the JApplet, now I want the image to move in a vertical way (up and down). The problem is I don't know how to do it.
Could someone has an idea about this matter?
You need to set the position of that image to some calculated value (means you caculate the vertical position using time, speed and maybe other restrictions).
How you'd set that position depends on how you draw the image.
Example, based on drawing in the applet's (or a nested component's) paint(Graphics g) method:
//first calculate the y-position
int yPos += timeSinceLastPaint * speed; //increment the position
if( (speed > 0 && yPos > someMaxY) || (speed < 0 && yPos <0 ) ) {
speed *= -1; //if the position has reached the bottom (max y) or the top invert the direction
}
//in your paint(Graphics g) method:
g.drawImage(image, yPos, x, null);
Then you'd have to constantly repaint the applet.
More information on animations in applets can be found here: http://download.oracle.com/javase/tutorial/uiswing/components/applet.html
another example for javax.swing.Timer with moving Ojbects created by paintComponent(Graphics g), and I have lots of Start, not some blurred Mikado :-)
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class AnimationBackground {
private Random random = new Random();
private JFrame frame = new JFrame("Animation Background");
private final MyJPanel panel = new MyJPanel();
private JLabel label = new JLabel("This is a Starry background.", JLabel.CENTER);
private JPanel stopPanel = new JPanel();
private JPanel startPanel = new JPanel();
public AnimationBackground() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
panel.setBackground(Color.BLACK);
for (int i = 0; i < 50; i++) {
Star star = new Star(new Point(random.nextInt(490), random.nextInt(490)));
star.setColor(new Color(100 + random.nextInt(155), 100 + random.nextInt(155), 100 + random.nextInt(155)));
star.setxIncr(-3 + random.nextInt(7));
star.setyIncr(-3 + random.nextInt(7));
panel.add(star);
}
panel.setLayout(new GridLayout(10, 1));
label.setForeground(Color.WHITE);
panel.add(label);
stopPanel.setOpaque(false);
stopPanel.add(new JButton(new AbstractAction("Stop this madness!!") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
panel.stopAnimation();
}
}));
panel.add(stopPanel);
startPanel.setOpaque(false);
startPanel.add(new JButton(new AbstractAction("Start moving...") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
panel.startAnimation();
}
}));
panel.add(startPanel);
frame.add(panel);
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
AnimationBackground aBg = new AnimationBackground();
}
});
}
private class Star extends Polygon {
private static final long serialVersionUID = 1L;
private Point location = null;
private Color color = Color.YELLOW;
private int xIncr, yIncr;
static final int WIDTH = 500, HEIGHT = 500;
Star(Point location) {
int x = location.x;
int y = location.y;
this.location = location;
this.addPoint(x, y + 8);
this.addPoint(x + 8, y + 8);
this.addPoint(x + 11, y);
this.addPoint(x + 14, y + 8);
this.addPoint(x + 22, y + 8);
this.addPoint(x + 17, y + 12);
this.addPoint(x + 21, y + 20);
this.addPoint(x + 11, y + 14);
this.addPoint(x + 3, y + 20);
this.addPoint(x + 6, y + 12);
}
public void setColor(Color color) {
this.color = color;
}
public void move() {
if (location.x < 0 || location.x > WIDTH) {
xIncr = -xIncr;
}
if (location.y < 0 || location.y > WIDTH) {
yIncr = -yIncr;
}
translate(xIncr, yIncr);
location.setLocation(location.x + xIncr, location.y + yIncr);
}
public void setxIncr(int xIncr) {
this.xIncr = xIncr;
}
public void setyIncr(int yIncr) {
this.yIncr = yIncr;
}
public Color getColor() {
return color;
}
}
private class MyJPanel extends JPanel {
private static final long serialVersionUID = 1L;
private ArrayList<Star> stars = new ArrayList<Star>();
private Timer timer = new Timer(20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (Star star : stars) {
star.move();
}
repaint();
}
});
public void stopAnimation() {
if (timer.isRunning()) {
timer.stop();
}
}
public void startAnimation() {
if (!timer.isRunning()) {
timer.start();
}
}
#Override
public void addNotify() {
super.addNotify();
timer.start();
}
#Override
public void removeNotify() {
super.removeNotify();
timer.stop();
}
MyJPanel() {
this.setPreferredSize(new Dimension(512, 512));
}
public void add(Star star) {
stars.add(star);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (Star star : stars) {
g.setColor(star.getColor());
g.fillPolygon(star);
}
}
}
}
How to move the image inside the JApplet ..?
Pretty much exactly the same way you might do it in a JFrame, JComponent or JPanel or...
Or to put that another way, nothing to do with applets and everything to do with Graphics2D. For more details, see the 2D Graphics Trail of the Java Tutorial.
When you've figured how to move an image and paint it to a Graphics2D, implement that logic in a JComponent or JPanel's paintComponent(Graphics) method and drop the component with moving image into a JApplet or JFrame (or a JPanel etc.).
For the animation side of it, use a javax.swing.Timer as seen in this example. This example does not extend any component. Instead, it creates a BufferedImage and adds it to a JLabel that is displayed to the user. When the timer fires, the code grabs the Graphics object of the image, and proceeds from there to draw the bouncing lines.
import java.awt.image.BufferedImage;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.*;
import javax.swing.*;
import java.util.Random;
class LineAnimator {
public static void main(String[] args) {
final int w = 640;
final int h = 480;
final RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
);
hints.put(
RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY
);
final BufferedImage bi = new BufferedImage(w,h, BufferedImage.TYPE_INT_ARGB);
final JLabel l = new JLabel(new ImageIcon(bi));
final BouncingLine[] lines = new BouncingLine[100];
int factor = 1;
for (int ii=0; ii<lines.length; ii++) {
lines[ii] = new BouncingLine(w*factor,h*factor);
}
final Font font = new Font("Arial", Font.BOLD, 30);
ActionListener al = new ActionListener() {
int count = 0;
long lastTime;
String fps = "";
private final BasicStroke stroke = new BasicStroke(6);
public void actionPerformed(ActionEvent ae) {
count++;
Graphics2D g = bi.createGraphics();
g.setRenderingHints(hints);
g.setColor(new Color(55,12,59));
g.fillRect(0,0,w,h);
g.setStroke(stroke);
for (int ii=0; ii<lines.length; ii++) {
lines[ii].move();
lines[ii].paint(g);
}
if ( System.currentTimeMillis()-lastTime>1000 ) {
lastTime = System.currentTimeMillis();
fps = count + " FPS";
count = 0;
}
g.setColor(Color.YELLOW);
g.setFont(font);
g.drawString(fps,5,h-5);
l.repaint();
g.dispose();
}
};
Timer timer = new Timer(25,al);
timer.start();
JOptionPane.showMessageDialog(null, l);
//System.exit(0);
timer.stop();
}
}
class BouncingLine {
private final Color color;
private static final Random random = new Random();
Line2D line;
int w;
int h;
int x1;
int y1;
int x2;
int y2;
BouncingLine(int w, int h) {
line = new Line2D.Double(random.nextInt(w),random.nextInt(h),random.nextInt(w),random.nextInt(h));
this.w = w;
this.h = h;
this.color = new Color(
random.nextInt(255)
,random.nextInt(255)
,random.nextInt(255)
,64+random.nextInt(128)
);
x1 = (random.nextBoolean() ? 1 : -1);
y1 = (random.nextBoolean() ? 1 : -1);
x2 = -x1;
y2 = -y1;
}
public void move() {
int tx1 = 0;
if (line.getX1()+x1>0 && line.getX1()+x1<w) {
tx1 = (int)line.getX1()+x1;
} else {
x1 = -x1;
tx1 = (int)line.getX1()+x1;
}
int ty1 = 0;
if (line.getY1()+y1>0 && line.getY1()+y1<h) {
ty1 = (int)line.getY1()+y1;
} else {
y1 = -y1;
ty1 = (int)line.getY1()+y1;
}
int tx2 = 0;
if (line.getX2()+x2>0 && line.getX2()+x2<w) {
tx2 = (int)line.getX2()+x2;
} else {
x2 = -x2;
tx2 = (int)line.getX2()+x2;
}
int ty2 = 0;
if (line.getY2()+y2>0 && line.getY2()+y2<h) {
ty2 = (int)line.getY2()+y2;
} else {
y2 = -y2;
ty2 = (int)line.getY2()+y2;
}
line.setLine(tx1,ty1,tx2,ty2);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setColor(color);
//line.set
g2.draw(line);
}
}
Update 1
I want to do it in JApplet(1) using the image(2), is it possible(3)?
The examples by mKorbel and myself feature either an image in a JLabel or custom rendering in a JPanel. In our case, we added the components to a JOptionPane & a JFrame. Either example could be just as easily added to a JApplet, or a JDialog, or as part of another panel, or.. See the Laying Out Components Within a Container lesson & Using Top-Level Containers in the Java Tutorial for more details.
Instead of the stars or lines in our examples, ..paint your image. My example goes so far as to demonstrate how to get the position to bounce around within the bounds of the container.
Sure it is possible, but "Batteries not included". Our intention is to give you some ideas that you can then adapt to your bouncing ball applet. I doubt anyone is going to create an example for you, using balls, in an applet. Though if you post an SSCCE that shows your intent and what you tried, I (and others) would often run with that source. If you want more specific answers, ask a more specific SSCCE. ;)
I want to do it in JApplet.
Why not both? You can have a hybrid application/applet as shown in this animation.
This is my class which I found on the Internet. It was originally an applet but I don't want to use it as an applet so I changed some methods (such as init() to a constructor).
However, it doesn't work. Would you please help me?
SignInFrame Frame:
public class SignInFrame extends javax.swing.JFrame {
Panel panel;
/** Creates new form SignInFrame */
public SignInFrame() {
initComponents();
}
public void init() {
getContentPane().add(panel = new Panel());
}
public void start() {
panel.start();
}
public void stop() {
panel.stop();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new SignInFrame().setVisible(true);
}
});
}}
Panel Dialog:
package ClientGUI;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.geom.GeneralPath;
import java.awt.image.BufferedImage;
/**
*
* #author ICC
*/
public class Panel extends javax.swing.JPanel implements Runnable{
private Thread thread;
private BufferedImage bimg;
private static final int NUMPTS = 6;
// solid line stoke
protected BasicStroke solid = new BasicStroke(10.0f,
BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
// dashed line stroke
protected BasicStroke dashed = new BasicStroke(10.0f,
BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 10, new float[] {5}, 0);
private float animpts[] = new float[NUMPTS * 2];
private float deltas[] = new float[NUMPTS * 2];
protected Paint fillPaint, drawPaint;
// indicates whether or not to fill shape
protected boolean doFill = true;
// indicates whether or not to draw shape
protected boolean doDraw = true;
protected GradientPaint gradient;
protected BasicStroke stroke;
public Panel() {
setBackground(Color.white);
gradient = new GradientPaint(0,0,Color.red,200,200,Color.yellow);
fillPaint = gradient;
drawPaint = Color.blue;
stroke = solid;
}
// generates new points for the path
public void animate(float[] pts, float[] deltas, int i, int limit) {
float newpt = pts[i] + deltas[i];
if (newpt <= 0) {
newpt = -newpt;
deltas[i] = (float) (Math.random() * 4.0 + 2.0);
} else if (newpt >= (float) limit) {
newpt = 2.0f * limit - newpt;
deltas[i] = - (float) (Math.random() * 4.0 + 2.0);
}
pts[i] = newpt;
}
/*
* generates random points with the specified surface width
* and height for the path
*/
public void reset(int w, int h) {
for (int i = 0; i < animpts.length; i += 2) {
animpts[i + 0] = (float) (Math.random() * w);
animpts[i + 1] = (float) (Math.random() * h);
deltas[i + 0] = (float) (Math.random() * 6.0 + 4.0);
deltas[i + 1] = (float) (Math.random() * 6.0 + 4.0);
if (animpts[i + 0] > w / 2.0f) {
deltas[i + 0] = -deltas[i + 0];
}
if (animpts[i + 1] > h / 2.0f) {
deltas[i + 1] = -deltas[i + 1];
}
}
gradient = new GradientPaint(0,0,Color.red,w*.7f,h*.7f,Color.yellow);
}
// calls animate for every point in animpts
public void step(int w, int h) {
for (int i = 0; i < animpts.length; i += 2) {
animate(animpts, deltas, i + 0, w);
animate(animpts, deltas, i + 1, h);
}
}
// sets the points of the path and draws and fills the path
public void drawDemo(int w, int h, Graphics2D g2) {
float[] ctrlpts = animpts;
int len = ctrlpts.length;
float prevx = ctrlpts[len - 2];
float prevy = ctrlpts[len - 1];
float curx = ctrlpts[0];
float cury = ctrlpts[1];
float midx = (curx + prevx) / 2.0f;
float midy = (cury + prevy) / 2.0f;
GeneralPath gp = new GeneralPath(GeneralPath.WIND_NON_ZERO);
gp.moveTo(midx, midy);
for (int i = 2; i <= ctrlpts.length; i += 2) {
float x1 = (midx + curx) / 2.0f;
float y1 = (midy + cury) / 2.0f;
prevx = curx;
prevy = cury;
if (i < ctrlpts.length) {
curx = ctrlpts[i + 0];
cury = ctrlpts[i + 1];
} else {
curx = ctrlpts[0];
cury = ctrlpts[1];
}
midx = (curx + prevx) / 2.0f;
midy = (cury + prevy) / 2.0f;
float x2 = (prevx + midx) / 2.0f;
float y2 = (prevy + midy) / 2.0f;
gp.curveTo(x1, y1, x2, y2, midx, midy);
}
gp.closePath();
if (doDraw) {
g2.setPaint(drawPaint);
g2.setStroke(stroke);
g2.draw(gp);
}
if (doFill) {
if (fillPaint instanceof GradientPaint) {
fillPaint = gradient;
}
g2.setPaint(fillPaint);
g2.fill(gp);
}
}
public Graphics2D createGraphics2D(int w, int h) {
Graphics2D g2 = null;
if (bimg == null || bimg.getWidth() != w || bimg.getHeight() != h) {
bimg = (BufferedImage) createImage(w, h);
reset(w, h);
}
g2 = bimg.createGraphics();
g2.setBackground(getBackground());
g2.clearRect(0, 0, w, h);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
return g2;
}
public void paint(Graphics g) {
Dimension d = getSize();
step(d.width, d.height);
Graphics2D g2 = createGraphics2D(d.width, d.height);
drawDemo(d.width, d.height, g2);
g2.dispose();
if (bimg != null) {
g.drawImage(bimg, 0, 0, this);
}
}
public void start() {
thread = new Thread(this);
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
}
public synchronized void stop() {
thread = null;
}
public void run() {
Thread me = Thread.currentThread();
while (thread == me) {
repaint();
try {
Thread.sleep(10);
} catch (Exception e) { break; }
}
thread = null;
}
public static void main(String argv[]) {
SignInFrame n = new SignInFrame();
n.start();
}}
In your SignInFrame constructor, you call initComponents(), but that does not exist. I think you mean to call init(). Also your JFrame does not have a size set, when I ran this under linux (Java 1.6), it worked but was tiny, you should add a setSize call.
Try it with these edits:
public class SignInFrame extends javax.swing.JFrame {
Panel panel;
/** Creates new form SignInFrame */
public SignInFrame() {
setSize (600,600);
init();
}
public void init() {
getContentPane().add(panel = new Panel());
start();
}
public void start() {
panel.start();
}
public void stop() {
panel.stop();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new SignInFrame().setVisible(true);
}
});
}
}