Java swing jbutton charging old image - java

i created a custom Java Button like this
public class GraphicPaintedButton extends JButton implements ToPaint{
protected BufferedImage background;
private boolean painted = false;
public GraphicPaintedButton() {
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(painted){
System.out.println("PAINTING!");
Dimension size = getSize();
g.drawImage(background, 0, 0,size.width, size.height,0, 0, background.getWidth(), background.getHeight(), null);
}
}
#Override
public void loadImage(String url){
painted = true;
URL imagePath = getClass().getResource(url);
BufferedImage result = null;
try {
result = ImageIO.read(imagePath);
} catch (IOException | IllegalArgumentException e) {
System.err.println("Errore, immagine non trovata");
e.printStackTrace();
}
background = result;
}
}
Iif i load an image on the button, it calls the repaint,and it's good, the image is shown, when i load a new Image, it calls the repaint again and the new Image is shown. The problem is when i pass the mouse over the button, it calls the rapaint, but loads the old image. Why? And how did it get the old image, as the new one should have replaced it?

I don't know why you want to go this extend and not simply use the icon property of the button, but...
First, I'd get rid of the painted flag, it runs the risk of allowing the paintComponent method to try and paint a null image, because the loadImage method may fail, but the painted flag is always set to true - Let's face it, you could easily end up with painted == true and background == null ... which is not a valid state
Instead, reason about the actual state you're interested in...
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
Dimension size = getSize();
g.drawImage(background, 0, 0, size.width, size.height, 0, 0, background.getWidth(), background.getHeight(), null);
}
}
I would also change the loadImage method
public void loadImage(URL url) throws IOException {
background = ImageIO.read(url);
revalidate();
repaint();
}
First, don't use String, it's meaning is to ambiguous, instead, specify the lowest common parameter you're willing to deal with.
Secondly, the image is either going to load or it's not, if you're not going to deal with the exception, in any meaningful fashion, pass it back to the caller who may be in a better position to deal with it - IMHO
I don't know if this important or not, but I'd also consider overriding the getPreferredSize method...
#Override
public Dimension getPreferredSize() {
return background == null ? new Dimension(10, 10) : new Dimension(background.getWidth(), background.getHeight());
}
This will at least try and match the button's size to the size of the image

Related

Issue with drawing png file into swing GUI

I am facing an issue that I am not able to draw an png image into my swing GUI into JPanel (which I am adding into JScrollPane after).
Here is my code I am trying to use for this.
if(processCreated == true){
System.out.println("updating tree of organisms");
processCreated = false;
updateTree();
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Svet.class.getName()).log(Level.SEVERE, null, ex);
}
tree = new File(path+"/out.png"); //File
try {
treeImage = ImageIO.read(tree); //BufferedImage
tp = new TreePane(treeImage.getScaledInstance( 500, 500 ,treeImage.SCALE_SMOOTH)); // my class, implementation below
treeOutput.add(tp); //adding "JPanel" with picture into GUI
treeOutput.repaint();
} catch (IOException ex) {
Logger.getLogger(Svet.class.getName()).log(Level.SEVERE, null, ex);
}
}
After this the JScrollPane remains empty. Is there anything wrong with my code? You can find what is what in comments.
Here is my TreePane class
public class TreePane extends JPanel{
Image img;
public TreePane( Image img ){
this.img = img;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
int imgX = 0;
int imgY = 0;
g.drawImage(img, imgX, imgY, this);
}
}
Very likely your TreePane is layed out to size 0,0 and therefore you'll never see anything. Try adding a breakpoint and inspecting in paintComponent - it might not even ever get called.
To fix, you should explicitly set the size of your TreePane before adding it to the JScrollPane.
tp = new TreePane(treeImage.getScaledInstance( 500, 500 ,treeImage.SCALE_SMOOTH)); // my class, implementation below
tp.setSize(myWidth, myHeight);
treeOutput.add(tp); //adding "JPanel" with picture into GUI
treeOutput.repaint();

Draw on Jframe image

