Resize Graphics2d into JScrollPane - java

In connection with question Resizing a component without repainting is my question how to create resiziable custom Graphics2d in form
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ZoomWithSelectionInViewport implements MouseWheelListener {
private JComponent b;
private int hexSize = 3;
private int zoom = 80;
private JScrollPane view;
public ZoomWithSelectionInViewport() throws Exception {
b = new JComponent() {
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredSize() {
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);
}
}
}
};
view = new JScrollPane(b);
b.addMouseWheelListener(this);
JFrame f = new JFrame();
f.setLocation(10, 10);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(view);
f.setPreferredSize(b.getPreferredSize());
f.pack();
f.setVisible(true);
}
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);
b.revalidate();
b.repaint();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
ZoomWithSelectionInViewport example = new ZoomWithSelectionInViewport();
} catch (Exception ex) {
//
}
}
});
}
}

If I understand correctly, you want the scroll pane's scroll bars to reflect the current zoom state. I see two alternatives:
Don't override getPreferredSize() in the component, and adjust the preferred size in the mouse listener to include the zoomed image; it appears slightly truncated on the right.
Do override getPreferredSize() in the component, and adjust the returned Dimension (now a constant) to include the zoomed boundary implicit in paintComponent().
I'd prefer the latter. I've also found it helpful to write explicit transformation functions to convert zoomed and un-zoomed coordinates, as shown here. An inverse AffineTransform, shown here, is also possible.

Related

Calculate 'interval and increment' for slide in animation in Java Swing

I'm building an application which has a slideshow in its homepage, currently I use Thread.sleep(10) and add/sub the x position of panel I want to slide.
For example: slideIn(30, panel_1, 10) < this will cause panel_1 to slide in with interval of 30ms and subtracts its x by 10 overtime until the panel is in center/occupy the slideshow_panel. But the con of this method is that the sliding animation won't smooth, I want the sliding animation/transition as smooth as Bootstrap Carousel. Is there a way to calculate the speed and increment/decrement value for slide transition speed?
Actually, I've something that's almost perfect for this. I assume you can create a Path2D for your animation path, right? And it also seems like you want a constant speed. There are a couple of references to my project (http://sourceforge.net/p/tus/code/HEAD/tree/) for calculating distance and showing the JPanel for instance, but it shouldn't be hard to remove them and replace with standard java. Try it out
public abstract class PathAnimation {
private Path2D mPath;
private double totalLength;
/**
* Be careful to call path.closePath before invoking this constructor
* #param path
*/
public PathAnimation(Path2D path) {
mPath = path;
totalLength = 0;
PathIterator iterator = mPath.getPathIterator(null);
//Point2D currentLocation;// = path.getCurrentPoint();
double[] location = new double[6];
iterator.currentSegment(location);
while (!iterator.isDone()) {
double[] loc = new double[6];
iterator.next();
iterator.currentSegment(loc);
if (loc[0] == 0 && loc[1] == 0) continue;
double distance = MathUtils.distance(location[0], location[1], loc[0], loc[1]);
totalLength += distance;
location = loc;
}
}
#Override
public Point2D getLocationAtTime(int time) {
return getLocationAtTime(time / (double) getTotalAnimationTime());
}
public Point2D getLocationAtTime(double pctTime) {
double len = totalLength * pctTime;
PathIterator iterator = mPath.getPathIterator(null);
double[] location = new double[6];
iterator.currentSegment(location);
while (!iterator.isDone()) {
double[] loc = new double[6];
iterator.next();
iterator.currentSegment(loc);
double distance= MathUtils.distance(location[0], location[1], loc[0], loc[1]);
if (distance > len) {
double pctThere = len / distance;
double xSpot = location[0] * (1 - pctThere) + loc[0] * pctThere;
double ySpot = location[1] * (1 - pctThere) + loc[1] * pctThere;
return new Point2D.Double(xSpot, ySpot);
}
len -= distance;
location = loc;
}
throw new ArrayIndexOutOfBoundsException("Path is too short or time is too long!");
}
/**
* Number of milliseconds that this animation spans
* #return
*/
public abstract int getTotalAnimationTime();
public static void main(String args[]) {
Rectangle rect = new Rectangle(10,10,20,20);
final Path2D.Double myPath = new Path2D.Double((Shape)rect);
myPath.closePath();
final PathAnimation myAnimation = new PathAnimation(myPath) {
Area star = new Area(PaintUtils.createStandardStar(15, 15, 5, .5, 0));
#Override
public Dimension getSizeAtTime(int time) {
return new Dimension(15,15);
}
#Override
public void paintAtTime(Graphics2D g, int time) {
Area toPaint = star;
if ((time / 150) % 2 == 1) {
Dimension size = getSizeAtTime(0);
toPaint = new Area(toPaint);
PaintUtils.rotateArea(toPaint, Math.PI / 6);
}
g.setColor(Color.YELLOW);
g.fill(toPaint);
g.setColor(Color.RED);
g.draw(toPaint);
}
#Override
public int getTotalAnimationTime() {
return 10000;
}
};
System.out.println(myAnimation.getLocationAtTime(0));
System.out.println(myAnimation.getLocationAtTime(2500));
System.out.println(myAnimation.getLocationAtTime(4000));
System.out.println(myAnimation.getLocationAtTime(5000));
System.out.println(myAnimation.getLocationAtTime(7000));
System.out.println(myAnimation.getLocationAtTime(7500));
System.out.println(myAnimation.getLocationAtTime(9000));
System.out.println(myAnimation.getLocationAtTime(10000));
final JPanel jp = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int time = ((int) System.currentTimeMillis()) % myAnimation.getTotalAnimationTime();
int time2 = (time + myAnimation.getTotalAnimationTime() / 2) % myAnimation.getTotalAnimationTime();
Point2D pt = myAnimation.getLocationAtTime(time);
Point2D pt2 = myAnimation.getLocationAtTime(time2);
Dimension size = myAnimation.getSizeAtTime(time);
g2.translate(pt.getX() - size.width / 2, pt.getY() - size.height / 2);
myAnimation.paintAtTime(g2, time);
g2.translate(- (pt.getX() - size.width / 2), - (pt.getY() - size.height / 2));
g2.translate(pt2.getX() - size.width / 2, pt2.getY() - size.height / 2);
myAnimation.paintAtTime(g2, time2);
g2.translate(- (pt2.getX() - size.width / 2), - (pt2.getY() - size.height / 2));
g2.setColor(Color.BLACK);
g2.draw(myPath);
}
};
WindowUtilities.visualize(jp);
AbstractAction action = new AbstractAction() {
public void actionPerformed(ActionEvent ae) {
jp.repaint();
}
};
javax.swing.Timer t = new javax.swing.Timer(30, action);
t.start();
}
}

