switching images dynamically on jframe - java

I have an assignment to create a GUI that switches images when a menu item is selected (ex. file, new picture) and also contains buttons for zooming in and out on the images. When I try switching images with my code, the image only partly loads. When I minimize the window and then reopen it, the image is fully loaded. I'm wondering why this is happening.
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import java.io.*;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
public class ImageZoom extends JPanel {
private Image image;
int x, y;
private JButton zoomIn;
private JButton zoomOut;
private JMenuBar bar;
private JMenu file;
private JMenuItem choosePic = new JMenuItem("New Picture");
private String pics[] = {"waterfall.jpg", "mountains.jpg"};
private int picIndex = 1;
int imageHeight = getHeight();
int imageWidth = getWidth();
int zoom = 1;
Image images[] = new Image[2];
public ImageZoom() {
try {
images[0] = ImageIO.read(new File("waterfall.jpg"));
images[1] = ImageIO.read(new File("mountains.jpg"));
} catch (IOException e) {}
zoomIn = new JButton("+");
zoomOut = new JButton("-");
JPanel panel = new JPanel();
bar = new JMenuBar();
file = new JMenu("File");
file.add(choosePic);
bar.add(file);
choosePic.addActionListener (new ActionListener() {
public void actionPerformed (ActionEvent e) {
if (e.getSource() == choosePic) {
repaint();
}
}
});
zoomIn.addActionListener (new ActionListener() {
public void actionPerformed (ActionEvent e) {
if (e.getSource() == zoomIn) {
if (zoom < 6) {
zoom += 1;
repaint();
}
}
}
});
zoomOut.addActionListener( new ActionListener() {
public void actionPerformed (ActionEvent e) {
if (e.getSource() == zoomOut) {
if (zoom > 1) {
zoom -= 1;
repaint();
}
}
}
});
}
public JPanel getButtonPanel () {
JPanel panel = new JPanel();
panel.add(zoomIn);
panel.add(zoomOut);
return panel;
}
public Image getImage() {
try {
image = ImageIO.read(new File(pics[picIndex % 2]));
picIndex++;
}
catch (IOException e){}
return image;
}
protected void paintComponent (Graphics g) {
imageHeight = getHeight() * zoom;
imageWidth = getWidth() * zoom;
super.paintComponent(g);
g.drawImage(getImage(), 0, 0, imageWidth, imageHeight, null);
}
public void createJFrame () {
JFrame frame = new JFrame();
ImageZoom imgZoom = new ImageZoom();
frame.setJMenuBar(bar);
frame.add(imgZoom);
frame.add(getButtonPanel(), BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(650, 650);
frame.setResizable(false);
frame.setVisible(true);
}
}
class Test {
public static void main (String[] args) {
ImageZoom zoom = new ImageZoom();
zoom.createJFrame();
}
}

For simplicity, you should just be using a JLabel and calling its setIcon method to switch the images. You could dynamically scale the images as required (just maintain a reference to the original)
Problem #1
You should be passing this to drawImage, this will allow the component to act as the ImageObserver and schedule additional reprints as required based on events from the image's state, which leads to
Problem #2
You should not be calling getImage from within the paintComponent method, paintComponent could be called for any number of reasons, many of which you don't control or even know about and paintComponent should simply paint the current state of the component and never, ever try and change the state
Side Note: Instead of repeatedly trying to load the images, it would be better to load them once and continue to reuse the loaded reference

Related

paintComponent not called when I scroll both Horizontal and Vertical scrollbars in a JScrollPane

I am having trouble with Swing and the JScrollPane.
I am having a strange behaviour.
I extended JScrollPane. I display an image in it and draw rectangles over it to define areas.
With a big image, I have an Horizontal and a Vertical scrollbars.
I - ok - When I move one scrollbar or the other I see my image move too as it should.
II - not ok - When I move one scrollbar an leave it in between max and min position, then when I move my second scrollbar my image disappears.
With some debug prints, I found out that paintComponent, is not called when in case II.
I would like to know why it is not calling paintComponent and how I can fix it.
Here below is my class:
package GUI;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import javax.swing.JScrollPane;
public class DrawingPanel extends JScrollPane {
private static final long serialVersionUID = 1L;
private static final Color DRAWING_COLOR = new Color(255, 100, 200);
private static final Color FINAL_DRAWING_COLOR = Color.red;
private static final double ZOOMING_STEP = 1.1;
private Image sImg;
private Point startPt;
private Point endPt;
private Point currentPt;
private int prefW;
private int prefH;
private double zoomFactor = 1;
private boolean zoomer = false;
private boolean loaded = false;
public DrawingPanel() {
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void loadImage(Image img) {
sImg = img;
prefW = sImg.getWidth(null);
prefH = sImg.getHeight(null);
zoomFactor = getSize().getWidth() / prefW;
zoomer = true;
loaded = true;
repaint();
revalidate();
}
int countPaint = 0;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("paintComponent " + countPaint);
if (loaded) {
int zoomWidth = (int) (prefW * zoomFactor);
int zoomHeight = (int) (prefH * zoomFactor);
if (zoomer) {
((Graphics2D) g).scale(zoomFactor, zoomFactor);
setSize(zoomWidth, zoomHeight);
zoomer = false;
}
g.drawImage(sImg, 0, 0, zoomWidth, zoomHeight, null);
drawRectangle(g);
}
g.dispose();
countPaint++;
}
#Override
public Dimension getPreferredSize() {
return loaded ?
this.getSize() :
new Dimension((int) (prefW*zoomFactor), (int) (prefH*zoomFactor));
}
private void drawRectangle(Graphics g) {
Point secondPoint = (currentPt != null) ? currentPt : endPt;
Color color = (currentPt != null) ? DRAWING_COLOR : FINAL_DRAWING_COLOR;
if (startPt!=null && secondPoint!=null) {
int x = Math.min(startPt.x, secondPoint.x);
int y = Math.min(startPt.y, secondPoint.y);
int rectangleWidth = Math.abs(startPt.x - secondPoint.x);
int rectangleHeight = Math.abs(startPt.y - secondPoint.y);
g.setColor(color);
g.drawRect(x, y, rectangleWidth, rectangleHeight);
}
}
public void deleteRectangle(){
startPt = null;
endPt = null;
}
public void increaseZoom(Point p) {
double oldZoom = zoomFactor;
zoomFactor *= ZOOMING_STEP;
repositonPointAfterZoom(oldZoom, zoomFactor);
}
public void decreaseZoom(Point p) {
double oldZoom = zoomFactor;
zoomFactor /= ZOOMING_STEP;
repositonPointAfterZoom(oldZoom, zoomFactor);
}
public void repositonPointAfterZoom(double oldZoom, double newZoom) {
double evolution = newZoom/oldZoom;
if (startPt!=null) {
startPt.setLocation(startPt.x * evolution, startPt.y * evolution);
}
if (endPt!=null) {
endPt.setLocation(endPt.x * evolution, endPt.y * evolution);
}
repaint();
}
// Getter et setter
public void setStartPt(Point startPt) {
this.startPt = startPt;
}
public void setEndPt(Point endPt) {
this.endPt = endPt;
}
public void setCurrentPt(Point currentPt) {
this.currentPt = currentPt;
}
public int getZoomCalculateX(int value){
return (int) (value / zoomFactor);
}
public int getZoomCalculateY(int value){
return (int) (value / zoomFactor);
}
public void setZoomer(boolean zoomer) {
this.zoomer = zoomer;
}
}
EDIT : Bellow is the class (simplified) that uses DrawingPanel so you can have a reproducible exemple.
package GUI;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.apache.commons.io.FilenameUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import fileHandler.*;
public class GUI {
private JFrame frame;
private MenuBar menubar;
private DrawingPanel panelImage;
private JScrollPane scroll;
private GroundTruth openFile;
private int[] panelImageDown = new int[2];
private int[] panelImageUp = new int[2];
private Menu CoordinateMenu1 = new Menu();
private Menu CoordinateMenu2 = new Menu();
private int actualPagePdf;
private PDFRenderer renderer;
public static void main(String[] args) throws IOException {
new GUI();
}
public GUI() throws IOException {
JFrame frame = CreateFrame();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JFrame CreateFrame() throws IOException {
frame = new JFrame();
frame.setMenuBar(CreateMenuBar());
frame.setContentPane(SplitScreen());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("GTA - Ground Truth Annotator");
frame.setExtendedState(frame.getExtendedState() | JFrame.MAXIMIZED_BOTH);
return frame;
}
private MenuBar CreateMenuBar() {
menubar = new MenuBar();
menubar.add(CreateFileMenu());
menubar.add(new Menu("Selection coordinates:"));
menubar.add(CoordinateMenu1);
menubar.add(new Menu("Width/Height:"));
menubar.add(CoordinateMenu2);
return menubar;
}
private Menu CreateFileMenu() {
Menu mFile = new Menu("File");
MenuItem miOpenImage = new MenuItem("Open Image/PDF File");
mFile.add(miOpenImage);
miOpenImage.addActionListener(OpenFileActionListener);
mFile.addSeparator();
MenuItem miExit = new MenuItem("Exit Program");
mFile.add(miExit);
miExit.addActionListener(ExitActionListener);
return mFile;
}
private JPanel SplitScreen() throws IOException {
JPanel splittedScreen = new JPanel(new GridLayout(1, 2));
splittedScreen.add(CreateLeftPanel());
splittedScreen.add(CreateRightPanel());
return splittedScreen;
}
private JLayeredPane CreateLeftPanel() throws IOException {
JLayeredPane panel = new JLayeredPane();
panel.setLayout(new BorderLayout());
panel.setBorder(BorderFactory.createLineBorder(Color.gray));
panel.add(CreateImageScrollPane());
return panel;
}
private JScrollPane CreateImageScrollPane() throws IOException {
scroll = new JScrollPane(CreateImagePanel((String) null));
scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scroll.getViewport().setScrollMode(JViewport.BLIT_SCROLL_MODE);
return scroll;
}
private DrawingPanel CreateImagePanel(String path) throws IOException {
if (panelImage == null) {
panelImage = new DrawingPanel();
}
if (path != null) {
panelImage.loadImage(ImageIO.read(new File(path)));
}
panelImage.addMouseListener(PanelImageMouseListener);
panelImage.addMouseWheelListener(PanelImageMouseWheelListener);
panelImage.addMouseMotionListener(PanelImageMouseMotionAdapter);
panelImage.setOpaque(false);
panelImage.revalidate();
panelImage.repaint();
panelImage.requestFocus();
return panelImage;
}
private DrawingPanel CreateImagePanel(Image image) throws IOException {
if (panelImage == null) {
panelImage = new DrawingPanel();
}
panelImage.loadImage(image);
panelImage.addMouseListener(PanelImageMouseListener);
panelImage.addMouseWheelListener(PanelImageMouseWheelListener);
panelImage.addMouseMotionListener(PanelImageMouseMotionAdapter);
panelImage.setOpaque(false);
panelImage.revalidate();
panelImage.repaint();
return panelImage;
}
private JPanel CreateRightPanel() {
JPanel panel = new JPanel(new GridLayout(0, 1));
//...
return panel;
}
ActionListener OpenFileActionListener = new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
OpenFile();
}
};
ActionListener ExitActionListener = new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Object[] options = {"Yes, quit now", "No, go back"};
int n = JOptionPane.showOptionDialog(
frame, "ATTENTION: closing without saving will cause any unsaved files to be lost. Do you want to proceed?",
"Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]
);
switch (n) {
case JOptionPane.YES_OPTION:
System.exit(0);
case JOptionPane.NO_OPTION:
case JOptionPane.CANCEL_OPTION:
}
}
};
MouseListener PanelImageMouseListener = new MouseListener() {
public void mousePressed(MouseEvent me) {
panelImageDown = new int[]{
panelImage.getZoomCalculateX(me.getX()), panelImage.getZoomCalculateY(me.getY())
};
panelImageUp = null;
CoordinateMenu1.setLabel(String.format("%s:%s", panelImageDown[0], panelImageDown[1]));
CoordinateMenu2.setLabel("");
panelImage.setStartPt(me.getPoint());
panelImage.repaint();
}
public void mouseReleased(MouseEvent me) {
panelImageUp = new int[]{
Math.abs(panelImage.getZoomCalculateX(me.getX()) - panelImageDown[0]),
Math.abs(panelImageDown[1] - panelImage.getZoomCalculateY(me.getY()))
};
CoordinateMenu2.setLabel(String.format("%s:%s", panelImageUp[0], panelImageUp[1]));
panelImage.setEndPt(me.getPoint());
panelImage.setCurrentPt(null);
panelImage.repaint();
}
public void mouseClicked(MouseEvent arg0) {
}
public void mouseEntered(MouseEvent arg0) {
}
public void mouseExited(MouseEvent arg0) {
}
};
MouseMotionAdapter PanelImageMouseMotionAdapter = new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent me) {
panelImageUp = new int[]{
Math.abs(panelImage.getZoomCalculateX(me.getX()) - panelImageDown[0]),
Math.abs(panelImageDown[1] - panelImage.getZoomCalculateY(me.getY()))
};
CoordinateMenu2.setLabel(String.format("%s:%s", panelImageUp[0], panelImageUp[1]));
panelImage.setCurrentPt(me.getPoint());
panelImage.repaint();
}
};
MouseWheelListener PanelImageMouseWheelListener = new MouseWheelListener() {
public void mouseWheelMoved(MouseWheelEvent me) {
if (me.isAltDown()) {
if (me.getWheelRotation() < 0) {
panelImage.setZoomer(true);
panelImage.increaseZoom();
panelImage.repaint();
panelImage.requestFocus();
//scroll.repaint();
//Zoom out
} else if(me.getWheelRotation() > 0) {
panelImage.setZoomer(true);
panelImage.decreaseZoom();
panelImage.repaint();
panelImage.requestFocus();
//scroll.repaint();
}
}
}
};
private void OpenFile() {
openFile = new GroundTruth();
JFileChooser fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(new File(System.getProperty("user.home")));
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
fileChooser.setAcceptAllFileFilterUsed(false);
fileChooser.addChoosableFileFilter(new FileNameExtensionFilter(
"Images / PDF Scan",
"bmp", "jpeg", "jpg", "png", "tif", "tiff", "pdf"
));
if (fileChooser.showOpenDialog(frame) != 0) {
return;
}
openFile.setFilename(fileChooser.getSelectedFile().getAbsolutePath());
if (getExtension(fileChooser.getSelectedFile().getName()).equals("pdf")) {
try {
PDDocument doc = PDDocument.load(fileChooser.getSelectedFile());
numberPagePdf = doc.getNumberOfPages();
actualPagePdf = 0;
renderer = new PDFRenderer(doc);
setPdfPage(actualPagePdf);
} catch (IOException e) {
e.printStackTrace();
}
} else {
try {
CreateImagePanel(fileChooser.getSelectedFile().getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void setPdfPage(int pageNumber){
try {
BufferedImage bim = renderer.renderImageWithDPI(pageNumber, 300);
refreshInfoPageSection();
CreateImagePanel(bim);
} catch (IOException e) {
e.printStackTrace();
}
}
// refresh the label who indicate the page display and set visible or inivisble the previous and next button
private void refreshInfoPageSection(){
panelImage.deleteRectangle();
}
public String getExtension(String filename) {
return FilenameUtils.getExtension(filename);
}
}
Here's a simplified example of a drawing JPanel that's larger than the scrolling JPanel.
You can see in the image that the drawing JPanel is larger both horizontally and vertically than the scrolling JPanel.
I don't call the paintComponent method at all in this code. Because I set up the GUI properly, Swing itself calls the repaint method when you move the scroll bars.
Here are the important things I did.
I started the Swing GUI with a call to the SwingUtilities invokeLater method. This method makes sure that the Swing components are created and executed on the Event Dispatch Thread.
I used a JFrame, two JPanels, and a JScrollPane. I extended JPanel to create the drawing panel. I used a JScrollPane, JPanel, and JFrame. The only time you extend a Swing component, or any Java class, is when you want to override one or more class methods.
I used Swing layout managers. I used a BorderLayout for the JFrame and scrolling JPanel.
Here's the complete runnable code. Why, you can even call it a minimal reproducible example!
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class LargeDrawingPanel implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new LargeDrawingPanel());
}
#Override
public void run() {
JFrame frame = new JFrame("Large Drawing Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
panel.setPreferredSize(new Dimension(400, 400));
JScrollPane scrollPane = new JScrollPane(new DrawingPanel());
panel.add(scrollPane, BorderLayout.CENTER);
return panel;
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
public DrawingPanel() {
this.setBackground(Color.WHITE);
this.setPreferredSize(new Dimension(2000, 2000));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
int x = 100;
int y = 100;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
g.fillRect(x, y, 100, 100);
x += 200;
}
y += 200;
x = 100;
}
}
}
}
Edited to add: The OP posted additional questions in a comment.
Thanks for the example but it doesn't show me how to print an image in
a JPanel.
Pretty simple. Read an image using the ImageIO class, save the image in an application model consisting of one or more plain Java getter / setter classes and use the Graphics drawImage method to draw the image.
Your preview has only one scrollbar moved not both - which is my
problem.
Did you actually run the code I provided? I can only move one scrollbar at a time. The drawing JPanel extends both horizontally and vertically.
And it doesn't explain why my example doesn't work.
Your example is riddled with errors. Start over, building a Swing application one Swing component at a time using sound principles. The Oracle tutorial, Creating a GUI With JFC/Swing, will show you the correct way to create a Swing application. You can skip the Netbeans section.