I want to read a file to get some points and then draw these points on an image. Currently, I am able to draw values on the image, but the file is read three times and the rectangles are drawn three times. I don't know where is the problem. Below is the code. The Read() function works fine seperately so I didn't include it in the code.
P.S: I am beginner in JAVA and don't know much about JFrame and Jcomponent.
public class LoadImageApp extends JComponent {
BufferedImage img;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, null);
Read(g);// This is the function in which I read a file.
}
public LoadImageApp() {
try {
img = ImageIO.read(this.getClass().getResource("/New York.jpg"));
} catch (IOException e) {
}
}
public Dimension getPreferredSize() {
if (img == null) {
return new Dimension(100,100);
} else {
return new Dimension(img.getWidth(null), img.getHeight(null));
}
}
public static void main(String[] args) {
JFrame f = new JFrame("Load Image Sample");
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
LoadImageApp img = new LoadImageApp();
f.add(img);
f.pack();
f.setVisible(true);
}
}
Do not, do not, DO NOT read from a file from within any painting method such as paintComponent(...). :)
That method should be for painting only. The more you slow it down, the less responsive your GUI will seem.
You cannot control how many times the method gets called, since it is not under direct control by you, the programmer.
You can't even control fully if the paintComponent method gets called, since the JVM might decide that too many requests for redraw are being stacked up, and it may not honor all of them.
Instead
read in the data once in a constructor or something similar.
I would create a read method that stores my points in an ArrayList<Point>, and then inside of the paintComponent method, iterate through that ArrayList using a for loop and draw them.
If the points don't change during your program's run, you could even draw them directly on to the BufferedImage by getting its Graphics context and using that to paint the points on to the image, and then show the new BufferedImage in your paintComponent method.
Other suggestions:
That empty catch block where you read your image is a dangerous thing to do. It's the coding equivalent of driving a motorcycle with your eyes closed. At least print out a stacktrace.
The WindowListener is not needed. Instead simply set your JFrame's defaultCloseOperation to JFrame.EXIT_ON_CLOSE: f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Image inside JFrame - Swing/AWT

Some days ago, I wasted a lot of time searching some way to show a image in a JFrame. And here is my final solution:
jPanel1 = new javax.swing.JPanel(){
#Override
public void paintComponent(Graphics g) {
BufferedImage image = null;
try {
BufferedImage in = ImageIO.read(Startup.class.getResource("imagem.jpg"));
image = new BufferedImage(in.getWidth(), in.getHeight(), BufferedImage.TYPE_INT_ARGB);
g.drawImage(in, 0, 0, null);
} catch (Exception ex) {}
super.paintComponents(g);
}
};
I just want to know, if it is the one way to do that, or exists another solutions like a image component on Swing o AWT that can be easily used?
You can show an image using JLabel, which is much simpler than your solution. For example:
label.setIcon(new ImageIcon("Path/to/your/image.jpg"));

How do I redraw things when my JFrame is restored (deiconified)?

I have a very basic little JFrame with JToggleButtons and subclassed JPanels that know how to draw what I want them to draw. Selecting a button causes an oval to appear in the corresponding panel. Unselecting the buttons makes the drawings disappear.
Unfortunately, minimizing (iconifying) and then restoring (deiconifying) causes any drawn shapes to disappear. So I need to trigger redrawings manually. The problem is that I can only get the redrawing done (that is, I only see it) if I show a message box first.
Here's the deiconify event for the JFrame:
private void formWindowDeiconified(java.awt.event.WindowEvent evt)
{
//having this message makes everything work
JOptionPane.showMessageDialog(null, "Useless message this is.");
//but if I skip it, I'm SOL
//what's going on?
drawAll();
}
This method goes over all of my buttons and asks for the redraws when necessary:
public void drawAll()
{
for (int i=0; i<channels; i++)
{
if (buttons[i].isSelected())
{
lightboxes[i].drawMe();
}
}
}
and here is my subclassed JPanel:
class MyJPanel extends JPanel {
public void drawMe()
{
Graphics myGraphics = this.getGraphics();
myGraphics.fillOval(0, 0, this.getWidth(), this.getHeight());
}
public void unDraw()
{
this.invalidate();
this.repaint();
}
}
The window should automatically be repainted once it is restored by the RepaintManager. The problem is you are not performing custom painting like you should...
This is not how to do custom painting...
public void drawMe()
{
Graphics myGraphics = this.getGraphics();
myGraphics.fillOval(0, 0, this.getWidth(), this.getHeight());
}
getGraphics can return null and is, at best, a snapshot of the graphics state.
Painting in Swing can occur at any time for many different reasons, most of which you don't have control over (nor should you care).
Your job is simply to respond to these repaint requests and update your components state.
Swing has a detailed paint chain which is called automatically and which you can use.
You should be overriding paintComponent and performing all painting within this method
Take a look at Performing Custom Painting and Painting in AWT and Swing for more details
Firstly, for speed I would use double buffering. It's best to paint your graphics off screen and display them to the screen when the drawing has completed. The below should sort you out.
public class MyPanel extends JPanel {
private BufferedImage buffer;
private Graphics2D canvas;
#Override
public void paintComponent(Graphics g) {
if(buffer == null) {
buffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
canvas = buffer.createGraphics();
}
canvas.fillOval(0, 0, this.getWidth(), this.getHeight());
g.drawImage(buffer, 0, 0, this);
}
}
I'm just providing this answer so people can see what I ended up doing. The major lesson pointed out by everyone was to use the component's paintComponent. See the comments for issues that you might be experiencing yourself.
Edit: Updated to reflect comments from MadProgrammer.
//with help from Slihp and MadProgrammer on StackOverflow
//http://stackoverflow.com/q/17331986/1736461
class MyJPanel extends JPanel {
private boolean buttonSelected = false;
#Override
public void paintComponent(Graphics g) {
//make sure the background gets painted (wacky results otherwise)
super.paintComponent(g);
//now if the corresponding toggle button is on, plop on the circle
if (buttonSelected)
{
g.fillOval(0, 0, this.getWidth(), this.getHeight());
}
}
//an action listener for the button calls this
public void setButtonSelected(boolean buttonStateIn)
{
buttonSelected = buttonStateIn;
}
}
I subclassed the buttons too, so I can get its "ID" off of it from the event handler:
class MyJToggleButton extends JToggleButton
{
private int whoAmI;
public MyJToggleButton(int whoAmIn)
{
//the string given to the constructor becomes the button's label
//("1", "2", "3", etc..)
super(Integer.toString(whoAmIn + 1));
whoAmI = whoAmIn;
}
public int getWho()
{
return whoAmI;
}
}
The JFrame code that makes the buttons:
private void makeButtons(int howMany)
{
buttons = new MyJToggleButton[howMany];
for (int i=0; i<howMany; i++)
{
buttons[i] = new MyJToggleButton(i);
buttons[i].addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
//find out which button this is
MyJToggleButton button = (MyJToggleButton) evt.getSource();
int which = button.getWho();
//send the button state to the corresponding lightbox
lightboxes[which].setButtonSelected(button.isSelected());
//trigger its redrawing
lightboxes[which].invalidate();
lightboxes[which].repaint();
}
});
this.add(buttons[i]);
}
}
And that's the only manual redrawing I have to do - resizing and reshowing and all those other fun things eventually hit up the paintComponent, and it just has to know if its button is pushed to know what to do. Super clean and just what I wanted.