How to adjust graphics on Swing progress indicator?

The lower source code, with the pictured example, from the post
Circular Progress Bar for Java Swing not working, is a great Swing feature.
I'd like to be able to use it with a "transparent" JFrame or glass pane
but the graphic "petals", in paint(), want to interact with the background,
so if the opacity of the background is very low, you can barely
see the "petals". Not being familiar with the Graphics2D functions there, I've taken many stabs in the dark to try to adjust the code, but no luck, so could someone who knows how those functions work,
suggest changes so that the "petals" don't interact with the background,
and start out solid white, and gradually fade, as the code does?
I also don't need any fade-in or fade-out delays, and I'm also
having difficulty with that, but if someone could just suggest
modifications for the "petals", that would be great!
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import javax.swing.*;
import javax.swing.plaf.LayerUI;
public class Loading_Test {
static final WaitLayerUI layerUI = new WaitLayerUI();
JFrame frame = new JFrame("JLayer With Animated Gif");
public Loading_Test() {
JPanel panel = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 300);
}
};
JLayer<JPanel> jlayer = new JLayer<>(panel, layerUI);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(jlayer);
frame.pack();
frame.setVisible(true);
layerUI.start();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Loading_Test loading_Test = new Loading_Test();
}
});
}
}
class WaitLayerUI extends LayerUI<JPanel> implements ActionListener {
private boolean mIsRunning;
private boolean mIsFadingOut;
private Timer mTimer;
private int mAngle;
private int mFadeCount;
private int mFadeLimit = 15;
#Override
public void paint(Graphics g, JComponent c) {
int w = c.getWidth();
int h = c.getHeight();
super.paint(g, c); // Paint the view.
if (!mIsRunning) {
return;
}
Graphics2D g2 = (Graphics2D) g.create();
float fade = (float) mFadeCount / (float) mFadeLimit;
Composite urComposite = g2.getComposite(); // Gray it out.
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .5f * fade));
g2.fillRect(0, 0, w, h);
g2.setComposite(urComposite);
int s = Math.min(w, h) / 5;// Paint the wait indicator.
int cx = w / 2;
int cy = h / 2;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(s / 4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.setPaint(Color.white);
g2.rotate(Math.PI * mAngle / 180, cx, cy);
for (int i = 0; i < 12; i++) {
float scale = (11.0f - (float) i) / 11.0f;
g2.drawLine(cx + s, cy, cx + s * 2, cy);
g2.rotate(-Math.PI / 6, cx, cy);
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, scale * fade));
}
g2.dispose();
}
#Override
public void actionPerformed(ActionEvent e) {
if (mIsRunning) {
firePropertyChange("tick", 0, 1);
mAngle += 3;
if (mAngle >= 360) {
mAngle = 0;
}
if (mIsFadingOut) {
if (--mFadeCount == 0) {
mIsRunning = false;
mTimer.stop();
}
} else if (mFadeCount < mFadeLimit) {
mFadeCount++;
}
}
}
public void start() {
if (mIsRunning) {
return;
}
mIsRunning = true;// Run a thread for animation.
mIsFadingOut = false;
mFadeCount = 0;
int fps = 24;
int tick = 1000 / fps;
mTimer = new Timer(tick, this);
mTimer.start();
}
public void stop() {
mIsFadingOut = true;
}
#Override
public void applyPropertyChange(PropertyChangeEvent pce, JLayer l) {
if ("tick".equals(pce.getPropertyName())) {
l.repaint();
}
}
}
One problem I see is that the code is setting the composite in the wrong place in the loop. It works, but as you've discovered, it's difficult to maintain or change.
g2.setComposite is being called at the end of the loop. This sets the alpha for the next petal drawn. This means there is no easy change you can make to adjust the alpha of the very first petal.
First, I would make the code more in line with the way humans think (at least, the way I think): Set the alpha of the line you're about to draw, right before you draw it:
for (int i = 0; i < 12; i++) {
float scale = (12 - i) / 12f;
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, scale * fade));
g2.drawLine(cx + s, cy, cx + s * 2, cy);
g2.rotate(-Math.PI / 6, cx, cy);
}
Now, making it work with any arbitrary background alpha is easy. We merely adjust the value of scale:
float componentAlpha = 0.5f;
for (int i = 0; i < 12; i++) {
float scale = (12 - i) / 12f;
// Give petals the same relative alpha as the component
// they're overlaying.
scale *= componentAlpha;
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, scale * fade));
g2.drawLine(cx + s, cy, cx + s * 2, cy);
g2.rotate(-Math.PI / 6, cx, cy);
}

