Reassigning G4P ImageButton image source file programatically

Hello

First I will tell you this is probably a question more about OOP than G4p or Gui Builder. I know little about OOP but enough to think so.

In Gui Builder, I have a simple window and an image button. I enter the source for the picture image I want to use and it shows up finre.

But later in a part of my code I want to update that picture to a new one.

I can get there by creating a new instance of this image button with the new file name replacing the old. This seems an odd way to make a simple update of the button, so I want to ask you for better information. I am having trouble understanding how to make changes repedly.

I am successfully grabbing a snapshot and writing it to a file. but not clear on how to repeatedly update the image button as the enduser repositions the shot and updates again and again. Thanks for help or ideas.

quark @quark

Tagged:

Answers

  • edited September 2015

    I never anticipated someone wanting to change the image of an existing button. It should be possible to extend the GImageButton class and add that functionality.

    1) Is the image you want to use created dynamically, in other words created at runtime?

    2) The image button can have 3 images for mouse off, mouse over and mouse pressed. If there are less than 3 it uses what its given. How many images does yours have?

    3) Somewhere in your code you have a statement to create the button. It will contain the text = new GImageButton (...) copy that line and post it here.

    I will not have access to my computer for a couple of weeks but I might be able to guide to a solution.

  • Answers to Quaerk 1. Picture is captured at after the program is running. I start with a stock photo entered in into a builder so that the image button has a default picture.

    In my sample I have a small window a image button and a standard button. When the normal button is clicked. I am using the line as you describe to load the next picture. The next picture has just been saved by a camera capture sketch and stored as a file.

    The button click event runs a new instance of the image button that is pointed to the new file name. This works, however. It seemed to me that there would be a simpler way to refresh this than to create an it's another instance.

    My question is whether there is a cleaner way to do this, then, creating another instance. I have looked for a method to do a refresh to close the earlier image button and can't come up with any ideas.

    My current method is to simply lay the new image button on top. The old one. And I'm not sure what this does for memory and how it may affect other things.

    I will try to learn about extending the image button control to either update the file name or close the earlier image button.

    I like using the image button because it solves the some of the issues of resizing the photo, however, I'm open to other ideas as I stumble along.

    Thank you!

  • I will try to learn about extending the image button control to either update the file name or close the earlier image button.

    I can help get you started but you need to answer part 3 of my questions above. Repeated here.

    3) Somewhere in your code you have a statement to create the button. It will contain the text = new GImageButton (...) copy that line and post it here.

  • edited September 2015
    public void button1_click1(GButton source, GEvent event) { //_CODE_:button1:546995:
      println("button1 - GButton event occured " + System.currentTimeMillis()%10000000 );
      //String pixFile = "d:/test.jpg"
      imgButton1 = new GImageButton(this, 117, 17, 263, 182, new String[] { pixFile, pixFile,pixFile } );
      snapShot(); //captures a snapshot and saces to piixFile.
      println("Filename: "+pixFile);
    
    } //_CODE_:button1:546995:
    
  • In the creategui() I have no change to the code, It is as GUI Byukder generated. with all three file names set to a stock photo (fenton.jpg)

  • edited September 2015

    The first thing to do is to create a new class in your sketch that extends GImageButton.

    These instructions need to be followed EXACTLY

    1) In your sketch create a new tab called MyImageButton.java this is case sensitive.

    2) Copy this code into the new tab

    import g4p_controls.*;
    
    public class MyImageButton extends GImageButton {
        public MyImageButton(PApplet theApplet, float p0, float p1, float p2, float p3, String[] fnames) {
            super(theApplet, p0, p1, p2, p3, fnames, null);
        }
    
    }
    

    3) Change your button creation code to

    imgButton1 = new MyImageButton(this, 117, 17, 263, 182, new String[] { pixFile, pixFile,pixFile } );

    4) Save and run your sketch it should work as before. Hopefully as I can't test any code at the moment.

    Now we have this class working we can look at adding code to modify the image, hopefully :)

  • edited September 2015

    @quark, your constructor is named after the original GImageButton.
    And there's no need whatsoever to create any extra ".java" suffixed tab.
    A nested inherited class in some regular ".pde" tab is pretty enough too: ;;)

    import g4p_controls.*;
    
    static final String PIX_URL = "http://" + "forum.Processing.org/" +
                                  "two/uploads/userpics/901/p36K1D8J85S4D.jpg";
    
    void setup() {
      MyImageButton imgButton1 = new MyImageButton(this, 117, 17, 263, 182,
                                                   PIX_URL, PIX_URL, PIX_URL);
    }
    
    void handleButtonEvents(GImageButton button, GEvent event) {
      println(button);
      println(event);
    }
    
    static class MyImageButton extends GImageButton {
      MyImageButton(PApplet p, float p0, float p1, float p2, float p3, String... paths) {
        super(p, p0, p1, p2, p3, paths, null);
      }
    }
    
  • @GoToLoop thanks for pointing out the constructor naming error, it comes from copying and pasting code. :\">

    I have corrected the code in my previous post.

    Although it is true it could be declared as an inner class I prefer (in this case) to have it as a top level class. Also the OP is using GUI Builder and the approach I am taking is tailored to his needs. :)

  • Message below:

    The constructor MyImageButton(sketchmame , int, int, int, int, String[]) is undefined.

    I have been reading all afternoon and still not sure why . @quark @GoToLoop Thanks for the second way to do this GoToLoop. I have been using quarks code not only to progress the problem but also to learn how the extend works. Your code is great. I have focused on quarks today. I appreciate your help and I will be learning from it today and tomorrow.

  • Does that mean you have implemented the code from my previous post and it works?

  • edited September 2015

    If you have successfully created the class as described in my previous post you need to add this method inside the class at line 7

    public void setImage(String[] fnames) {
        //======================================
        bimage = ImageManager.loadImage(winApp, fnames);
        // There should be 3 images if not use as many as possible, 
        // duplicating the last one if neccessary
        if(bimage.length != 3){
            PImage[] temp = new PImage[3];
            for(int i = 0; i < 3; i++)
              temp[i] = bimage[Math.min(i, bimage.length - 1)];
            bimage = temp;
        }
        //======================================
        // resize images if needed
        for(int i = 0; i < bimage.length; i++){
            if(bimage[i].width != width || bimage[i].height != height)
              bimage[i].resize((int)width, (int)height);                    
         }  
    }
    

    MODIFIED POST

  • To get this to work the button needs to be of type MyImageButton but GUI Builder will always create a GImageButton. The best solution is to create the button manually.

    1) Declare a global variable with MyImageButton mib;

    2) In setup add the following line after the call to createGUI
    mib = new MyImageButton(this, 117, 17, 263, 182, new String[] { pixFile, pixFile,pixFile } );
    where pixFile = "fenton.jpg";

    3) Change line
    imgButton1 = new MyImageButton(this, 117, 17, 263, 182, new String[] { pixFile, pixFile,pixFile } );
    to
    mib.setImage(this, new String[] { pixFile, pixFile,pixFile } );

    4) Use GUI Builder to delete imgButton1 since you no longer use it.

  • If you get any syntax errors post them here. I am not in a position to test this code although sematically correct I cannot check for syntax errors myself.

  • error in this line: public MyImageButton(PApplet theApplet, float p0, float p1, float p2, float p3, String[] fnames) { Error : "Cannot find a class or type named "pApplet" "

    I have not added the method yet. I have replaced the iinitial code with your revision.

  • Add this import statement to the MyImageButton class tab

    import processing.core.*;

  • Adding the import statement solved the problem.

    I added the method code just below the curlybrace immediately after the supr statement. This line errors:

    public setImage(String[] fnames) {

    The error is Return type for the Method id missing.

  • Should be

    public void setImage(String[] fnames) {

    My mistake :\">

  • Have changed the earlier post to correct this :)

  • Very Close now. The line: mib.setImage(this, new String[] { pixFile, pixFile,pixFile } );

    Has this error: The method setImage(String[]in the type MyImageButton is not applicable for the arguments(Quark2,String[])

  • mib.setImage(new String[] { pixFile, pixFile,pixFile } );

  • edited September 2015

    All errors are clear.

    I expexted the setImage to update the image on the button. It does not. Here is the button_click thshows the original file pix, takes a new snapshot and replaces the pix in the same named file. . If I stop the program and restart, the new pix is now on the iMyImageButton. Here is the button_click code:

     public void button1_click1(GButton source, GEvent event) { //_CODE_:button1:546995:
      println("button1 - GButton event occured " + System.currentTimeMillis()%10000000 );
    
      snapShot();
      mib.setImage(new String[] { pixFile, pixFile,pixFile } );
      println("Filename: "+pixFile);
    } //_CODE_:button1:546995:
    
  • edited September 2015

    I don't have access to my computer to try this out, hence the syntax errors.

    I think I know what is causing the problem but it needs explaining. This line

    bimage = ImageManager.loadImage(winApp, fnames);

    will only allow one image to be stored for each filename so you need to use a dynamically created filename in snapshot () e.g.

    pixFile = "file" + millis () + ".png";

  • Answer ✓

    This restriction is needed to prevent poorly written programs loading the same image repeatably, for instance creating image buttons inside the draw() method.

  • Perhaps I missed it earlier, but when you told me to delete the old imagebutton with Gui Builder I could not because the Gui Builder no longer showed any controls.

    I manually deleted what I thought needed to go but I had left GImageButton imButton1 if the createGUI(). I changed it to MyImageButton imgButton1.

    This I hoped was the problem. But picture is not updating. No errors though.

  • It is working! The dynamic file name was the last piece needed/. I cannot tell you how much I appreciate the effort. I simply could not have gotten here for a very very long time without your help. I am a little confused about the method, but I think only because it has a lot of moving parts. I will spend more time there. . Also the image manager is I think on your references page so I will spend some time there. I was aware (remember I came to Processing from Arduino and 20 years after taking a C++ class in school) that Classes can be extended, however I thought it would be clunky. I have learned a lot from you and I thank you for that too. I long ago gave up on programming becuase it was no fun. But Processing is terrific fun.

  • Glad I was able to help you. In many situations G4P users can add their own functionality by extending the controls class in the way we gave done here, so this discussion might be useful for others. Mind this is not for the feint hearted :-S

  • I have sat here thinking about the setImage method and while my need is met, it seems to me that an animated button is in reach. But thankfully I do not know why some one would want an animated button, but there you go.!! I have learned a lot. I think you did great for doing it with pen and ink and no computer access.~ Very cool. :)

  • Very useful thread. Thank you. Since I didn't used GuiBuiler and all my image's buttons had the same size I deleted float p2 and float p3 from:

     public MyImageButton(PApplet theApplet, float p0, float p1, **float p2, float p3,** String[] fnames) {
            super(theApplet, p0, p1, **p2, p3,** fnames, null);
    
  • @jrmasiero
    Glad it is still useful because at the time of the original discussion we were using Processing 2. G4P for Processing 3 was released on the 4th October 2015 and some things have changed. The latest version supports animated icons :)

Sign In or Register to comment.