Adding animations to JPanel

I've written some code that essentially animates a sequence of images and adds them to a frame when I run the file.
I want to implement a functionality where I can add this animation to two different areas of a JPanel that has a BorderLayout (North and West).
I want to do this using a button but I don't know how to do that. I am new to event handling and layout managers.
How do I go about this?
My code for the animation:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ImageSequence extends JPanel implements ActionListener {
private ImageSQPanel imageSQPanel;
private static int frameNumber = -1;
private Timer timer;
private void buildUI(Container container, Image[] arrows) {
int fps = 10;
int delay = 1000 / fps;
timer = new Timer(delay, this);
timer.setInitialDelay(0);
timer.setCoalesce(true);
imageSQPanel = new ImageSQPanel(arrows);
container.add(imageSQPanel, BorderLayout.CENTER);
}
private synchronized void startAnimation() {
if (!timer.isRunning()) {
timer.start();
}
}
public void actionPerformed(ActionEvent e) {
frameNumber++;
imageSQPanel.repaint();
}
class ImageSQPanel extends JPanel {
Image arrowAnimation[];
ImageSQPanel(Image[] arrowAnimation) {
this.arrowAnimation = arrowAnimation;
}
//Draw the current frame of animation.
public void paintComponent(Graphics g) {
super.paintComponent(g); //paint background
//Paint the frame into the image.
try {
g.drawImage(arrowAnimation[ImageSequence.frameNumber % 10], 0, 0, this);
} catch (ArrayIndexOutOfBoundsException e) {
//On rare occasions, this method can be called
//when frameNumber is still -1. Do nothing.
}
}
}
//Invoked only when this is run as an application.
public static void main(String[] args) {
Image[] waving = new Image[7];
for (int i = 1; i <= 7; i++) {
waving[i - 1] = Toolkit.getDefaultToolkit().getImage(
"/Users/sarthaksachdeva/Documents/IntelliJ Projects/Animation/src/images/Arrow" + i + ".png");
}
JFrame f = new JFrame("ImageSequenceTimer");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
ImageSequence controller = new ImageSequence();
controller.buildUI(f.getContentPane(), waving);
controller.startAnimation();
f.setSize(new Dimension(200, 200));
f.setVisible(true);
}
}