Changing the center of a GUI with mouseclick, and repainting

I've got a GUI that generates a graphics image using the Mandelbrot set.
I've implemented some zoom buttons, but I'd like to be able to change the centre of my GUI with a mouseclick (make mouse coordinates the new centre-point).
It's proving to be quite difficult. Any suggestions?
My attempt can be found at the moveGraph method.
Thanks in advance!
package assn4_12mgs;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class MandelBrot extends JFrame{
MandelPanel mp;
double xMax = 2.26;
double xMin = -2.24;
double yMax = 2.26;
double yMin = -2.24;
double yMove, xMove;
static double ESCAPE_MODULUS = 2.0;
static int MAX_ITERATIONS = 32;
public MandelBrot(){
super();
setLayout(new BorderLayout());
setTitle("Graham's Mandelbrot GUI");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(600,700);
setResizable(false);
mp = new MandelPanel();
mp.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent evt) {
MoveGraph(evt);
}
});
JPanel panel = new JPanel(new FlowLayout());
JButton zoomIn = new JButton("+");
zoomIn.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent evt) {
ZoomIn(evt);
}
});
JButton zoomOut = new JButton("-");
zoomOut.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent evt) {
ZoomOut(evt);
}
});
JButton reset = new JButton("Reset");
reset.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent evt) {
reset(evt);
}
});
panel.add(reset, BorderLayout.WEST); ///How to change positioning?
panel.add(zoomOut, BorderLayout.EAST);
panel.add(zoomIn, BorderLayout.EAST);
add(panel, BorderLayout.SOUTH);
add(mp, BorderLayout.NORTH);
}
private void MoveGraph(MouseEvent evt){
int x = evt.getPoint().x;
int y = evt.getPoint().y;
xMove = x/100;
yMove = y/100;
mp.repaint();
}
private void ZoomIn(MouseEvent evt){
xMax /= 2;
xMin /= 2;
yMax /= 2;
yMin /= 2;
mp.repaint();
}
private void ZoomOut(MouseEvent evt){
xMax *= 2;
xMin *= 2;
yMax *= 2;
yMin *= 2;
mp.repaint();
}
private void reset(MouseEvent evt){
xMax = 2.26;
xMin = -2.24;
yMax = 2.26;
yMin = -2.24;
xMove = 0;
yMove = 0;
mp.repaint();
}
public class MandelPanel extends JPanel {
public MandelPanel() {
setPreferredSize(new Dimension(600,600));
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// draw here
int row, col;
ComplexNumber c, z;
double xPos, yPos;
double modulus = 0;
boolean escaped = false;
int iterations = 0;
int desiredColour;
// Calculate the scale factor to go from pixels to actual units
int height = mp.getHeight(); // drawingZone is the JPanel drawing area
int width = mp.getWidth();
double xScale = (xMax - xMin) / width; // These are min and max values in actual
double yScale = (yMax - yMin) / height; // coordinates.
Graphics2D g2D = (Graphics2D)g;
BufferedImage pretty = new BufferedImage(width, height,
BufferedImage.TYPE_3BYTE_BGR);
// Iterate through the entire panel, pixel by pixel
for (row = 0; row < height; row++) {
// Calculate the actual y position
yPos = yMax - row * yScale;// - yMove
for (col = 0; col < width; col++) {
// Calculate the actual x position
xPos = xMin + col * xScale;// + xMove;
// Create the complex number for this position
c = new ComplexNumber(xPos, yPos);
z = new ComplexNumber(0, 0);
iterations = 0;
// Iterate the fractal equation z = z*z + c
// until z either escapes or the maximum number of iterations
// is reached
do {
z = (z.multiply(z)).add(c);
modulus = z.abs();
escaped = modulus > ESCAPE_MODULUS;
iterations++;
} while (iterations < MAX_ITERATIONS && !escaped);
// Set the colour according to what stopped the above loop
if (escaped) {
desiredColour = setEscapeColour(iterations);
} else {
desiredColour = setColour(modulus);
}
pretty.setRGB(col, row, desiredColour);
} // end for
} // end for
g2D.drawImage(pretty, null, 0, 0);
//yMove = 0;
//xMove = 0;
}
}
// Sets gray level for escape situation
private static int setEscapeColour(int numIterations) {
float grayLevel = 0.5F - (float) numIterations / MAX_ITERATIONS;
grayLevel = Math.max(grayLevel, 0.1F);
return new Color(grayLevel, grayLevel, grayLevel).getRGB();
} // end setEscapeColour
// Sets colour level for interior situation
// The algorithm used here is *totally* empirical!
private static int setColour(double modulus) {
float factor = (float) (modulus / ESCAPE_MODULUS);
float incr = (float) Math.log10(factor * 5.5);
float r = Math.min(Math.abs(10.0F * incr) * factor, 1.0F);
float g = Math.min(Math.abs(6.0F * incr) * factor, 1.0F);
float b = Math.min(Math.abs(0.5F * factor + incr), 1.0F);
return new Color(r, g, b).getRGB();
} // end setColour
public static void main(String args[]){
MandelBrot manBrot = new MandelBrot();
manBrot.setVisible(true);
}
}
We take a point on which a user has clicked as a center point for drawing, then calculate the window (half the distance up and down, left and right) around that point. See
/**
* Calculate real coordinates of the point we clicked.
*/
double xDist = Math.abs(xMax) + Math.abs(xMin);
double yDist = Math.abs(yMax) + Math.abs(yMin);
double xTr = xDist / 600.0 * ((double) e.getX());
double yTr = yDist / 700.0 * ((double) e.getY());
/**
* Calculate the window coordinates. It is relative to the point where the user clicked.
*/
xMax = xTr + xDist/2.0;
xMin = xTr - xDist/2.0;
yMax = yTr + yDist/2.0;
yMin = yTr - yDist/2.0;
** The Code**
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.JOptionPane;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class MandelBrot
extends JFrame
{
public static class ComplexNumber
{
double re;
double im;
public void setRe(double re)
{
this.re = re;
}
public double re()
{
return re;
}
public void setIm(double im)
{
this.im = im;
}
public double im()
{
return im;
}
public ComplexNumber(double re, double im)
{
this.re = re;
this.im = im;
}
public ComplexNumber add(ComplexNumber c)
{
setRe(re() + c.re());
setIm(im() + c.im());
return this;
}
public ComplexNumber multiply(ComplexNumber z)
{
setRe(re()*z.re() - im()*z.im());
setIm(im()*z.re() - re()*z.im());
return this;
}
public double abs()
{
return Math.sqrt(re()*re() + im()*im());
}
}
MandelPanel mp;
double xMax = 2.26;
double xMin = -2.24;
double yMax = 2.26;
double yMin = -2.24;
double yMove, xMove;
static double ESCAPE_MODULUS = 2.0;
static int MAX_ITERATIONS = 32;
public MandelBrot()
{
super();
setLayout(new BorderLayout());
setTitle("Graham's Mandelbrot GUI");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(600, 700);
setResizable(false);
mp = new MandelPanel();
mp.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
JOptionPane.showMessageDialog(
null,
"You clicked on a picture area (x,y): (" + e.getX() + "," + e.getY() + ")" ,
"Info",
JOptionPane.INFORMATION_MESSAGE);
double xDist = Math.abs(xMax) + Math.abs(xMin);
double yDist = Math.abs(yMax) + Math.abs(yMin);
double xTr = xDist / 600.0 * ((double) e.getX());
double yTr = yDist / 700.0 * ((double) e.getY());
xMax = xTr + xDist/2.0;
xMin = xTr - xDist/2.0;
yMax = yTr + yDist/2.0;
yMin = yTr - yDist/2.0;
System.out.format("%f %f %f %f %n", xDist, yDist, xTr, yTr);
System.out.format("%f %f %f %f %n", xMin, xMax, yMin, yMax);
mp.repaint();
}
public void mouseReleased(MouseEvent evt)
{
MoveGraph(evt);
}
});
JPanel panel = new JPanel(new FlowLayout());
JButton zoomIn = new JButton("+");
zoomIn.addMouseListener(new MouseAdapter()
{
public void mouseReleased(MouseEvent evt)
{
ZoomIn(evt);
}
});
JButton zoomOut = new JButton("-");
zoomOut.addMouseListener(new MouseAdapter()
{
public void mouseReleased(MouseEvent evt)
{
ZoomOut(evt);
}
});
JButton reset = new JButton("Reset");
reset.addMouseListener(new MouseAdapter()
{
public void mouseReleased(MouseEvent evt)
{
reset(evt);
}
});
panel.add(reset, BorderLayout.WEST); ///How to change positioning?
panel.add(zoomOut, BorderLayout.EAST);
panel.add(zoomIn, BorderLayout.EAST);
add(panel, BorderLayout.SOUTH);
add(mp, BorderLayout.NORTH);
}
private void MoveGraph(MouseEvent evt)
{
int x = evt.getPoint().x;
int y = evt.getPoint().y;
xMove = x / 100;
yMove = y / 100;
mp.repaint();
}
private void ZoomIn(MouseEvent evt)
{
xMax /= 2;
xMin /= 2;
yMax /= 2;
yMin /= 2;
mp.repaint();
}
private void ZoomOut(MouseEvent evt)
{
xMax *= 2;
xMin *= 2;
yMax *= 2;
yMin *= 2;
mp.repaint();
}
private void reset(MouseEvent evt)
{
xMax = 2.26;
xMin = -2.24;
yMax = 2.26;
yMin = -2.24;
xMove = 0;
yMove = 0;
mp.repaint();
}
public class MandelPanel
extends JPanel
{
public MandelPanel()
{
setPreferredSize(new Dimension(600, 600));
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// draw here
int row, col;
ComplexNumber c, z;
double xPos, yPos;
double modulus = 0;
boolean escaped = false;
int iterations = 0;
int desiredColour;
// Calculate the scale factor to go from pixels to actual units
int height = mp.getHeight(); // drawingZone is the JPanel drawing area
int width = mp.getWidth();
double xScale = (xMax - xMin) / width; // These are min and max values in actual
double yScale = (yMax - yMin) / height; // coordinates.
Graphics2D g2D = (Graphics2D) g;
BufferedImage pretty = new BufferedImage(width, height,
BufferedImage.TYPE_3BYTE_BGR);
// Iterate through the entire panel, pixel by pixel
for (row = 0; row < height; row++)
{
// Calculate the actual y position
yPos = yMax - row * yScale;// - yMove
for (col = 0; col < width; col++)
{
// Calculate the actual x position
xPos = xMin + col * xScale;// + xMove;
// Create the complex number for this position
c = new ComplexNumber(xPos, yPos);
z = new ComplexNumber(0, 0);
iterations = 0;
// Iterate the fractal equation z = z*z + c
// until z either escapes or the maximum number of iterations
// is reached
do
{
z = (z.multiply(z)).add(c);
modulus = z.abs();
escaped = modulus > ESCAPE_MODULUS;
iterations++;
}
while (iterations < MAX_ITERATIONS && !escaped);
// Set the colour according to what stopped the above loop
if (escaped)
{
desiredColour = setEscapeColour(iterations);
}
else
{
desiredColour = setColour(modulus);
}
pretty.setRGB(col, row, desiredColour);
} // end for
} // end for
g2D.drawImage(pretty, null, 0, 0);
//yMove = 0;
//xMove = 0;
}
}
// Sets gray level for escape situation
private static int setEscapeColour(int numIterations)
{
float grayLevel = 0.5F - (float) numIterations / MAX_ITERATIONS;
grayLevel = Math.max(grayLevel, 0.1F);
return new Color(grayLevel, grayLevel, grayLevel).getRGB();
} // end setEscapeColour
// Sets colour level for interior situation
// The algorithm used here is *totally* empirical!
private static int setColour(double modulus)
{
float factor = (float) (modulus / ESCAPE_MODULUS);
float incr = (float) Math.log10(factor * 5.5);
float r = Math.min(Math.abs(10.0F * incr) * factor, 1.0F);
float g = Math.min(Math.abs(6.0F * incr) * factor, 1.0F);
float b = Math.min(Math.abs(0.5F * factor + incr), 1.0F);
return new Color(r, g, b).getRGB();
} // end setColour
public static void main(String args[])
{
MandelBrot manBrot = new MandelBrot();
manBrot.setVisible(true);
}
}

