How to resize JComponent forcefully in a null layout? - java

I am trying to resize a panel in a container panel where the container panel's layout is set to null.
I am setting the location and changing the size like this:
panelCapture.setLocation(
scale.scale(((capture.getTotalBounds().width + 500) / 2) - (capture.getTotalBounds().width / 2)),
scale.scale(((capture.getTotalBounds().height + 500) / 2) - (capture.getTotalBounds().height / 2))
);
Dimension pcSize = panelCapture.getSize();
Dimension pcNewSize = new Dimension(scale.scale(pcSize.width), scale.scale(pcSize.height));
panelCapture.setSize(pcNewSize);
panelCapture.setPreferredSize(pcNewSize);
The scaling multiplies it by my current scale which is 1.0f, 1.1f, etc.
Changing the position seems to work but changing the size does not.

Instead of using setLocation and setSize, try setBounds(...) or setPreferredSize(...). You may also need a call to repaint() after that. You may want to refer to the tutorial on using absolute/null layout here.
Here's a sample I wrote to change the size of a JPanel inside another JPanel which has a null layout (using only setBounds).
public class Capture
{
JPanel capture;
JPanel panelCapture;
JTextField scaleField;
JButton changeScale;
static final int PARENT_WIDTH = 800;
static final int PARENT_HEIGHT = 600;
static final int CHILD_WIDTH = 100;
static final int CHILD_HEIGHT = 100;
public static void main(String [] args)
{
Capture c = new Capture();
c.doStuff();
}
public void doStuff()
{
capture = new JPanel();
capture.setLayout(null);
capture.setPreferredSize(new Dimension(PARENT_WIDTH, PARENT_HEIGHT));
scaleField = new JTextField();
scaleField.setBounds(100, 550, 200, 25);
capture.add(scaleField);
changeScale = new JButton("Scale");
changeScale.setBounds(325, 550, 100, 25);
changeScale.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e)
{
panelCapture.setBounds(getBounds(CHILD_WIDTH * Float.parseFloat(scaleField.getText()), CHILD_HEIGHT * Float.parseFloat(scaleField.getText())));
}
});
capture.add(changeScale);
panelCapture = new JPanel();
panelCapture.setBackground(Color.blue);
panelCapture.setBounds(getBounds(CHILD_WIDTH, CHILD_HEIGHT));
capture.add(panelCapture);
JFrame frame = new JFrame();
frame.setContentPane(capture);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private Rectangle getBounds(float width, float height)
{
int left = (int) (PARENT_WIDTH - width) / 2;
int top = (int) (PARENT_HEIGHT - height) / 2;
return new Rectangle(left, top, (int) width, (int) height);
}
}

Related

How to fill JSlider track up to the point of the current thumb value with Nimubs L&F?