how to pass value to rotate method on menu item click?

i am developing application of rotating image.
as user click menu item as per that image should be rotate.
right now i have implemented keyboard listener, in which as user press right to left button it moves but i want to change that method and want as per menu item click.
right now it passes degrees variable to method rotate, now i want to custom that and as user click menu item it pass the value.
i don't know how to do.
my code:
public class RotateIMGn extends JPanel {
private static final long serialVersionUID = 1L;
ImageIcon image = new ImageIcon("D://Workspace//ScaleImage//src//images//img.png");
JLabel label = new JLabel(image);
JPanel rotationPanel;
final int WIDTH = 350;
final int HEIGHT = 500;
double degrees;
public RotateIMGn() {
setPreferredSize(new Dimension(446, 500));
setFocusable(true);
addKeyListener(new KeyboardListener());
rotationPanel = new JPanel();
rotationPanel = new turningCanvas();
rotationPanel.setPreferredSize(new Dimension(image.getIconWidth(), image.getIconHeight()));
add(rotationPanel);
JMenuBar menuBar = new JMenuBar();
add(menuBar);
JMenu mnFile = new JMenu("Rotate");
menuBar.add(mnFile);
ImageIcon icon90 = createImageIcon("/images/images_Right.png");
JMenuItem mntmTR90 = new JMenuItem("Rotate 90+", icon90);
mntmTR90.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
try {
} catch (Exception e) {
e.printStackTrace();
}
}
});
mnFile.add(mntmTR90);
ImageIcon icon180 = createImageIcon("/images/images_Vertical.png");
JMenuItem mntmRT180 = new JMenuItem("Rotate 180+", icon180);
mnFile.add(mntmRT180);
JSeparator separator = new JSeparator();
mnFile.add(separator);
ImageIcon micon90 = createImageIcon("/images/images_Left.png");
JMenuItem mntmTRM90 = new JMenuItem("Rotate 90-", micon90);
mnFile.add(mntmTRM90);
ImageIcon micon180 = createImageIcon("/images/images_Horizontal.png");
JMenuItem mntmRTM180 = new JMenuItem("Rotate 180-", micon180);
mnFile.add(mntmRTM180);
rotationPanel.setBounds(WIDTH / 2, HEIGHT / 2,
rotationPanel.getPreferredSize().width,
rotationPanel.getPreferredSize().height);
degrees = 0;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
public class turningCanvas extends JPanel {
private static final long serialVersionUID = 1L;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.rotate(Math.toRadians(degrees), image.getIconWidth() / 2,
image.getIconHeight() / 2);
image.paintIcon(this, g2d, 0, 0);
}
}
public class KeyboardListener implements KeyListener {
public void keyPressed(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.VK_LEFT) {
degrees--;
repaint();
}
if (event.getKeyCode() == KeyEvent.VK_RIGHT) {
degrees++;
repaint();
}
}
public void keyTyped(KeyEvent event) {
}
public void keyReleased(KeyEvent event) {
}
}
public static void main(String[] args) {
RotateIMGn test = new RotateIMGn();
JFrame frame = new JFrame();
frame.setContentPane(test);
frame.pack();
frame.setVisible(true);
}
protected static ImageIcon createImageIcon(String path) {
java.net.URL imgURL = RotateIMGn.class.getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
}
anyone's idea will help me a lot so...
Use Swing Actions for the menu items instead of Strings. Then, in the actionPerformed method, update the degreesvariable, as you do your KeyListener.
Something like:
ImageIcon icon90 = createImageIcon("/images/images_Right.png");
JMenuItem mntmTR90 = new JMenuItem(new AbstractAction("Rotate 90+", icon90) {
public void actionPerformed(ActionEvent e) {
degrees += 90;
repaint();
}
});