why is it only painting one of the components?

package puzzle;
import java.awt.Color;
import javax.swing.*;
import java.util.*;
public class Puzzle {
Integer x = 50;
Integer y = 50;
int x2 = 100;
int y2 = 100;
int vnotx = 0;
int vnoty = 0;
float t = 0;
float t2 = 0;
JFrame frame = new JFrame();
Move m = new Move(x, y,Color.GREEN);
Move n = new Move(x,y,Color.ORANGE);
java.util.Timer timer = new java.util.Timer();
java.util.Timer timer2 = new java.util.Timer();
public Puzzle() {
frame.setUndecorated(true);
frame.setSize(400, 400);
frame.add(m);
frame.add(n);
frame.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
formKeyPressed(evt);
}
});
com.sun.awt.AWTUtilities.setWindowOpacity(frame, 1f);
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
rD();
}
}, 0, 20);
timer2.scheduleAtFixedRate(new TimerTask() {
public void run() {
t2+=.01;
x2 =(int) ((Math.cos(t2)+1)*100);
y2 =(int) ((Math.sin(t2)+1)*100);
System.out.println(x2+", "+y2);
}
}, 0, 2);
}
int z = 0;
public void rD() {
z++;
m = new Move(x, y, Color.GREEN);
n = new Move(x2, y2, Color.ORANGE);
frame.add(n);
frame.add(m);
frame.validate();
}
private void formKeyPressed(java.awt.event.KeyEvent evt) {
int id = evt.getID();
int kC = evt.getKeyCode();
if (kC == 39) {
final java.util.Timer right = new java.util.Timer();
right.scheduleAtFixedRate(new TimerTask() {
public void run() {
t += .01;
int x1 = x;
if (x + 51 < 400) {
x = x1 + (int) (10 * t) + (-1 * ((int) (20 * t * t)));
}
if (t > .5) {
t = 0;
right.cancel();
}
}
}, 0, 10);
}
if (kC == 37) {
final java.util.Timer left = new java.util.Timer();
left.scheduleAtFixedRate(new TimerTask() {
public void run() {
t += .01;
int x1 = x;
if (x - 1 >= 0) {
x = x1 + (int) (-10 * t) - (-1 * ((int) (20 * t * t)));
}
if (t > .5) {
t = 0;
left.cancel();
}
}
}, 0, 10);
}
if (kC == 40) {
final java.util.Timer right = new java.util.Timer();
right.scheduleAtFixedRate(new TimerTask() {
public void run() {
t += .01;
int y1 = y;
if (y + 51 < 400) {
y = y1 + (int) (10 * t) + (-1 * ((int) (20 * t * t)));
}
if (t > .5) {
t = 0;
right.cancel();
}
}
}, 0, 10);
}
if (kC == 38) {
final java.util.Timer left = new java.util.Timer();
left.scheduleAtFixedRate(new TimerTask() {
public void run() {
t += .01;
int y1 = y;
if (y-1 >= 0)
{
y = y1 + (int) (-10 * t) - (-1 * ((int) (20 * t * t)));
}
if (t > .5) {
t = 0;
left.cancel();
}
}
}, 0, 10);
}
if (kC == 32) {
}
if (kC == 67) {
}
if (kC == 77) {
}
}
public static void main(String[] args) {
new Puzzle().frame.setVisible(true);
}
}
why is this not adding both instances of the move class. it only adds the last one called. the class paint is below what should i change in order for it paint both instances of move
package puzzle;
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class Move extends JPanel{
int x;
int y;
Color kk;
public Move(int x1, int y1, Color k)
{
x=x1;
y=y1;
kk = k;
}
public void paintComponent(Graphics g)
{Graphics2D g2 = (Graphics2D)g;
super.paintComponent(g2);
g2.setColor(kk);
g2.fill(new RoundRectangle2D.Float(x, y, 50, 50,10,10));
g2.drawString(x+", "+y, 200, 200);
}
}
the class move paints a rectangle with the position and color passed from the puzzle class
Are you taking layout managers into consideration? Do you know about JFrame's contentPane using BorderLayout as its default layout manager, and if you add components to this without constants, they are added BorderLayout.CENTER, and only one of these can be visible at a time (the last added).
I think that you might do better disassociating Move from JPanel, yes making it paintable, but making it more of a logical object rather than a gui component and instead of having it extend JPanel, allow a single drawing JPanel to hold one or more Move objects and then draw the Move objects in this JPanel's paintComponent method.
Also, you seem to be using several java.util.Timers in your code, but since it is a Swing application, it would likely be better served by using javax.swing.Timers instead, in fact perhaps just one Swing Timer that functioned as a game loop.
if (kC == 39) {
Don't use magic numbers.
Instead you should be using:
KeyEvent.VK_???

JScrollPane "jumping" when scrollbars start being used

Sorry, this is a long piece of sample code below, but here's the issue:
I have a background that I'm actively drawing (I could probably be smart and draw it once and just scale it, but this shows the problem just as well).
You can use the mouse wheel to zoom in and out on the image.
The idea is to do a "google map" zoom where it zooms under the mouse pointer. What I've noticed is that it doesn't seem to actuall behave until the image is big enough to use both scroll bars. Until then, you get the image simply getting bigger, but locked to the origin.
The "correct" behavior should be that the viewposition is moved, even though the scrollbars aren't yet being utilized by an oversized image.
I'm not sure how to get around this (or if this is correct and expected) without drawing a much larger background behind the image so it more than fills the viewport.
It "jumps" after one or the other scroll bars engages due to (I think) the same issue.
Thoughts?
package com.hostigr.raw.io.client.gui;
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.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;
public class TestFrame extends JFrame {
public static void main(String[] arg) {
new TestFrame();
}
public TestFrame() {
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 {
JScrollPane scrollPane;
public 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 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;
public 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;
double prevScale = scale;
if (notches != 0) {
modifier = 1.0 + -notches / Math.abs(notches) * scaleModifier;
}
scale = 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;
}*/
this.repaint();
setPreferredSize(new Dimension((int)(scale * width * SIZE),
(int)(scale * width * SIZE)));
JViewport viewport = ((JViewport)(getParent().getParent().getComponent(0)));
Point orig = viewport.getViewPosition();
viewport.setViewPosition(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();
}
private class MapMouseWheelListener implements MouseWheelListener {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
loc = e.getPoint();
incrementScale(e.getWheelRotation());
}
}
}
}
looks like as JViewPort#scrollRectToVisible(Rectangle r) for me works
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)))));
EDIT and with correct Swing repaint's rulles, then yout codeBlock must ends with revalidate(); + repaint();
setPreferredSize(new Dimension((int) (scale * width * SIZE),
(int) (scale * width * SIZE)));
JViewport viewport = ((JViewport) (getParent().getParent().getComponent(0)));
Point orig = viewport.getViewPosition();
/*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();

Categories