I am working on a volume slider and would like to change the default look of Nimbus JSlider.
I want my JSlider to automatically fill the track up to the point of the current thumb value. An idea to this approach would be like (see picture)
I've tried to extend BasicSliderUI and override the paintTrack() method with no luck. I've also tried to skin the JSlider (see example http://www.jasperpotts.com/blog/2008/08/skinning-a-slider-with-nimbus/) but it seems that this method only changes the look of JSlider.
Anyone know how to approach this problem?
This example is supported only for horizontal JSlider:
import java.awt.*;
import javax.swing.*;
public class SliderSkinDemo2 {
public JComponent makeUI() {
UIDefaults d = new UIDefaults();
d.put("Slider:SliderTrack[Enabled].backgroundPainter", new Painter<JSlider>() {
#Override public void paint(Graphics2D g, JSlider c, int w, int h) {
int arc = 10;
int trackHeight = 8;
int trackWidth = w - 2;
int fillTop = 4;
int fillLeft = 1;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setStroke(new BasicStroke(1.5f));
g.setColor(Color.GRAY);
g.fillRoundRect(fillLeft, fillTop, trackWidth, trackHeight, arc, arc);
int fillBottom = fillTop + trackHeight;
int fillRight = xPositionForValue(
c.getValue(), c,
new Rectangle(fillLeft, fillTop, trackWidth, fillBottom - fillTop));
g.setColor(Color.ORANGE);
g.fillRect(fillLeft + 1, fillTop + 1, fillRight - fillLeft, fillBottom - fillTop);
g.setColor(Color.WHITE);
g.drawRoundRect(fillLeft, fillTop, trackWidth, trackHeight, arc, arc);
}
//#see javax/swing/plaf/basic/BasicSliderUI#xPositionForValue(int value)
protected int xPositionForValue(int value, JSlider slider, Rectangle trackRect) {
int min = slider.getMinimum();
int max = slider.getMaximum();
int trackLength = trackRect.width;
double valueRange = (double) max - (double) min;
double pixelsPerValue = (double) trackLength / valueRange;
int trackLeft = trackRect.x;
int trackRight = trackRect.x + (trackRect.width - 1);
int xPosition;
xPosition = trackLeft;
xPosition += Math.round(pixelsPerValue * ((double) value - min));
xPosition = Math.max(trackLeft, xPosition);
xPosition = Math.min(trackRight, xPosition);
return xPosition;
}
});
JSlider slider = new JSlider();
slider.putClientProperty("Nimbus.Overrides", d);
JPanel p = new JPanel();
p.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
p.setBackground(Color.DARK_GRAY);
p.add(new JSlider());
p.add(Box.createRigidArea(new Dimension(200, 20)));
p.add(slider);
return p;
}
public static void main(String... args) {
EventQueue.invokeLater(() -> {
try {
for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(laf.getName())) {
UIManager.setLookAndFeel(laf.getClassName());
}
}
} catch (Exception e) {
e.printStackTrace();
}
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new SliderSkinDemo2().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}

How to slowly change object color from one to another?

I am trying to achieve a scenario where the color of an object changes slowly from one color to another color.
I have the initial color as targetColor and final color as updateColor. The changingSpeed variable is set to 5.
The mechanism that I have to use is
Use getRed(), getGreen(), getBlue() to obtain the red, green and blue color
Compute the difference of color of target bytargetColor–color = [ dr dg db]
Normalize [ dr dg db] by dividing the norm of the vector [ dr dg db] T(Beware of div by zero)
Multiply it by changingSpeed to control the speed in changing the color
Update the color to color + [ dr’ dg’ db’ ]
So far, i have been able to make the following code:
dr=targetColor.getRed()-updateColor.getRed();
dg=targetColor.getGreen()-updateColor.getGreen();
db=targetColor.getBlue()-updateColor.getBlue();
double nrml= Math.sqrt((dr*dr)+(dg*dg)+(db*db));
dr=dr/nrml;
dg=dg/nrml;
db=db/nrml;
How to execute the 4th and 5th steps?
Can please anyone specify how to do this via code example?
Also please check if the above code is correct.
Here is an example the fades the background as you move from component to component:
import java.awt.*;
import java.awt.event.*;
import java.util.Hashtable;
import java.util.ArrayList;
import javax.swing.*;
public class Fader
{
// background color when component has focus
private Color fadeColor;
// steps to fade from original background to fade background
private int steps;
// apply transition colors at this time interval
private int interval;
// store transition colors from orginal background to fade background
private Hashtable backgroundColors = new Hashtable();
/*
* Fade from a background color to the specified color using
* the default of 10 steps at a 50 millisecond interval.
*
* #param fadeColor the temporary background color
*/
public Fader(Color fadeColor)
{
this(fadeColor, 10, 50);
}
/*
* Fade from a background color to the specified color in the
* specified number of steps at the default 5 millisecond interval.
*
* #param fadeColor the temporary background color
* #param steps the number of steps to fade in the color
*/
public Fader(Color fadeColor, int steps)
{
this(fadeColor, steps, 50);
}
/*
* Fade from a background color to the specified color in the
* specified number of steps at the specified time interval.
*
* #param fadeColor the temporary background color
* #param steps the number of steps to fade in the color
* #param intevral the interval to apply color fading
*/
public Fader(Color fadeColor, int steps, int interval)
{
this.fadeColor = fadeColor;
this.steps = steps;
this.interval = interval;
}
/*
* Add a component to this fader.
*
* The fade color will be applied when the component gains focus.
* The background color will be restored when the component loses focus.
*
* #param component apply fading to this component
*/
public Fader add(JComponent component)
{
// Get colors to be used for fading
ArrayList colors = getColors( component.getBackground() );
// FaderTimer will apply colors to the component
new FaderTimer( colors, component, interval );
return this;
}
/*
** Get the colors used to fade this background
*/
private ArrayList getColors(Color background)
{
// Check if the color ArrayList already exists
Object o = backgroundColors.get( background );
if (o != null)
{
return (ArrayList)o;
}
// Doesn't exist, create fader colors for this background
ArrayList colors = new ArrayList( steps + 1 );
colors.add( background );
int rDelta = ( background.getRed() - fadeColor.getRed() ) / steps;
int gDelta = ( background.getGreen() - fadeColor.getGreen() ) / steps;
int bDelta = ( background.getBlue() - fadeColor.getBlue() ) / steps;
for (int i = 1; i < steps; i++)
{
int rValue = background.getRed() - (i * rDelta);
int gValue = background.getGreen() - (i * gDelta);
int bValue = background.getBlue() - (i * bDelta);
colors.add( new Color(rValue, gValue, bValue) );
}
colors.add( fadeColor );
backgroundColors.put(background, colors);
return colors;
}
class FaderTimer implements FocusListener, ActionListener
{
private ArrayList colors;
private JComponent component;
private Timer timer;
private int alpha;
private int increment;
FaderTimer(ArrayList colors, JComponent component, int interval)
{
this.colors = colors;
this.component = component;
component.addFocusListener( this );
timer = new Timer(interval, this);
}
public void focusGained(FocusEvent e)
{
alpha = 0;
increment = 1;
timer.start();
}
public void focusLost(FocusEvent e)
{
alpha = steps;
increment = -1;
timer.start();
}
public void actionPerformed(ActionEvent e)
{
alpha += increment;
component.setBackground( (Color)colors.get(alpha) );
if (alpha == steps || alpha == 0)
timer.stop();
}
}
public static void main(String[] args)
{
// Create test components
JComponent textField1 = new JTextField(10);
textField1.setBackground( Color.YELLOW );
JComponent textField3 = new JTextField(10);
JComponent textField4 = new JTextField(10);
JComponent button = new JButton("Start");
JComponent checkBox = new JCheckBox("Check Box");
JFrame frame = new JFrame("Fading Background");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.getContentPane().add(textField1, BorderLayout.NORTH );
frame.getContentPane().add(button, BorderLayout.SOUTH );
frame.getContentPane().add(textField3, BorderLayout.WEST );
frame.getContentPane().add(textField4, BorderLayout.EAST );
frame.getContentPane().add(checkBox);
// Gradual Fading (using defaults)
// Fader fader = new Fader( new Color(155, 255, 155) );
Fader fader = new Fader( new Color(155, 255, 155), 10, 50 );
fader.add( textField1 );
fader.add( textField3 );
fader.add( checkBox );
// Instant Fading
fader = new Fader( new Color(255, 155, 155), 1, 1 );
fader.add( textField4 );
fader.add( button );
frame.pack();
frame.setVisible( true );
}
}
It uses a Timer to update the backgrounds at the specified interval. It then just interpolates between the two color based on the number of steps desired.
Look at this example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Test {
public static void main(String args[]) {
final JFrame frame = new JFrame();
frame.setBounds(100, 100, 300, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// set some random initial color
final Component comp = frame.getContentPane();
comp.setBackground(new Color(
(float) Math.random(),
(float) Math.random(),
(float) Math.random()));
frame.setVisible(true);
final Timer timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
final Color targetColor = new Color(30,40,50);
final int changingSpeed = 5;
final Color currentColor = comp.getBackground();
// step 1
int r = currentColor.getRed();
int g = currentColor.getGreen();
int b = currentColor.getBlue();
// step 2
double dr = targetColor.getRed() - r;
double dg = targetColor.getGreen() - g;
double db = targetColor.getBlue() - b;
// step 3
double norm = Math.sqrt(dr*dr+dg*dg+db*db);
if (norm < .001) {
((Timer)(evt.getSource())).stop();
return;
}
dr /= norm;
dg /= norm;
db /= norm;
// step 4
dr *= Math.min(changingSpeed, norm);
dg *= Math.min(changingSpeed, norm);
db *= Math.min(changingSpeed, norm);
// step 5
r += dr;
g += dg;
b += db;
comp.setBackground(new Color(r,g,b));
frame.repaint();
}
});
timer.start();
}
}
A few things to note:
Use a timer to fire the updates. This ensures, they are done in the EventThread, what is mandatory for manipulating Swing GUIs.
Test the norm for beeing very small. This means, your delta is near zero and you should stop updating the color.
Use the minimum of the norm and your changing speed. If your changing speed is high enough, your color will alternate around the target color and your delta will swap the sign forever and the process doesn't terminate. So if your delta is smaller than your changing speed, use the delta!
Don't forget to call repaint, when you are done with manipulating the color.
Yea, instead of using the for loop in line
while(i<=10);
you can actually use your changing speed. Meanwhile your changingSpeed should
be an array of length 3 because the different offset of colors interval i.e
dr, dg, db so that they can be taking care of independently.
like this...
int [] changingSpeed(int []Offset){
int loop = 5;
// 5 means the color should be change 5 times
int [] changeSpeed = new int[3];
changeSpeed[0]= offset[0]/loop;
changeSpeed[1]= offset[1]/loop;
changeSpeed[2]= offset[2]/loop;
return changeSpeed;
}
// your update method will now look like this
updateColor(int [] changeSpeed) throws AWTException{
int dr = changeSpeed[0];
int dg = changeSpeed[1];
int db = changeSpeed[2];
Robot slow = new Robot();
int i=0;
int f= loop; // the number of time you want the color to change
while(i<=f){
slow.delay(1000)
//sleep will sleep for 1000ms
setColor(targetColor.getRed() + dr/10, targetColor.getGreen(),targetColor.getBlue());
setColor(targetColor.getRed(), targetColor.getGreen() + (dg/10),targetColor.getBlue());
setColor(targetColor.getRed(), targetColor.getGreen(),targetColor.getBlue() + db/10);
i++;
}
}
I wouldnt rely on a specific delay time to compute the next step in an animation as this will certainly provide different execution times in different machines, although it might not be a relevant difference.
Instead of a changing speed factor your could use a long representing the animation total time and use a Thread (or another multithreading mecanism) to control the animation lifecycle (such as calculating how much time has passed since the last repaint and whats the percentage of completion for the next iteration).
I don't know if I followed your math instructions.
I created a Swing GUI so i could watch the transition from one color to another.
The Reset Colors button generates a random starting color and a random finishing color. The Start button transforms the bottom panel from the starting color to the finishing color. Each transformation moves about 5 values in either the red, green, or blue dimension, with a delay of 300 milliseconds.
I tended to watch the numbers change, rather than the color. I wanted to make sure that the transformation was fairly even.
Anyway, here's the code. You can use this to model other Swing GUI's. I put all the classes together in one file so I could paste the code here. You should separate the classes into separate files.
package com.ggl.testing;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ColorChangeTest implements Runnable {
private static final Insets normalInsets = new Insets(10, 10, 0, 10);
private Color currentColor;
private Color targetColor;
private ColorPanel changingColorPanel;
private ColorPanel currentColorPanel;
private ColorPanel targetColorPanel;
private JLabel changingLabel;
private JLabel currentLabel;
private JLabel targetLabel;
public static void main(String args[]) {
SwingUtilities.invokeLater(new ColorChangeTest());
}
#Override
public void run() {
JFrame frame = new JFrame("Color Change Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
mainPanel.add(createColorPanel(), BorderLayout.NORTH);
mainPanel.add(createChangingPanel(), BorderLayout.CENTER);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createColorPanel() {
JPanel colorPanel = new JPanel();
setNewColors();
JPanel currentPanel = new JPanel();
currentPanel.setLayout(new BorderLayout());
JPanel currentLabelPanel = new JPanel();
currentLabelPanel.setLayout(new BorderLayout());
JLabel startLabel = new JLabel("Starting Color");
startLabel.setHorizontalAlignment(JLabel.CENTER);
currentLabelPanel.add(startLabel, BorderLayout.NORTH);
currentLabel = new JLabel(getColorString(currentColor));
currentLabel.setHorizontalAlignment(JLabel.CENTER);
currentLabelPanel.add(currentLabel, BorderLayout.SOUTH);
currentPanel.add(currentLabelPanel, BorderLayout.NORTH);
currentColorPanel = new ColorPanel(100, 100, currentColor);
currentPanel.add(currentColorPanel, BorderLayout.CENTER);
colorPanel.add(currentPanel);
JPanel targetPanel = new JPanel();
targetPanel.setLayout(new BorderLayout());
JPanel targetLabelPanel = new JPanel();
targetLabelPanel.setLayout(new BorderLayout());
JLabel finishLabel = new JLabel("Finishing Color");
finishLabel.setHorizontalAlignment(JLabel.CENTER);
targetLabelPanel.add(finishLabel, BorderLayout.NORTH);
targetLabel = new JLabel(getColorString(targetColor));
targetLabel.setHorizontalAlignment(JLabel.CENTER);
targetLabelPanel.add(targetLabel, BorderLayout.SOUTH);
targetPanel.add(targetLabelPanel, BorderLayout.NORTH);
targetColorPanel = new ColorPanel(100, 100, targetColor);
targetPanel.add(targetColorPanel, BorderLayout.CENTER);
colorPanel.add(targetPanel);
colorPanel.add(createButtonPanel());
return colorPanel;
}
private JPanel createButtonPanel() {
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridBagLayout());
int gridy = 0;
JButton resetButton = new JButton("Reset Colors");
resetButton.addActionListener(new ResetColorsListener(this));
addComponent(buttonPanel, resetButton, 0, gridy++, 1, 1, normalInsets,
GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL);
JButton startButton = new JButton("Start");
startButton.addActionListener(new ColorChangeListener(this));
addComponent(buttonPanel, startButton, 0, gridy++, 1, 1, normalInsets,
GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL);
return buttonPanel;
}
private JPanel createChangingPanel() {
JPanel changingPanel = new JPanel();
changingPanel.setLayout(new BorderLayout());
changingLabel = new JLabel(getColorString(currentColor));
changingLabel.setHorizontalAlignment(JLabel.CENTER);
changingPanel.add(changingLabel, BorderLayout.NORTH);
changingColorPanel = new ColorPanel(300, 200, currentColor);
changingPanel.add(changingColorPanel, BorderLayout.CENTER);
return changingPanel;
}
public void setChangingColorLabelText(Color color) {
changingLabel.setText(getColorString(color));
}
public void setNewColors() {
currentColor = getRandomColor();
targetColor = getRandomColor();
}
public void displayNewColors() {
currentLabel.setText(getColorString(currentColor));
targetLabel.setText(getColorString(targetColor));
changingLabel.setText(getColorString(currentColor));
currentColorPanel.setColor(currentColor);
targetColorPanel.setColor(targetColor);
changingColorPanel.setColor(currentColor);
}
public Color getCurrentColor() {
return currentColor;
}
public Color getTargetColor() {
return targetColor;
}
public ColorPanel getChangingColorPanel() {
return changingColorPanel;
}
private Color getRandomColor() {
return new Color((float) Math.random(), (float) Math.random(),
(float) Math.random());
}
private String getColorString(Color color) {
int r = color.getRed();
int g = color.getGreen();
int b = color.getBlue();
return "(" + r + ", " + g + ", " + b + ")";
}
private void addComponent(Container container, Component component,
int gridx, int gridy, int gridwidth, int gridheight, Insets insets,
int anchor, int fill) {
GridBagConstraints gbc = new GridBagConstraints(gridx, gridy,
gridwidth, gridheight, 1.0D, 1.0D, anchor, fill, insets, 0, 0);
container.add(component, gbc);
}
public class ColorPanel extends JPanel {
private static final long serialVersionUID = -2894328511698328096L;
private Color color;
public ColorPanel(int width, int height, Color color) {
this.color = color;
this.setPreferredSize(new Dimension(width, height));
}
public void setColor(Color color) {
this.color = color;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(color);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
public class ResetColorsListener implements ActionListener {
private ColorChangeTest colorChangeTest;
public ResetColorsListener(ColorChangeTest colorChangeTest) {
this.colorChangeTest = colorChangeTest;
}
#Override
public void actionPerformed(ActionEvent event) {
colorChangeTest.setNewColors();
colorChangeTest.displayNewColors();
}
}
public class ColorChangeListener implements ActionListener {
private ColorChangeTest colorChangeTest;
public ColorChangeListener(ColorChangeTest colorChangeTest) {
this.colorChangeTest = colorChangeTest;
}
#Override
public void actionPerformed(ActionEvent event) {
ColorChange colorChange = new ColorChange(colorChangeTest);
new Thread(colorChange).start();
}
}
public class ColorChange implements Runnable {
private static final long sleepTime = 300L;
private double r, g, b, dr, dg, db;
private int tr, tg, tb, cr, cg, cb;
private ColorChangeTest colorChangeTest;
public ColorChange(ColorChangeTest colorChangeTest) {
this.colorChangeTest = colorChangeTest;
}
#Override
public void run() {
calculateColorChange();
sleep(sleepTime);
while (calculateNextColor()) {
sleep(sleepTime);
}
setColor(colorChangeTest.getTargetColor());
}
private void calculateColorChange() {
double increment = 5D;
// step 1
r = cr = colorChangeTest.getCurrentColor().getRed();
g = cg = colorChangeTest.getCurrentColor().getGreen();
b = cb = colorChangeTest.getCurrentColor().getBlue();
// step 2
tr = colorChangeTest.getTargetColor().getRed();
tg = colorChangeTest.getTargetColor().getGreen();
tb = colorChangeTest.getTargetColor().getBlue();
dr = tr - cr;
dg = tg - cg;
db = tb - cb;
// step 3
double d = Math.sqrt(dr * dr + dg * dg + db * db);
int steps = (int) (d / increment);
dr /= (double) steps;
dg /= (double) steps;
db /= (double) steps;
setColor(new Color(cr, cg, cb));
}
private boolean calculateNextColor() {
// step 5
r += dr;
g += dg;
b += db;
if (isFinished()) {
return false;
} else {
setColor(new Color(round(r), round(g), round(b)));
return true;
}
}
private boolean isFinished() {
return isColorFinished(cr, tr, round(r))
|| isColorFinished(cg, tg, round(g))
|| isColorFinished(cb, tb, round(b));
}
private int round(double value) {
return (int) Math.round(value);
}
private boolean isColorFinished(int original, int target, int current) {
boolean isFinished = false;
if (current < 0 || current > 255) {
isFinished = true;
} else if ((target >= original) && (current >= target)) {
isFinished = true;
} else if ((target <= original) && (current <= target)) {
isFinished = true;
}
return isFinished;
}
private void setColor(final Color color) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
colorChangeTest.getChangingColorPanel().setColor(color);
colorChangeTest.setChangingColorLabelText(color);
}
});
}
private void sleep(long sleepTime) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
}
}
}
}
In order to achieve the act of slowness, it might be a good idea to use the instance of Robot class.
//Method to obtain the offset of the color
static int [] getColorOffset(Color initial, Color final){
int [] colorOffset = new int[3];
colorOffset[0]= final.getRed()-initial.getRed();
colorOffset[1] = final.getGreen()-initial.getGreen();
colorOffset[2]= final.getBlue()-initial.getBlue();
return colorOffset;
}
updateColor(int [] colorOffset) throws AWTException{
int dr = colorOffset[0];
int dg = colorOffset[1];
int db = colorOffset[2];
Robot slow = new Robot();
int i=0;
while(i<=10){
slow.delay(1000)
//sleep will sleep for 1000ms
setColor(targetColor.getRed() + dr/10, targetColor.getGreen(),targetColor.getBlue());
setColor(targetColor.getRed(), targetColor.getGreen() + (dg/10),targetColor.getBlue());
setColor(targetColor.getRed(), targetColor.getGreen(),targetColor.getBlue() + db/10);
i++;
}
}
public static void main(String args[]) throws AWTException{
Color initial = Color.black;
Color final = Color,white;
int [] colorOffset = getColorOffset(initial, final);
updateColor(colorOffset);
}