Strange JFrame Behavior

I have the following program which has some very strange and unwanted behavior when it runs. Its supposed to have two buttons, "Start" and "Stop, but when I click "Start" another button shows up right below "Start". Here's a print screen of what I'm talking about:
What am I doing wrong and how do I fix this ugly problem?
Here's the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
public class TwoButtonsTest {
JFrame frame;
Timer timer;
boolean isClicked;
public static void main(String[] args) {
TwoButtonsTest test = new TwoButtonsTest();
test.go();
}
public void go() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
JButton startButton = new JButton("Start");
startButton.addActionListener(new StartListener());
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(new StopListener());
final DrawPanel myDraw = new DrawPanel();
frame.getContentPane().add(BorderLayout.CENTER, myDraw);
frame.getContentPane().add(BorderLayout.NORTH, startButton);
frame.getContentPane().add(BorderLayout.SOUTH, stopButton);
frame.setVisible(true);
timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
myDraw.repaint();
}
});
}
class StartListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//needs to be implemented
if(!isClicked) {
}
isClicked = true;
timer.start();
}
}
class StopListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//needs to be implemented
timer.stop();
isClicked = false;
}
}
class DrawPanel extends JPanel {
public void paintComponent(Graphics g) {
int red = (int)(Math.random()*256);
int blue = (int)(Math.random()*256);
int green = (int)(Math.random()*256);
g.setColor(new Color(red, blue, green));
Random rand = new Random();
// following 4 lines make sure the rect stays within the frame
int ht = rand.nextInt(getHeight());
int wd = rand.nextInt(getWidth());
int x = rand.nextInt(getWidth()-wd);
int y = rand.nextInt(getHeight()-ht);
g.fillRect(x,y,wd,ht);
}
} // close inner class
}
Also I'm trying to get the Start button to do two things. One is to of course start the animation but when the Stop button is pressed and I press Start again, I want it to clean the screen so to speak and start the animation again a new. Any tips on that?
You do not call super.paintComponent(Graphics g) in overriden paintComponent(..) method which you should in order to honor the paint chain and thus the painting of other components.
This call should also be the first call within the method:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//do painting here
}
A probem might arise that drawings are not persistent. You must than have a way to store drawings and redraw every time. The most common is an ArrayList which will hold objects to be drawn (thus you cann add to the list remove etc), you would than iterate over the list and redraw each object in paintComponent. See my answer here for an example.
Also please remember to create and manipulate Swing components on Event Dispatch Thread :
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//create UI and components here
}
});
Dont call setSize(..) on JFrame rather override getPreferredSize() of JPanel and return an appropriate height which fits all components, than call JFrame#pack() before setting JFrame visible (but after adding all components).
No need for getContentPane().add(..) as of Java 6+ add(..) defaults to contentPane
Do not re declare Random i.e Random r=new Random() each time paintComponent is called as this will make the distributions of the values less random rather initiate it once when class is created and call methods on the instance
Here is the fixed code (with above fixes implemented):
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.*;
public class TwoButtonsTest {
JFrame frame;
Timer timer;
boolean isClicked;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TwoButtonsTest test = new TwoButtonsTest();
test.go();
}
});
}
final DrawPanel myDraw = new DrawPanel();
public void go() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton startButton = new JButton("Start");
startButton.addActionListener(new StartListener());
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(new StopListener());
frame.add(myDraw, BorderLayout.CENTER);
frame.add(startButton, BorderLayout.NORTH);
frame.add(stopButton, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
myDraw.repaint();
}
});
}
class StartListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
//needs to be implemented
if (!isClicked) {
}
myDraw.clearRects();
isClicked = true;
timer.start();
}
}
class StopListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//needs to be implemented
timer.stop();
isClicked = false;
}
}
class DrawPanel extends JPanel {
private ArrayList<MyRectangle> rects = new ArrayList<>();
private Random rand = new Random();
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
addRect();
for (MyRectangle r : rects) {
g.setColor(r.getColor());
g.fillRect(r.x, r.y, r.width, r.height);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
public void clearRects() {
rects.clear();
}
public void addRect() {
// following 4 lines make sure the rect stays within the frame
int ht = rand.nextInt(getHeight());
int wd = rand.nextInt(getWidth());
int x = rand.nextInt(getWidth() - wd);
int y = rand.nextInt(getHeight() - ht);
int red = (int) (Math.random() * 256);
int blue = (int) (Math.random() * 256);
int green = (int) (Math.random() * 256);
rects.add(new MyRectangle(x, y, wd, ht, new Color(red, blue, green)));
}
} // close inner class
}
class MyRectangle extends Rectangle {
Color color;
public MyRectangle(int x, int y, int w, int h, Color c) {
super(x, y, w, h);
this.color = c;
}
public Color getColor() {
return color;
}
}
I wish I could offer a solution, but as of yet I haven't found one. I can tell you the root of the "problem" here lies in the way you are drawing the Center section of your BorderLayout. You are overriding the whole paintComponent() function for this program and having whatever it creates put into the Center of your BoarderLayout. In this case, each time you click a button, the program calls the repaint to draw the image of a clicked button, but since you have also added ANY of the drawn objects to the Center panel, it also is drawn there. Since this specific repaint doesn't specify a location, it goes in the upper left corner.
I fixed your button problem on my Windows XP computer by invoking SwingUtilities.
I formatted your Java code.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class TwoButtonsTest implements Runnable {
JFrame frame;
Timer timer;
boolean isClicked;
public static void main(String[] args) {
SwingUtilities.invokeLater(new TwoButtonsTest());
}
#Override
public void run() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
JButton startButton = new JButton("Start");
startButton.addActionListener(new StartListener());
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(new StopListener());
final DrawPanel myDraw = new DrawPanel();
frame.getContentPane().add(BorderLayout.CENTER, myDraw);
frame.getContentPane().add(BorderLayout.NORTH, startButton);
frame.getContentPane().add(BorderLayout.SOUTH, stopButton);
frame.setVisible(true);
timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
myDraw.repaint();
}
});
}
class StartListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
// needs to be implemented
if (!isClicked) {
}
isClicked = true;
timer.start();
}
}
class StopListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
// needs to be implemented
timer.stop();
isClicked = false;
}
}
class DrawPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
int red = (int) (Math.random() * 256);
int blue = (int) (Math.random() * 256);
int green = (int) (Math.random() * 256);
g.setColor(new Color(red, blue, green));
Random rand = new Random();
// following 4 lines make sure the rect stays within the frame
int ht = rand.nextInt(getHeight());
int wd = rand.nextInt(getWidth());
int x = rand.nextInt(getWidth() - wd);
int y = rand.nextInt(getHeight() - ht);
g.fillRect(x, y, wd, ht);
}
} // close inner class
}
To clean the screen when you press the Start button, you're going to have to add some methods to your DrawPanel class.
Here's one way to do it.
class DrawPanel extends JPanel {
protected boolean eraseCanvas;
public void setEraseCanvas(boolean eraseCanvas) {
this.eraseCanvas = eraseCanvas;
}
#Override
public void paintComponent(Graphics g) {
if (eraseCanvas) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
} else {
int red = (int) (Math.random() * 256);
int blue = (int) (Math.random() * 256);
int green = (int) (Math.random() * 256);
g.setColor(new Color(red, blue, green));
Random rand = new Random();
// following 4 lines make sure the rect stays within the frame
int ht = rand.nextInt(getHeight());
int wd = rand.nextInt(getWidth());
int x = rand.nextInt(getWidth() - wd);
int y = rand.nextInt(getHeight() - ht);
g.fillRect(x, y, wd, ht);
}
}
} // close inner class

