Any way to get this to work in Processing 3.05? (menu)

edited September 2015 in Questions about Code

This code works fine in processing 2. It doesn't work in processing 3. Is there any way to make it work in processing 3 or are menu bars no longer allowed?

import java.awt.*;
import java.awt.event.*;
import java.awt.CheckboxMenuItem;

MenuBar myMenu;
Menu fileMenu,viewMenu,freqMenu,freqSMenu;
MenuItem fileLoad,fileSave,viewOpen,viewClose,viewFlip,freqSplit, freqJoin;
CheckboxMenuItem  splitBlur,splitMed;

myMenuListener menuListen;

color bg = color(255);

void setup(){
     size(600,600);
     menu_setup();
}

void draw(){
 // get the current menu state
 background(bg);
 point(0,0);
}

//this menuListener object is largely ripped off from http://java.sun.com/docs/books/tutorial/uiswing/examples/components/MenuDemoProject/src/components/MenuDemo.java

 class myMenuListener implements ActionListener, ItemListener{

 myMenuListener(){

 }

 public void actionPerformed(ActionEvent e) {
   MenuItem source = (MenuItem)(e.getSource());
   String s = "Action event detected."
     + "    Event source: " + source.getLabel()
     + " (an instance of " + getClassName(source) + ")";
   println(s);

   //this part changes the background colour
   if(source.equals(fileLoad)){
     println("Load a layer");
   }
   else if(source.equals(fileSave)){
     println("Save a layer");
   }
   else if(source.getLabel().equals("View Open")){
     println(" Open view window");
   }
   else if(source.getLabel().equals("View Close")){
     println("Close view window");
   }
   else if(source.getLabel().equals("Flip View")){
     println("Flip view window");
   }
   else println(" etc. etc..");

 }

   public void itemStateChanged(ItemEvent e) {

  MenuItem source = (MenuItem)(e.getSource());
   String s = "Action event detected."
     + "    Event source: " + source.getLabel()
     + " (an instance of " + getClassName(source) + ")";
   println(s);

   //this part changes the background colour
   if(source.getLabel().equals("Load Layer")){
     println("Load a layer");
   }
   else if(source.getLabel().equals("Save Layer")){
     println("Save a layer");
   }
   else if(source.getLabel().equals("View Open")){
     println(" Open view window");
   }
   else if(source.getLabel().equals("View Close")){
     println("Close view window");
   }
   else if(source.getLabel().equals("Flip View")){
     println("Flip view window");
   }
   else println(" etc. etc..");


      }

}



protected String getClassName(Object o) {
      String classString = o.getClass().getName();
      int dotIndex = classString.lastIndexOf(".");
      return classString.substring(dotIndex+1);
} 

void menu_setup(){

 //this doesn't demonstrate best coding practice, just a simple method
 //create the MenuBar Object
 menuListen = new myMenuListener();
 myMenu = new MenuBar();

 //create the top level button
 fileMenu = new Menu("File");
 viewMenu = new Menu("View");
 freqMenu = new Menu ("Frequency");
 freqSMenu  = new Menu("Frequency Split");

 //create all the Menu Items and add the menuListener to check their state.
 fileLoad = new MenuItem("Load Layer");
 fileLoad.addActionListener(menuListen);
 fileSave = new MenuItem("Save Layer");
 fileSave.addActionListener(menuListen);
 viewOpen = new MenuItem("View Open");
 viewOpen.addActionListener(menuListen);
 viewClose = new MenuItem("View Close");
 viewClose.addActionListener(menuListen);
 viewFlip = new MenuItem("Flip View");
 viewFlip.addActionListener(menuListen);
 freqJoin = new MenuItem("Join Frequencies");
 freqJoin.addActionListener(menuListen);
 splitBlur = new CheckboxMenuItem("Blur",false);
 splitBlur.addActionListener(menuListen);
 splitMed = new CheckboxMenuItem("Median",true);
 splitMed.addActionListener(menuListen);

 fileMenu.add(fileLoad);
 fileMenu.add(fileSave);
 viewMenu.add(viewOpen);
 viewMenu.add(viewClose);
 viewMenu.add(viewFlip);
 freqMenu.add(freqSMenu);
 freqMenu.add(freqJoin);
 freqSMenu.add(splitBlur);
 freqSMenu.add(splitMed);



// add the button to the menu
 myMenu.add(fileMenu);
 myMenu.add(viewMenu);
 myMenu.add(freqMenu);

 //add the menu to the frame!
 frame.setMenuBar(myMenu);  
}
Tagged:

Answers

  • Yikes, that's a lot of code just to demonstrate a problem with a menu bar. In the future, you should try to narrow your problem down to as few lines as possible.

    Anyway, Processing 3 has replaced the frame variable with the surface variable. It does not have all of the functionality of frame, but it is more platform-independent, which is a good thing.

    But as discussed here, you can still get to the frame variable:

    import java.awt.MenuBar;
    import java.awt.Menu;
    import processing.awt.PSurfaceAWT;
    
    void setup() {
      size(200, 200);
      MenuBar myMenu = new MenuBar();
      Menu fileMenu = new Menu("File");
      myMenu.add(fileMenu);
      PSurfaceAWT awtSurface = (PSurfaceAWT)surface;
      PSurfaceAWT.SmoothCanvas smoothCanvas = (PSurfaceAWT.SmoothCanvas)awtSurface.getNative();
      smoothCanvas.getFrame().setMenuBar(myMenu);
    }
    
    void draw() {
      background(0);
    }
    
  • How good of a thing it is is hard for me to know. I don't know what gains it made to make up for the tutorials its thrown into the wind. I don't see many beginners getting a menu up, and anything they find on the subject will be useless now. They'll have to find this thread. So what did we get for that?

  • edited September 2015

    I appreciate the response. Sorry about all the code, but I didn't know where the problem was. The programs didn't say "what FRAME?" " I don't know nothing about no FRAME." It just didn't work. No error. It just didn't work. In spite of all the code - which might be instructive for any who google processing and adding a menu - its only a matter of pasting six lines of code into it, 3 at the top in the imports and the 3 lines at the bottom demonstrating the esoteric way of actually getting the menu on the frame.

    This works fine and might help some trying implement a menu with check boxes. because the old how to's wont work.

    import java.awt.*;
    import java.awt.event.*;
    import java.awt.CheckboxMenuItem;
    import java.awt.MenuBar;
    import java.awt.Menu;
    import processing.awt.PSurfaceAWT;
    
    MenuBar myMenu;
    Menu fileMenu,viewMenu,freqMenu,freqSMenu;
    MenuItem fileLoad,fileSave,viewOpen,viewClose,viewFlip,freqSplit, freqJoin;
    CheckboxMenuItem  splitBlur,splitMed;
    
    myMenuListener menuListen;
    
    color bg = color(255);
    
    void setup(){
         size(600,600);
         menu_setup();
    }
    
    void draw(){
     // get the current menu state
     background(bg);
     point(0,0);
    }
    
    //this menuListener object is largely ripped off from <a href="http://java.sun.com/docs/books/tutorial/uiswing/examples/components/MenuDemoProject/src/components/MenuDemo.java" target="_blank" rel="nofollow">http://java.sun.com/docs/books/tutorial/uiswing/examples/components/MenuDemoProject/src/components/MenuDemo.java</a>;
    
     class myMenuListener implements ActionListener, ItemListener{
    
     myMenuListener(){
    
     }
    
     public void actionPerformed(ActionEvent e) {
       MenuItem source = (MenuItem)(e.getSource());
       String s = "Action event detected."
         + "    Event source: " + source.getLabel()
         + " (an instance of " + getClassName(source) + ")";
       println(s);
    
       //this part changes the background colour
       if(source.equals(fileLoad)){
         println("Load a layer");
       }
       else if(source.equals(fileSave)){
         println("Save a layer");
       }
       else if(source.getLabel().equals("View Open")){
         println(" Open view window");
       }
       else if(source.getLabel().equals("View Close")){
         println("Close view window");
       }
       else if(source.getLabel().equals("Flip View")){
         println("Flip view window");
       }
       else println(" etc. etc..");
    
     }
    
       public void itemStateChanged(ItemEvent e) {
    
      MenuItem source = (MenuItem)(e.getSource());
       String s = "Action event detected."
         + "    Event source: " + source.getLabel()
         + " (an instance of " + getClassName(source) + ")";
       println(s);
    
       //this part changes the background colour
       if(source.getLabel().equals("Load Layer")){
         println("Load a layer");
       }
       else if(source.getLabel().equals("Save Layer")){
         println("Save a layer");
       }
       else if(source.getLabel().equals("View Open")){
         println(" Open view window");
       }
       else if(source.getLabel().equals("View Close")){
         println("Close view window");
       }
       else if(source.getLabel().equals("Flip View")){
         println("Flip view window");
       }
       else println(" etc. etc..");
    
    
          }
    
    }
    
    
    
    protected String getClassName(Object o) {
          String classString = o.getClass().getName();
          int dotIndex = classString.lastIndexOf(".");
          return classString.substring(dotIndex+1);
    } 
    
    void menu_setup(){
    
     //this doesn't demonstrate best coding practice, just a simple method
     //create the MenuBar Object
     menuListen = new myMenuListener();
     myMenu = new MenuBar();
    
     //create the top level button
     fileMenu = new Menu("File");
     viewMenu = new Menu("View");
     freqMenu = new Menu ("Frequency");
     freqSMenu  = new Menu("Frequency Split");
    
     //create all the Menu Items and add the menuListener to check their state.
     fileLoad = new MenuItem("Load Layer");
     fileLoad.addActionListener(menuListen);
     fileSave = new MenuItem("Save Layer");
     fileSave.addActionListener(menuListen);
     viewOpen = new MenuItem("View Open");
     viewOpen.addActionListener(menuListen);
     viewClose = new MenuItem("View Close");
     viewClose.addActionListener(menuListen);
     viewFlip = new MenuItem("Flip View");
     viewFlip.addActionListener(menuListen);
     freqJoin = new MenuItem("Join Frequencies");
     freqJoin.addActionListener(menuListen);
     splitBlur = new CheckboxMenuItem("Blur",false);
     splitBlur.addActionListener(menuListen);
     splitMed = new CheckboxMenuItem("Median",true);
     splitMed.addActionListener(menuListen);
    
     fileMenu.add(fileLoad);
     fileMenu.add(fileSave);
     viewMenu.add(viewOpen);
     viewMenu.add(viewClose);
     viewMenu.add(viewFlip);
     freqMenu.add(freqSMenu);
     freqMenu.add(freqJoin);
     freqSMenu.add(splitBlur);
     freqSMenu.add(splitMed);
    
    
    
    // add the button to the menu
     myMenu.add(fileMenu);
     myMenu.add(viewMenu);
     myMenu.add(freqMenu);
    
     //add the menu to the frame!
       PSurfaceAWT awtSurface = (PSurfaceAWT)surface;
      PSurfaceAWT.SmoothCanvas smoothCanvas = (PSurfaceAWT.SmoothCanvas)awtSurface.getNative();
      smoothCanvas.getFrame().setMenuBar(myMenu);
    }
    
  • Smaller code is better: you've got a lot of extra code in there that will just confuse the issue.

    The reason the frame variable has been deprecated is discussed here: https://github.com/processing/processing/issues/3388

    But the basics are this: Processing supports multiple renderers. One of those renderers (Java2D) uses a JFrame behind the scenes. The other two (OpenGL and JavaFX) do not. So the frame variable wouldn't work with them.

    Instead, they've introduced this surface variable which gives you all of the shared functionality between the renderers: setting the size, title, location, etc.

    To do something like add a menu, you need access to the underlying, render-specific native frame. That's going to be different depending on your renderer, so it can't be mapped to a single variable anymore, so you have to go through the method I gave you above.

    This also means that your code will not work with the OpenGL or JavaFX renderers.

    If you really want a menu bar, you should probably just create your own Java application and use Processing as an embedded library. 95% of people will never use a menu, so it's left to the "advanced users" to figure out on their own.

  • edited September 2015

    Why keep modes that don't use Jframe which has more features than frame? I would love to use Jmenue. If they're gonna deprecate something deprecate frame and go to jframe.

  • edited September 2015

    "If you really want a menu bar, you should probably just create your own Java application and use Processing as an embedded library. 95% of people will never use a menu, so it's left to the "advanced users" to figure out on their own."

    This is just my opinion of course, but its hard for me to believe 95% of people in a graphics environment would not appreciate access to a menu. The PDE has one. Obviously its a useful tool in a graphic application.

  • Why keep modes that don't use Jframe which has more features than frame? I would love to use Jmenue. If they're gonna deprecate something deprecate frame and go to jframe.

    JavaFX uses a class called Scene, which is newer than JFrame.

    This is just my opinion of course, but its hard for me to believe 95% of people in a graphics environment would not appreciate access to a menu. The PDE has one. Obviously its a useful tool in a graphic application.

    Not sure what to tell you, other than to point out that the developers of Processing seem to agree with my statement.

    Processing is designed for quick artistic displays. I think they're also trying to make it more compatible with Processing.js, and adding a menu to a JavaScript sketch would be pretty ugly at best.

  • That may well be but it makes no sense to me. Menus have always been a fundamental part of interface. Its hard to think of useful application that doesn't employ a menu. It changes a proactive program into a reactive program. It turns the gestapo into your valet.

  • I guess we have to agree to disagree. I'll just point out that "modern" applications are going away from traditional menus and more towards "hamburger" menus. If you really need a menu in your application, you might want to think about doing it that way instead.

  • edited September 2015

    I have no problem with hamburger menus. Its a menu. Its a weird choice for some desktop applications, but I understand every generation wants to be different. I think its an excellent choice for apps where screen space is a priority ( like browsers and mobile apps). I think it would be a weird choice for a studio application or a word processor. But hamburger, right click, context menus. They're menus and a fundamental part of interface.

Sign In or Register to comment.