Difficulty in resizing an image which is stored in a JLabel - image

I managed to increase an image of JLabel(which has an imageIcon stored in). When I press the increase size button, the original size of the image is increased on the panel, which is exactly what I want. However, when I click on my decrease size button(I figured dividing it by the scale might fix it)the label decreases, but the actual image appearance(size I guess)is changed. It's not decreasing the size, the same way my increase button increases the size. I have spent hours trying to figure out why by multiplying it, I am able to increase the size of a the label and the image in it(which implies that not just the label is increasing, the actual image is too)but for decrease(I'm dividing instead of multiplying)it doesn't work. Here is both my increase and decrease listener.
public class IncreaseSizeListener implements ActionListener {
static JLabel increasedLabel;
#Override
public void actionPerformed(ActionEvent e) {
increasedLabel = CardLabelListener.selectedLabel;
Icon icon = CardLabelListener.selectedLabel.getIcon();
int scale =2;
System.out.println("Increased size fired");
//I can now resize images, based on my needs
BufferedImage bi = new BufferedImage(
scale*icon.getIconWidth(),
scale*icon.getIconHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.scale(scale,scale);
icon.paintIcon(null,g,0,0);
g.dispose();
JLabel temp = new JLabel(new ImageIcon(bi));
//to ensure proper size is kept for the enlarged image
CardLabelListener.selectedLabel.setSize(icon.getIconWidth()*scale, icon.getIconHeight()*(scale));
CardLabelListener.selectedLabel.setIcon(temp.getIcon());
CardLabelListener.selectedLabel.updateUI();
}
}
public class DecreaseSizeListener implements ActionListener {
static JLabel increasedLabel;
#Override
public void actionPerformed(ActionEvent e) {
increasedLabel = CardLabelListener.selectedLabel;
Icon icon = CardLabelListener.selectedLabel.getIcon();
int scale =2;
//I can now resize images, based on my needs
BufferedImage bi = new BufferedImage(
icon.getIconWidth()/scale,
icon.getIconHeight()/scale,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.scale(scale,scale);
icon.paintIcon(null,g,0,0);
g.dispose();
JLabel temp = new JLabel(new ImageIcon(bi));
//to ensure proper size is kept for the enlarged image
CardLabelListener.selectedLabel.setSize( (icon.getIconWidth()/scale), (icon.getIconHeight()/(scale)));
CardLabelListener.selectedLabel.setIcon(temp.getIcon());
CardLabelListener.selectedLabel.updateUI();
}
}

Change g.scale(scale,scale); to g.scale(0.5d,0.5d); in your decrease action listener
Or you could do this...
int scale = 0.5;
//I can now resize images, based on my needs
BufferedImage bi = new BufferedImage(
icon.getIconWidth() * scale,
icon.getIconHeight() * scale,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.scale(scale,scale);
icon.paintIcon(null,g,0,0);
g.dispose();
// This really isn't required...
//JLabel temp = new JLabel(new ImageIcon(bi));
//to ensure proper size is kept for the enlarged image
// There is a better way...
//CardLabelListener.selectedLabel.setSize( (icon.getIconWidth()/scale), (icon.getIconHeight()/(scale)));
// This isn't required
//CardLabelListener.selectedLabel.setIcon(temp.getIcon());
// This doesn't do what you think it does...
//CardLabelListener.selectedLabel.updateUI();
CardLabelListener.selectedLabel.setIcon(new ImageIcon(bi));
CardLabelListener.selectedLabel.setSize(CardLabelListener.selectedLabel.getPreferredSize());
Now both the increase and decrease algorithm's are just about the same (except for the factor), you should be able to use a single method ;)
This is pretty much the code I ended up with...
public class ScaleMyIcon {
public static void main(String[] args) {
new ScaleMyIcon();
}
public ScaleMyIcon() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new ScaleMyIconPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
protected class ScaleMyIconPane extends JPanel {
public ScaleMyIconPane() {
setLayout(new BorderLayout());
ImageIcon image = null;
try {
image = new ImageIcon(ImageIO.read(getClass().getResource("/stormtrooper-tie.jpg")));
} catch (IOException ex) {
ex.printStackTrace();
}
JLabel label = new JLabel(image);
add(label);
JPanel buttons = new JPanel();
JButton increase = new JButton("+");
JButton decrease = new JButton("-");
buttons.add(increase);
buttons.add(decrease);
increase.addActionListener(new IncreaseSizeListener(label));
decrease.addActionListener(new DecreaseSizeListener(label));
add(buttons, BorderLayout.SOUTH);
}
}
public class Scaler {
public Icon getScaledInstance(Icon original, double scale) {
BufferedImage bi = new BufferedImage(
(int)Math.round(scale * original.getIconWidth()),
(int)Math.round(scale * original.getIconHeight()),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.scale(scale, scale);
original.paintIcon(null, g, 0, 0);
g.dispose();
return new ImageIcon(bi);
}
}
public class IncreaseSizeListener extends Scaler implements ActionListener {
private JLabel increasedLabel;
private IncreaseSizeListener(JLabel label) {
increasedLabel = label;
}
#Override
public void actionPerformed(ActionEvent e) {
Icon icon = increasedLabel.getIcon();
int scale = 2;
increasedLabel.setIcon(getScaledInstance(icon, scale));
}
}
public class DecreaseSizeListener extends Scaler implements ActionListener {
private JLabel decreasedLabel;
private DecreaseSizeListener(JLabel label) {
decreasedLabel = label;
}
#Override
public void actionPerformed(ActionEvent e) {
Icon icon = decreasedLabel.getIcon();
decreasedLabel.setIcon(getScaledInstance(icon, 0.5d));
}
}
}
UPDATED with different approach
While I was mucking around with it, I noticed two issues. There was no coalition between the up and down scales and you were never using the original image to scale against, you were always scaling the dirty image. Try scaling the image down and back up again.
This is my take on how to overcome those issues
public class ScaleMyIcon {
public static void main(String[] args) {
new ScaleMyIcon();
}
public ScaleMyIcon() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new ScaleMyIconPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
protected class ScaleMyIconPane extends JPanel {
public ScaleMyIconPane() {
setLayout(new BorderLayout());
ImageIcon image = null;
try {
image = new ImageIcon(ImageIO.read(getClass().getResource("/stormtrooper-tie.jpg")));
} catch (IOException ex) {
ex.printStackTrace();
}
JLabel label = new JLabel(image);
add(label);
JPanel buttons = new JPanel();
JButton increase = new JButton("+");
JButton decrease = new JButton("-");
buttons.add(increase);
buttons.add(decrease);
increase.addActionListener(new IncreaseSizeListener(label));
decrease.addActionListener(new DecreaseSizeListener(label));
add(buttons, BorderLayout.SOUTH);
}
}
public static class Scalable {
private JLabel label;
private Icon original;
private static double scale = 1;
private Scalable(JLabel label) {
this.label = label;
original = label.getIcon();
}
public JLabel getLabel() {
return label;
}
public double getScale() {
return scale;
}
public void setScale(double scale) {
this.scale = scale;
}
public void incrementScale(double factor) {
setScale(getScale() + factor);
}
public Icon getScaledInstance() {
BufferedImage bi = new BufferedImage(
(int) Math.round(scale * original.getIconWidth()),
(int) Math.round(scale * original.getIconHeight()),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.scale(scale, scale);
original.paintIcon(null, g, 0, 0);
g.dispose();
return new ImageIcon(bi);
}
}
public class IncreaseSizeListener extends Scalable implements ActionListener {
public IncreaseSizeListener(JLabel label) {
super(label);
}
#Override
public void actionPerformed(ActionEvent e) {
incrementScale(0.05);
getLabel().setIcon(getScaledInstance());
}
}
public class DecreaseSizeListener extends Scalable implements ActionListener {
private DecreaseSizeListener(JLabel label) {
super(label);
}
#Override
public void actionPerformed(ActionEvent e) {
incrementScale(-0.05);
getLabel().setIcon(getScaledInstance());
}
}
}

Related

javafx User interface not updating?

I'm new to JavaFX.
I'm building a GUI for a project of mine, and I have a problem with it -
it seems that once I show my UI it stops updating.
In my case, it supposed to update a fill colour for a circle but it does not.
I tried to move the line:
someCircleId.setFill(color));
to be above the line:
Main.stage.show();
in the initialize function in my code and it did change the color of
the certain circle.
public class UIController implements Initializable {
public UIController() {
fillMap();
}
#Override
public void initialize(URL location, ResourceBundle resources) {
Main.stage.show();
}
#FXML
public void pressExitButton() {
Main.dropDBSchema();
System.exit(0);
}
public void changeCircleColor(String circleKey, Color color) {
Platform.runLater(
() -> {
Circle circle = this.circles.get(circleKey);
PauseTransition delay = new PauseTransition(Duration.seconds(10));
delay.setOnFinished(event -> circle.setFill(color));
delay.play();
}
);
}
}
And this is the class that uses these functions:
public class MonitoringLogicImpl implements MonitoringLogic {
public void updateUI(UUID flowUUID, String sender, String receiver, DATA_STATUS status){
String key = flowUUID.toString()+"_"+sender+"_"+receiver;
Color color = this.uiController.getColorAccordingToStatus(status);
this.uiController.changeCircleColor(key, color);
}
}
This is the FXML initialization :
public void start(Stage stage){
this.stage = stage;
FXMLLoader loader = new FXMLLoader();
try {
loader.setLocation(getClass().getResource("/UserInterface.fxml"));
this.root = loader.load();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
stage.setTitle("Troubleshooting project");
stage.setScene(new Scene(root, 900, 700));
stage.show();
}
I created my UI using Scene-Builder tool.

How to smoothly animate an ImageView with effects applied

I have created a CollapsablePane which shows an EffectImageView as collapsableContent, and a Node as mainContent. The EffectImageView consists of two layered ImageViews, the bottom one having an BoxBlur effect applied on it.
When there is a ScrollEvent on the mainContent the collapsableContent will be animated accordingly by setTranslateY.
With a BoxBlur effect applied, the translation of the lower part of the collapsableContent is very unsmooth, while it is absolutely smooth without the effect.
Is there a possibility to improve the transition performance?
public class EffectImageView extends Pane {
private ImageView img;
private ImageView imgEffect;
private Rectangle clipTop;
private Rectangle clipBottom;
private DoubleProperty imageEffectHeight = new SimpleDoubleProperty();
private double effectOffset;
public EffectImageView() {
img = createCachedImageView();
imgEffect = createCachedImageView();
imgEffect.imageProperty().bind(img.imageProperty());
imgEffect.fitWidthProperty().bind(img.fitWidthProperty());
imgEffect.fitHeightProperty().bind(img.fitHeightProperty());
clipTop = new Rectangle();
clipTop.widthProperty().bind(img.fitWidthProperty());
clipTop.heightProperty().bind(img.fitHeightProperty().subtract(imageEffectHeight).subtract(translateYProperty()));
clipBottom = new Rectangle();
clipBottom.widthProperty().bind(img.fitWidthProperty());
clipBottom.heightProperty().bind(imageEffectHeight);
clipBottom.translateYProperty().bind(heightProperty().subtract(imageEffectHeight).subtract(translateYProperty()));
img.setClip(clipTop);
imgEffect.setClip(clipBottom);
getChildren().addAll(img, imgEffect);
}
private ImageView createCachedImageView() {
ImageView img = new ImageView();
img.setCache(true);
img.setCacheHint(CacheHint.SPEED);
return img;
}
public final ObjectProperty<Image> imageProperty() {
return img.imageProperty();
}
public final Image getImage() {
return img.getImage();
}
public final void setImage(Image image) {
img.setImage(image);
}
public void setImageEffect(Effect effect) {
imgEffect.setEffect(effect);
}
public final DoubleProperty imageEffectHeightProperty() {
return imageEffectHeight;
}
public void setEffectOffset(double offset) {
effectOffset = offset;
}
#Override
protected void layoutChildren() {
double w = getWidth();
double h = getHeight();
img.relocate(-effectOffset, 0);
imgEffect.relocate(-effectOffset, 0);
img.setFitWidth(w + effectOffset * 2);
img.setFitHeight(h);
}
}

Sliding JPanel with Universal Tween Engine

For a few days I have been trying to create a JPanel, that comes flying in from the side. I found the Universal Tween Engine and also saw a few demos but for some reason I was never able to make it work in my own code. For the sake of simplicity let's just attempt to move a JPanel (containing an image in a JLabel) from (0,0) to (600,0) on a JFrame. This is what I've got so far and the closest I have ever gotten to actually moving things with this framework, all it does it make the JPanel jump to its destination within the first tick or so. It is supposed to be so simple but I must be missing something...
SlideTest.java - Creating the UI, initializing the Thread + Tween
public class SlideTest {
TweeningPane p;
public TweenManager tweenManager;
public static void main(String[] args) {
new SlideTest();
}
public SlideTest() {
try {
setupGUI();
} catch (IOException e) {
e.printStackTrace();
}
tweenManager = new TweenManager();
AnimationThread aniThread = new AnimationThread();
aniThread.setManager(tweenManager);
aniThread.start();
Tween.to(p, 1, 10.0f).target(600).ease(Quad.OUT).start(tweenManager);
}
public void setupGUI() throws IOException {
JFrame f = new JFrame();
f.setSize(800, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
p = new TweeningPane();
JLabel l = new JLabel(new ImageIcon("E:/Pictures/Stream/aK6IX4V.png"));
f.setLayout(null);
p.add(l);
p.setBounds(0, 0, 300, 300);
f.add(p);
f.setVisible(true);
}
}
AnimationThread.java - The Thread, that is supposed to keep my TweenManager updated as much/often as possible
public class AnimationThread extends Thread {
TweenManager tm;
public void setManager(TweenManager tweenmanager) {
this.tm = tweenmanager;
}
public void run() {
while (true) {
//System.out.println("MyThread running");
tm.update(MAX_PRIORITY);
try {
sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
TweeningPane.java - My Object(JPanel), I want to move across the JPanel
public class TweeningPane extends JPanel implements TweenAccessor<JPanel> {
private static final long serialVersionUID = 1L;
#Override
public int getValues(JPanel arg0, int arg1, float[] arg2) {
return (int) arg0.getBounds().getX();
}
#Override
public void setValues(JPanel arg0, int arg1, float[] arg2) {
arg0.setBounds((int) arg2[0], 0, 300, 300);
}
}
I have finally figured it out. I was simply using the framework in a wrong way as I expected. I'm not sure whether all these steps were needed but this is what I went through in order to make it work: (for future reference)
I had to register my accessor to the engine:
Tween.registerAccessor(TweeningPane.class, new TweeningPane());
And the thread itself now looks like this; I had to give the manager's update method the elapsed time as a parameter.
public void run() {
long ms1 = System.currentTimeMillis();
while (true) {
//System.out.println("MyThread running");
tm.update((System.currentTimeMillis() - ms1) / 1000f);
try {
Thread.sleep(40);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

call method from a method within the same class

I have a platformer class that creates a window and spawns platforms and a "character". It uses another class platform to make platforms. The character is supposed to jump up and land on the platforms. I use the getBounds and getTopY functions for collision detection but they only work for the first platform. How can i get them to work for multiple platforms?
public class Platformer extends JPanel {
Platform platform = new Platform(this);
Character character = new Character(this);
public Platformer() {
addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
character.keyTyped(e);
}
#Override
public void keyReleased(KeyEvent e) {
character.keyReleased(e);
}
#Override
public void keyPressed(KeyEvent e) {
character.keyPressed(e);
}
});
setFocusable(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
platform.Location(150,200);
platform.paint(g2d);
platform.Location(200,120);
platform.paint(g2d);
character.paint(g2d);
}
private void move(){
character.move();
}
public static void main(String args[]){
JFrame frame = new JFrame("Mini Tennis");
//create new game
Platformer platformer = new Platformer();
//add game
frame.add(platformer);
//size
frame.setSize(400, 400);
frame.setVisible(true);
//set close condition
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while (true) {
platformer.move();
platformer.repaint();
try {
Thread.sleep(10);//sleep for 10 sec
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}
public class Platform {
private static final int Height = 10;
private static final int Width = 60;
int x;
int Y;
private Platformer platformer;
public Platform(Platformer platformer) {
this.platformer = platformer;
}
public void Location(int xin, int yin) {
x = xin;
Y = yin;
}
public void paint(Graphics2D g) {
g.fillRect(x, Y, Width, Height);
}
public Rectangle getBounds() {
return new Rectangle(x, Y, Width, Height);
}
public int getTopPlat() {
return Y;
}
}
Actually you have only one platform. And you draw this platform twice in different places (paint function in Platformer):
platform.Location(150,200);
platform.paint(g2d);
platform.Location(200,120);
platform.paint(g2d);
Therefore I suppose you handle only one platform (with coordinates 200 and 120). You must keep all of your platforms and handle each of them separately.

How to load fast an image URL into android grid view?

I have this following codes for displaying few url images into my android grid view. the problem is, it takes a lot of time just to display few numbers of images into my grid view. These are my codes:
public class GridViewImageAdapter extends BaseAdapter {
private Activity activity;
private ArrayList<HashMap<String, String>> galleryAttributes = new ArrayList<HashMap<String, String>>();
private int imageWidth;
int ctr = 0;
public GridViewImageAdapter(Activity activity,
ArrayList<HashMap<String, String>> galleryAttributes, int imageWidth) {
this.activity = activity;
this.galleryAttributes = galleryAttributes;
this.imageWidth = imageWidth;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return galleryAttributes.size();
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return galleryAttributes.get(position);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ImageView imageView;
if(convertView == null){
imageView = new ImageView(activity);
}else{
imageView = (ImageView) convertView;
}
LoadImage loadImage = new LoadImage();
try {
Bitmap image = loadImage.execute(galleryAttributes.get(position).get("Link")).get();
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new GridView.LayoutParams(imageWidth, imageWidth));
imageView.setImageBitmap(image);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return imageView;
}
public class LoadImage extends AsyncTask<String, String, Bitmap>{
#Override
protected Bitmap doInBackground(String... params) {
// TODO Auto-generated method stub
try{
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream((InputStream) new URL(params[0]).getContent(), null, o);
final int REQUIRED_WIDTH = imageWidth;
final int REQUIRED_HEIGHT = imageWidth;
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_WIDTH
&& o.outHeight / scale / 2 >= REQUIRED_HEIGHT)
scale *= 2;
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream((InputStream) new URL(params[0]).getContent(), null, o2);
}
catch(Exception e){
e.printStackTrace();
}
return null;
}
}
Try to use picasso
http://square.github.io/picasso/
This library will cache the picture that downloaded from the URL and next time you open it, it will loaded much more faster because you didn't need to download it again but just take it from the cache.
If the initial displaying is also slow, try to resizing it to reasonable size.
The usage is also pretty easy :
Picasso.with(context)
.load(url)
.resize(50, 50)
.centerCrop()
.into(imageView)
You can user Glide or Picasso.
But Glide is having thumbnail support too.
Glide.with(this)
.load(galleryAttributes.get(position).get("Link"))
.thumbnail(0.1f)
.into(imageView);
Picasso.with(this).load(galleryAttributes.get(position).get("Link")).into(imageView);

Resources