JPanel zoom out

The code below is perfect for zoom in and zoom out, but zoom out with restrictions. How to improve this code to allow zoom out without restrictions. In this example
you can do zoom in ever you want, but zooming out is possible to return zoomed in panel to its original state.
public class FPanel extends javax.swing.JPanel {
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() {
public void mouseWheelMoved(MouseWheelEvent e) {
updatePreferredSize(e.getWheelRotation(), e.getPoint());
}
});
}
private void updatePreferredSize(int n, Point p) {
double d = (double) n * 1.08;
d = (n > 0) ? 1/d : -d;
int w = (int) (getWidth() * d);
int h = (int) (getHeight() * d);
preferredSize.setSize(w, h);
int offX = (int)(p.x * d) - p.x;
int offY = (int)(p.y * d) - p.y;
setLocation(getLocation().x-offX,getLocation().y-offY);
getParent().doLayout();
}
public Dimension getPreferredSize() {
return preferredSize;
}
private Rectangle2D r = new Rectangle2D.Float();
public void paint(Graphics g) {
super.paint(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);
}
}
}
If I am correct, you want to zoom out the panel less than 100% (original size OR size of the JFrame).
Check this code.
public class FPanel extends javax.swing.JPanel {
private static int prevN = 0;
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);
JPanel containerPanel = new JPanel(); // extra JPanel
containerPanel.setLayout(new GridBagLayout());
FPanel zoomPanel = new FPanel();
containerPanel.add(zoomPanel);
jf.add(new JScrollPane(containerPanel));
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 n, Point p) {
if(n == 0) // ideally getWheelRotation() should never return 0.
n = -1 * prevN; // but sometimes it returns 0 during changing of zoom
// direction. so if we get 0 just reverse the direction.
double d = (double) n * 1.08;
d = (n > 0) ? 1 / d : -d;
int w = (int) (getWidth() * d);
int h = (int) (getHeight() * d);
preferredSize.setSize(w, h);
int offX = (int)(p.x * d) - p.x;
int offY = (int)(p.y * d) - p.y;
getParent().setLocation(getParent().getLocation().x-offX,getParent().getLocation().y-offY);
//in the original code, zoomPanel is being shifted. here we are shifting containerPanel
getParent().doLayout(); // do the layout for containerPanel
getParent().getParent().doLayout(); // do the layout for jf (JFrame)
prevN = n;
}
#Override
public Dimension getPreferredSize() {
return preferredSize;
}
private Rectangle2D r = new Rectangle2D.Float();
public void paint(Graphics g) {
super.paint(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);
}
}
}
Explaination : I have added an extra JPanel (containerPanel) which contains the zoomPanel. The containerPanel will accommodate for the empty space created when zoomPanel size is less than that of JFrame.
Also, the position sensitive zooming is only till the size of zoomPanel is greater than that of frame. Once the zoomPanel is smaller than JFrame, it will always be centered (by GridBagLayout).