Display image on applet

I am using Jtree for listing various images of a directory, I want to display image on applet when the user click on the image name displayed in the Tree, the code i'm using is as below, ta is an object of the applet because i'm using it in another class.
private void displayImage(URL furl, String fname) {
ta.Picture = ta.getImage(furl, fname);
prepareImage(ta.Picture, this);
Graphics g = ta.imageCanvas.getGraphics();
g.clearRect(10, 10, 800, 800);
g.drawImage(ta.Picture, 10, 10, this);
} // displayImage
public void valueChanged(TreeSelectionEvent e)
{
// TODO Auto-generated method stub
FileTreeNode node = (FileTreeNode) tree.getLastSelectedPathComponent();
System.out.println("slecte asldf " + node.isLeaf());
if (node.isLeaf())
{
currentFile = node.file;
System.out.println("File name " + currentFile.getName());
try
{
URL furl = new URL("file:/F:/photos");
displayImage(furl, currentFile.getName());
}
catch (MalformedURLException mle)
{
System.out.println("Exception::::::" + mle);
}
}
else
currentFile = null;
}
But its not working.
As you are showing files from the local filesystem, working with URLs is not required. Use
displayImage(currentFile);
and rewrite that method as following:
private void displayImage(File file) {
BufferedImage image = ImageIO.read(file);
ta.image = image;
ta.repaint();
}
where the paint method of the (I an assuming) component ta must be like
BufferedImage image;
public void paint(Graphics g) {
g.clearRect(10, 10, 800, 800);
g.drawImage(ta.Picture, 10, 10, this);
}
Because of security reasons, the applet will only be able to access the file system if signed or running without security manager (most often on the same computer).
But its not working.
This is in no way helpful, do you get exceptions? What happens? Please post an SSCCE for better help sooner
I want to display image on applet when the user click on the image
name displayed in the Tree, the code i'm using is as below, ta is an
object of the applet because i'm using it in another class.
IMO you are going about it wrong using the JPanel object and Component#getGraphics.
Dont use Component#getGraphics() as its not good practice and not persistent thus on next call to repaint() the screen will be cleared.
Dont use Applet with Swing components rather use JApplet.
Add a custom JPanel with getters and setters for BufferedImage variable to the container and than override paintComponnet and draw the BufferedImage there.
Now to change the BufferedImage simply call the setter i.e setBackgroundImage(BufferedImage img) and than call repaint() on JPanel to show the changes. Like so:
public class MyPanel extends JPanel {
private BufferedImage bg;
public MyPanel(BufferedImage bi) {
bg=bi;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d=(Graphics2D)g;
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
g2d.drawImage(bg,0,0,this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(bg.getWidth(),bg.getHeight());
}
public BufferedImage setBackgroundImage(BufferedImage bi) {
bg=bi;
}
}
Now we use it like so:
MyPanel mp=new MyPanel(...);//create the panel with an image
...
add(mp);//add to container
...
mp.setBackgroundImage(..);//change the image being displayed
mp.repaint();//so the new image may be painted

Categories

Resources