JButton setIcon Updation error

Currently i m making a java program using netbeans based on changing image in a button....
Actually my requirement is to change the Image icon of a button as i click another button (Say A).....
i came out with the following program........
// Following function is included inside the button's (Here A) ActionListener........
public void change_image()
{
if(sex==0)
{
ic=new ImageIcon("E:\\java_images\\female_profile.jpg");
sex=1;
}
else if(sex==1)
{
ic = new ImageIcon("E:\\java_images\\male_profile.png");
sex=0;
}
// To resize the image into the size of the button...
labelicon.setImage(ic.getImage().getScaledInstance(image_btn.getWidth(),image_btn.getHeight(), Image.SCALE_DEFAULT));
img_btn.setIcon(labelicon);
}
The Variables i've included are
private int sex; // 0 - female, 1 - male
private ImageIcon ic,labelicon; // variables meant for storing ImageIcons.....
private JButton img_btn; // the button at which the image is to be displayed....
Now the Weird Behaviour i observed is.......
The image gets displayed on the button click, only when i click the minimize button.
i.e when the i click the button A, the code specified in the ActionListener is getting executed. But the effect of the image change appears only when i minimize the window and again make it appear on the screen.... Can anyone tell why this is occuring and how can i remove the problem ??
All i want is to change the image the moment i click the A Button.....
Well..i haven't included for the code for creating button since they are easily done by netbeans swing GUI builder......
load Icon / ImageIcon as local variable once time, there no reason to re_loading image from ActionListener
in the API is description that Image#ScaledInstance is pretty asynchronous
otherwise you have to call
.
labelicon.getImage().flush();
img_btn.setIcon(labelicon);
EDIT
#akp wrote but..how would you resize the icon image..??
there are two or three another ways how to put Icon /ImageIcon and will be resiziable with its parent, JLabelcould be easiest of ways
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.swing.*;
public class JButtonAndIcon {
private static JLabel label = new JLabel();
private static Random random = new Random();
private static ImageIcon image1; // returns null don't worry about
private static ImageIcon image2; // returns null don't worry about
private static Timer backTtimer;
private static int HEIGHT = 300, WEIGHT = 200;
public static void main(String[] args) throws IOException {
label.setPreferredSize(new Dimension(HEIGHT, WEIGHT));
final JButton button = new JButton("Push");
button.setBorderPainted(false);
button.setBorder(null);
button.setFocusable(false);
button.setMargin(new Insets(0, 0, 0, 0));
button.setContentAreaFilled(false);
button.setLayout(new BorderLayout());
button.add(label);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (button.getIcon() == image1) {
label.setIcon(image2);
} else {
label.setIcon(image1);
}
}
});
JFrame frame = new JFrame("Test");
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
startBackground();
frame.setVisible(true);
}
private static void startBackground() {
backTtimer = new javax.swing.Timer(750, updateBackground());
backTtimer.start();
backTtimer.setRepeats(true);
}
private static Action updateBackground() {
return new AbstractAction("Background action") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
label.setIcon(new ImageIcon(getImage()));
}
};
}
public static BufferedImage getImage() {
int w = label.getWidth();
int h = label.getHeight();
GradientPaint gp = new GradientPaint(0f, 0f, new Color(
127 + random.nextInt(128),
127 + random.nextInt(128),
127 + random.nextInt(128)),
w, w,
new Color(random.nextInt(128), random.nextInt(128), random.nextInt(128)));
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bi.createGraphics();
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
g2d.setColor(Color.BLACK);
return bi;
}
}
The problem here is that you are updating the internals of an Icon. The setIcon method will think that it's the same icon that the button already has. I would recommend you to do two different Icon objects that to use to update the icon with. That will fix the problems.
Example (with two different icons):
public static void main(String[] args) throws IOException {
final ImageIcon redIcon = createImageIcon(10, 10, Color.RED);
final ImageIcon blueIcon = createImageIcon(10, 10, Color.BLUE);
final JButton button = new JButton("Push", blueIcon);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (button.getIcon() == redIcon)
button.setIcon(blueIcon);
else
button.setIcon(redIcon);
}
});
JFrame frame = new JFrame("Test");
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private static ImageIcon createImageIcon(int w, int h, Color color) {
Image image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
g.setColor(color);
g.fillRect(0, 0, w, h);
g.dispose();
return new ImageIcon(image);
}
Background:
Looking at the source of AbstractButton.setIcon, you can see that it won't know about the update if the reference "isn't updated":
.....
if (defaultIcon != oldValue) {
if (defaultIcon == null || oldValue == null ||
defaultIcon.getIconWidth() != oldValue.getIconWidth() ||
defaultIcon.getIconHeight() != oldValue.getIconHeight()) {
revalidate();
}
repaint();
}
Note to #HarryJoy, you actually had a point even though you didn't know why... :) Sorry! +1 again!
//Call img_btn.revalidate() and img_btn.repaint()
Correction, setIcon should already do this. I use the hacky way of img_btn.setText("<HTML><BODY><IMG SRC=\"/path/to/img.jpg\"/></BODY</HTML>"); personally.

Categories