Image gets disappeared in the vertical scrollpane view port

duke.png ->
arrowToLeft.gif ->
arrowToRight.gif ->
I need a UI where I want to depict a network device's graphical representation in Swing. For this, I am just loading multiple images and overlap them one by one to show the current state of the device. I have to support zooming for this view. The zoom code looks like this.
public class LayeredPaneTest{
private JLayeredPane layeredPane;
private JScrollPane scrollPane;
private static double MIN_ZOOM_VALUE = 0.60; // 1.0;
private static double MAX_ZOOM_VALUE = 2.0;
private static final int LAYER1 = 0;
private static final int LAYER2 = 1;
private static final int LAYER3 = 3;
private double scaleFactor = 1.0;
private JInternalFrame internalFrame =
new JInternalFrame("LayeredPaneTest",false, false, false, false);
public LayeredPaneTest(){
loadView();
}
public JInternalFrame getView(){
return internalFrame;
}
private void loadView(){
((javax.swing.plaf.basic.BasicInternalFrameUI)internalFrame.getUI())
.setNorthPane(null);
internalFrame.setBorder(null);
internalFrame.getContentPane().add(buildCenterPane());
internalFrame.setSize(new Dimension(200, 200));
internalFrame.setLocation(0, 0);
internalFrame.setResizable(false);
internalFrame.setVisible(true);
}
private JPanel buildCenterPane(){
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
layeredPane = new JLayeredPane();
Position shelfPosition = new Position(0,0,200,200);
setLayeredPaneSize(shelfPosition);
JLabel label = getImageLabel(getImage("duke.png"),
new Position(0,0,100,100));
layeredPane.add(label, Integer.valueOf(LAYER1));
label = getImageLabel(getImage("arrowToLeft.gif"),
new Position(100,100,50,50));
layeredPane.add(label, Integer.valueOf(LAYER2));
label = getImageLabel(getImage("arrowToRight.gif"),
new Position(50,50,50,50));
layeredPane.add(label, Integer.valueOf(LAYER3));
scrollPane = new JScrollPane(layeredPane);
panel.add(scrollPane, BorderLayout.CENTER);
panel.add(getSliderPane(), BorderLayout.SOUTH);
return panel;
}
private Image getImage(String key){
InputStream is = this.getClass().getResourceAsStream(key);
try {
return ImageIO.read(is);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private void setLayeredPaneSize(Position shelfPosition){
int width = (int)(shelfPosition.getWidth() * scaleFactor + 10);
int height = (int)(shelfPosition.getHeight() * scaleFactor + 10);
layeredPane.setPreferredSize(new Dimension(width,height));
}
public void zoom(double factor){
if (factor < MIN_ZOOM_VALUE)
factor = MIN_ZOOM_VALUE;
else if (factor > MAX_ZOOM_VALUE)
factor = MAX_ZOOM_VALUE;
scaleFactor = factor;
Position shelfPosition = new Position(0,0,200,200);
setLayeredPaneSize(shelfPosition);
scrollPane.getViewport().repaint();
scrollPane.repaint();
scrollPane.getViewport().revalidate();
scrollPane.revalidate();
}
private JLabel getImageLabel(Image image, Position position) {
position = position.moveInRatio(scaleFactor);
ImageLabel label = new ImageLabel(new ImageIcon(image), position);
label.setOpaque(false);
label.setBounds(position.getLeft(),
position.getTop(),position.getWidth(),position.getHeight());
return label;
}
private JPanel getSliderPane(){
JPanel outer = new JPanel();
outer.setLayout(new FlowLayout());
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
final JSlider slider = new JSlider((int) (MIN_ZOOM_VALUE * 100),
(int) (MAX_ZOOM_VALUE * 100), 100);
slider.setMajorTickSpacing(1);
slider.setMinorTickSpacing(1);
double sliderValue = scaleFactor * 100.0;
slider.setValue((int) sliderValue);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
scaleFactor = slider.getValue() / 100.0;
zoom(scaleFactor);
}
});
panel.add(slider, BorderLayout.CENTER);
outer.add(panel);
return outer;
}
public static void main(String...strings){
JFrame frame = new JFrame("FrameDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new LayeredPaneTest().getView(),
BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
static class Position{
private final int left,top,width,height;
Position(int x1, int y1, int x2, int y2){
this.left = x1;
this.top = y1;
this.width = x2;
this.height = y2;
}
public int getLeft() {
return left;
}
public int getTop() {
return top;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
private class ImageLabel extends JLabel{
private static final long serialVersionUID = 6152144095443433296L;
private ImageIcon image;
private Position position;
public ImageLabel(ImageIcon image, Position position){
super(image);
this.image = image;
this.position = position;
}
public void paintComponent(Graphics g) {
int newX = (int)(position.getLeft() * scaleFactor);
int newY = (int)(position.getTop() * scaleFactor);
Graphics2D g2 = (Graphics2D)g;
int newW = (int)(position.getWidth() * scaleFactor);
int newH = (int)(position.getHeight() * scaleFactor);
setBounds(newX, newY, newW, newH);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawImage(image.getImage(), 0, 0, newW, newH, null);
}
}
}
But the problem here is, when I zoom in once and zoom out, some of the images disappear. Any idea why it behaves like this?
Following are the steps to reproduce the bug;
a. Drag the slider bar to the maximum,
b. Witness the image being expanded to maximum and the scroll bar is introduced,
c. Now few portion of the image is hidden,
d. Now drag the slider bar to minimum.
e. The hidden portion of the image disappears.
You do not honor the paint chain by calling super.XXX implementation of overridden paintComponent method like so:
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
//do the rest of the painting here
}
As the docs clearly state:
if you do not invoker super's implementation you must honor the opaque
property, that is if this component is opaque, you must completely
fill in the background in a non-opaque color. If you do not honor the
opaque property you will likely see visual artifacts.
Also note the #Override annotation to make sure I am overriding the correct method, and by default paintComponent is protected keep it that way as you dont want to expose this method to other classes they should use repaint()

Image rendering outside of the frame?

Im working on a game in Java and having an issue (i believe its with the content pane) when rendering. I have a screen class which draws the background and all sprites to an Image. The frame then displays the image using a doubleBuffer. For some odd reason tho the image is rendering off the edge of the frame. You can see in the link below that the image is rendering 3 pixels to the left and 28 pixels above where it should be. Does anyone have any idea what could be causing this?
![enter image description here][1]
http://imageshack.us/photo/my-images/41/weirdg.png/
public class Game extends JFrame implements Runnable{
private static final long serialVersionUID = 1L;
//graphics
public BufferStrategy buffy;
BufferedImage image;
Screen screen;
public Boolean running = false;
public Boolean playerTurn = false;
public InputManager input;
public Level level;
//JButton b;
public static final int HEIGHT = 452;
public static final int WIDTH = 768;
public Game() {
super("GridWars");
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel drawPanel = new JPanel();
drawPanel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
drawPanel.setLayout(null);
drawPanel.setOpaque(false);
//drawPanel.setLocation(50,50);
setContentPane(drawPanel);
setResizable(false);
pack();
setLocationRelativeTo(null);
setVisible(true);
requestFocus();
createBufferStrategy(2);
//b = new JButton("this sucks");
//getContentPane().add(b);
//b.setBounds(300, 300, 100, 50);
buffy = getBufferStrategy();
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
screen = new Screen(WIDTH, HEIGHT);
input = new InputManager(this);
level = new Level(WIDTH, HEIGHT, input, this);
}
public void start() {
running = true;
new Thread(this).start();
}
public void setup(){
}
public void run() {
final double TICKS = 30.0;
final double UPDATE_INTERVAL_NS = 1000000000 / TICKS;
double pastUpdateNS = System.nanoTime();
int updateCount = 0;
int frameCount = 0;
final double FRAPS = 60.0;
final double RENDER_INTERVAL_NS = 1000000000 / FRAPS;
double pastRenderNS = System.nanoTime();
int pastSecondNS = (int) (pastUpdateNS/1000000000);
while(running) {
double nowNS = System.nanoTime();
if(nowNS - pastUpdateNS >= UPDATE_INTERVAL_NS) {
update();
pastUpdateNS += UPDATE_INTERVAL_NS;
updateCount++;
}
float interp = Math.min(1.0f, (float) ((nowNS - pastUpdateNS) / UPDATE_INTERVAL_NS) );
render(interp);
pastRenderNS += RENDER_INTERVAL_NS;
frameCount++;
int thisSecondNS = (int) (pastUpdateNS/1000000000);
if (thisSecondNS > pastSecondNS) {
//System.out.println("TICKS: "+updateCount+" | FRAPS: "+frameCount);
updateCount = 0;
frameCount = 0;
pastSecondNS = thisSecondNS;
}
while( nowNS - pastRenderNS < RENDER_INTERVAL_NS && nowNS - pastUpdateNS < UPDATE_INTERVAL_NS) {
try { Thread.sleep(1); } catch(Exception e) {};
nowNS = System.nanoTime();
}
}
}
public void update() {
input.update();
level.update();
}
public void render(float interp) {
level.render(screen, interp);
image = screen.getImage();
Graphics g = buffy.getDrawGraphics();
g.drawImage(image, 0, 0, null, null);
//b.repaint();
g.dispose();
buffy.show();
}
public static void main(String[] args) {
Game game = new Game();
game.start();
}
}
The 0,0 coordinate of Graphics object you obtain from buffy.getDrawGraphics(); is exactly at top left corner of JFrame and it is ignoring frame decorations.
UPD I forgot one obvious option. JFrame.getInsets() provides information about decorations. You could simply shift your rendering.
You would make frame undecorated (setUndecorated(true)) and render/manage window controls yourself.
Or, and i think it is easier way, you would forget about direct rendering on JFrame, place Canvas on it, and use it instead. Canvas also contains createBufferStrategy method, so you need few simple changes.
JPanel drawPanel = new JPanel();
drawPanel.setLayout(new BorderLayout());
Canvas canvas = new Canvas();
canvas.setPreferredSize(new Dimension(WIDTH, HEIGHT));
drawPanel.add(canvas, BorderLayout.CENTER);
// some code skipped
canvas.setIgnoreRepaint(true); //important
canvas.createBufferStrategy(2);
buffy = canvas.getBufferStrategy();
I've created simple demo with similar render few days ago for another answer. Maybe it will helpful.

Categories