# Is there a way to add JMenuBar (File, Edit...) to my program?

**URL:** <https://discourse.processing.org/t/is-there-a-way-to-add-jmenubar-file-edit-to-my-program/31830>\
**Category:** Project Guidance\
**Created:** [August 21, 2021, 5:17pm UTC](https://discourse.processing.org/t/is-there-a-way-to-add-jmenubar-file-edit-to-my-program/31830 "2021-08-21T17:17:53Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Flolo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/flolo/32/13874_2.png) [@Flolo](https://discourse.processing.org/u/Flolo)\
**Post date:** [August 21, 2021, 5:17pm UTC](https://discourse.processing.org/t/is-there-a-way-to-add-jmenubar-file-edit-to-my-program/31830/1 "2021-08-21T17:17:53Z")

</div>

Hey  
I wanted to ask if there is a way to add an File, Edit, Sketchbook… to a Processing Sketch like the PDE also has?  
 ![Screenshot 2021-08-21 191636](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/5/589dad22bbf86b2ed0906145347640f3a6c96f5a.png)

Thanks in advance 😄

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [August 21, 2021, 6:48pm UTC](https://discourse.processing.org/t/is-there-a-way-to-add-jmenubar-file-edit-to-my-program/31830/2 "2021-08-21T18:48:13Z")

</div>

Please elaborate

Do you have an editor and want to save what the user typed?

---

<div class="post-metadata">

**Author:** ![Flolo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/flolo/32/13874_2.png) [@Flolo](https://discourse.processing.org/u/Flolo)\
**Post date:** [August 21, 2021, 6:55pm UTC](https://discourse.processing.org/t/is-there-a-way-to-add-jmenubar-file-edit-to-my-program/31830/3 "2021-08-21T18:55:07Z")

</div>

Yes, for example, or that you can select a certain tool…

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [August 21, 2021, 7:38pm UTC](https://discourse.processing.org/t/is-there-a-way-to-add-jmenubar-file-edit-to-my-program/31830/4 "2021-08-21T19:38:01Z")

</div>

Do you mean

- a Menu like the File Menu with different commands OR
- a mouse button?

Please elaborate

---

<div class="post-metadata">

**Author:** ![Flolo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/flolo/32/13874_2.png) [@Flolo](https://discourse.processing.org/u/Flolo)\
**Post date:** [August 21, 2021, 7:53pm UTC](https://discourse.processing.org/t/is-there-a-way-to-add-jmenubar-file-edit-to-my-program/31830/5 "2021-08-21T19:53:02Z")

</div>

A Menu like the processing IDE has.

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [August 21, 2021, 7:55pm UTC](https://discourse.processing.org/t/is-there-a-way-to-add-jmenubar-file-edit-to-my-program/31830/6 "2021-08-21T19:55:22Z")

</div>

but then your own commands for the menu entries not the stuff from the processing IDE right?

Check out section GUI here : [https://processing.org/reference/libraries/#gui](https://processing.org/reference/libraries/#gui)

not sure about Menus

---

<div class="post-metadata">

**Author:** ![Flolo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/flolo/32/13874_2.png) [@Flolo](https://discourse.processing.org/u/Flolo)\
**Post date:** [August 21, 2021, 7:58pm UTC](https://discourse.processing.org/t/is-there-a-way-to-add-jmenubar-file-edit-to-my-program/31830/7 "2021-08-21T19:58:27Z")

</div>

> [@Chrisir](#):
>
> but then your own commands for the menu entries not the stuff from the processing IDE right?

Yes my own commands. GUI buttons is not what I mean ☹

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [August 21, 2021, 8:06pm UTC](https://discourse.processing.org/t/is-there-a-way-to-add-jmenubar-file-edit-to-my-program/31830/8 "2021-08-21T20:06:49Z")

</div>

just tried to post a code but it was too long for the forum  
you have to join both posts - or split them to multiple tabs at the \*\*\*\*\*\*\* lines

```auto

// ********************************************************************************
//    
// ********************************************************************************

// ********************************************************************************
// tab: MenuAdvanced8.pde main file (file name is folder name)

/* 
 All tabs beginning with "class..." belong to the library. 
 All other tabs are part of the demo. 
 
 features 
 * different positions: top, left, right, bottom
 * Headlines for groups of buttons
 * help view
 * easy handling 
 * groups of buttons 
 * radio button with circle 
 * check box with rectangle and cross
 * ID und y-position is given by the order you define the buttons (with menu.addButton)
 * drop down menus or side menus (all buttons visible)
 */

import java.util.Map;

// text 
final String helpText = 
  "Demo for advanced menu with different types of buttons (toggle side with l,r,b,t)."; 

// the core object (from lib)
Menu menu;

// those 3 int/boolean switches are modified by buttons (example switches without function)
int mode; // switch 1

int viewMode=0; // switch 2 

boolean boolTest = true; // switch 3

// status bar text 
String statusBarText = "Demo for advanced menu with different types of buttons";
String statusBarTextDefault = statusBarText; 

// states 
final int NORMAL = 0; 
final int HELP = 1; 
int state = NORMAL;

// ---------------------------------------------------------------------
// CORE functions 

void settings() {
  size(1600, 660, P2D);
}

void setup() {
  background(255);

  menu=new Menu();

  // ------------------------------

  menu.addButton( "Modes", Button.IS_HEADLINE, "Modes_Group"); // HEADLINE 
  menu.addButton( "Normal", Button.IS_RADIO_BUTTON, "Modes_Group");
  menu.addButton( "Select", Button.IS_RADIO_BUTTON, "Modes_Group");
  menu.addButton( "Drag", Button.IS_RADIO_BUTTON, "Modes_Group");

  menu.addButton( "Views", Button.IS_HEADLINE, "Views_Group"); // HEADLINE 
  menu.addButton( "Top Down", Button.IS_RADIO_BUTTON, "Views_Group" );
  menu.addButton( "From North", Button.IS_RADIO_BUTTON, "Views_Group" );
  menu.addButton( "From East", Button.IS_RADIO_BUTTON, "Views_Group" );
  menu.addButton( "From South", Button.IS_RADIO_BUTTON, "Views_Group" );
  menu.addButton( "From West", Button.IS_RADIO_BUTTON, "Views_Group" );
  menu.addButton( "Peasy Cam", Button.IS_RADIO_BUTTON, "Views_Group" );
  menu.addButton( "Rotate", Button.IS_RADIO_BUTTON, "Views_Group" );

  menu.addButton( "Camera View", Button.IS_HEADLINE, "Camera View"); // HEADLINE
  menu.addButton( "View is on", Button.IS_CHECKBOX, "Camera View");
  // during adding buttons user can retrieve the last ID 
  menu.printlnCurrentButtonID();

  menu.addButton( "General", Button.IS_HEADLINE, "General"); // HEADLINE
  menu.addButton( "Export", Button.IS_COMMAND_BUTTON, "General" );
  // during adding buttons user can retrieve the last ID 
  menu.printlnCurrentButtonID();
  menu.addButton( "Help", Button.IS_COMMAND_BUTTON, "General");
  // during adding buttons user can retrieve the last ID 
  menu.printlnCurrentButtonID();

  // ------------------------------

  // add help texts to the groups
  menu.addGroupHelp ( "Modes_Group", "Here you can choose modes" );
  menu.addGroupHelp ( "Views_Group", "Here you can choose views" );
  menu.addGroupHelp ( "Camera View", "Here you can toggle the view for camera" );
  menu.addGroupHelp ( "General", "Here you can do general things" ); 

  // these buttons are already highlighted (they represent values: mode, viewMode, boolTest)
  menu.buttons[1].isActive=true;
  menu.buttons[5].isActive=true;
  menu.buttons[13].isActive=true;

  // set position; some positions (top and bottom) don't have enough space for all entries 
  // menu.setLeft();
  // menu.setRight(); // the default 
  // menu.setTop();
  // menu.setBottom();

  // set menu as drop down menu 
  menu.setDropDown();
  //
}// func 

void draw() {

  // state based program 

  switch(state) {

  case NORMAL:
    drawForNormal();
    break; 

  case HELP:
    drawForHelp();
    break;

  default:
    println("Error #111: unknown state: "
      +state);
    exit();
    break; 
    //
  }//switch
  //
}//draw
//

// ********************************************************************************
// tab: classButton.pde

// Helper class for the Menu class.
// Used only by the Menu class.

class Button {

  // visible text
  String btnText; 

  // type: Headline or command button or ............. 
  static final int IS_HEADLINE = 0; // constants: unique numbers 
  static final int IS_COMMAND_BUTTON = 1;
  static final int IS_RADIO_BUTTON = 2; 
  static final int IS_CHECKBOX = 3;
  // type
  int type = IS_COMMAND_BUTTON; 

  // which group does the button belong to?  
  String groupName = "";
  int id_Within_Group = 0; // for radio buttons: a group has one and only one active member.  

  // pos and size
  int x, y; // The x- and y-coordinates
  int sizeWidth, sizeHeight; // size (width and height) (w/h)

  // flags 
  boolean over = false; // True when the mouse is over
  boolean pressed = false; // True when the mouse is over and pressed

  // index 
  int index; // index 

  // is it ON ? 
  boolean isActive=false; // for check box and radio button 

  // -------------------------------------------------------------------------

  // constructor 
  Button(String text_, 
    int type_, 
    String groupName_, 
    int xp_, int yp_, 
    int sizeWidth_, int sizeHeight_, 
    int index_) {

    btnText=text_;

    type=type_; 

    groupName=groupName_;

    x = xp_;
    y = yp_;

    sizeWidth = sizeWidth_;
    sizeHeight = sizeHeight_; 

    index=index_;
  } // constructor 

  // Updates the over field every frame
  void update() {
    if ((mouseX >= x) && (mouseX <= x + sizeWidth) &&
      (mouseY >= y) && (mouseY <= y + sizeHeight)) {
      over = true;
    } else {
      over = false;
    }
  }

  boolean press() {
    if (over) {
      pressed = true;
      return true;
    } else {
      pressed = false; 
      return false;
    }
  }

  void release() {
    pressed = false; // Set to false when the mouse is released
  }

  void displayForDropDownMenu(Group currGroup) {
    //
    switch(type) {

    case IS_HEADLINE: 
      // Headline
      // display like normal button/command button  
      fill(111);
      noStroke(); 
      rect(x, y, 
        sizeWidth, sizeHeight);

      fill(255); // white
      textAlign(LEFT);
      text(btnText, x+6, y+16);
      break;

    default:
      if (currGroup.dropDownIsOpen) {
        // 
        display();
      }//if
      break;
    }//switch
  }//method 

  void display() {
    //
    float dist = 2;
    switch(type) {

    case IS_HEADLINE: 
      // Headline
      fill(0); // white
      textAlign(LEFT);
      text(btnText, x+0, y+16);
      break;

    case IS_COMMAND_BUTTON:
      // normal button 
      fill(111);
      noStroke(); 
      rect(x, y, 
        sizeWidth, sizeHeight);

      fill(255); // white
      textAlign(LEFT);
      text(btnText, x+6, y+16);
      break;

    case IS_RADIO_BUTTON:
      //
      fill(111);
      noStroke(); 
      rect(x, y, 
        sizeWidth, sizeHeight);

      noFill(); 
      stroke(0);
      dist = 2; 
      strokeWeight(1);//reset
      ellipseMode(CENTER); // Set ellipseMode to CENTER
      ellipse(x+dist+8, y+dist+9, 
        9, 9);  
      noStroke(); 
      if (isActive) {
        fill(0); 
        ellipseMode(CENTER); // Set ellipseMode 
        ellipse(x+dist+8, y+dist+9, 
          4, 4);  
        strokeWeight(2);
        stroke(0, 225, 0);//green
        noFill();
      }

      dist = 1; 
      rect(x+dist, y+dist, 
        sizeWidth-dist-dist, sizeHeight-dist-dist);
      strokeWeight(1);//reset

      fill(255); // white
      textAlign(LEFT);
      text(btnText, x+19, y+16);
      break; 

    case IS_CHECKBOX:
      // yes/no boolean
      //
      fill(111);
      noStroke();
      rect(x, y, 
        sizeWidth, sizeHeight);

      noFill(); 
      stroke(0);
      dist = 2; 
      strokeWeight(1);//reset
      // rect with a CHECKBOX 
      PVector upperLeftCorner=new PVector(x+dist+2, y+dist+2+2);
      rect(upperLeftCorner.x, upperLeftCorner.y, 
        9, 9);

      noStroke(); 
      if (isActive) {
        fill(0); 
        stroke(0); 
        // line \
        line(upperLeftCorner.x, upperLeftCorner.y, 
          upperLeftCorner.x+9, upperLeftCorner.y+9);  
        // line /
        line(upperLeftCorner.x+9, upperLeftCorner.y, 
          upperLeftCorner.x, upperLeftCorner.y+9);  
        strokeWeight(2);
        stroke(0, 225, 0);//green
        noFill();
      }// if

      dist = 1; 
      rect(x+dist, y+dist, 
        sizeWidth-dist-dist, sizeHeight-dist-dist);
      strokeWeight(1);//reset

      fill(255); // white
      textAlign(LEFT);
      text(btnText, x+19, y+16);
      break;

    default:
      println("Error 121");
      exit();
      break;
    }//switch
  }//method

  void displayHelpText() {
    // Help View 
    if (type==IS_HEADLINE) {
      // Headline
      fill(0); // 
      textAlign(LEFT);
      text(btnText, x+6, y+16);
    } else {
      // normal button 
      noFill(); 
      stroke(111);
      rect(x, y, sizeWidth, sizeHeight);
      strokeWeight(1);//reset
      fill(111);
      textAlign(LEFT);
      text(btnText, x+6, y+16);
    }//else
  }
  //
}//class
//

// ********************************************************************************
// tab: classGroup.pde

// Helper class for the Menu class.
// A group of buttons.
// Used only by the Menu class.

class Group {

  String name="";

  String helpText=""; 

  String headline="";
  boolean hasHeadline = false; 

  boolean isRadioButtonGroup = false; 
  int groupReturnValue = 0;
  int id_Within_Group_Counter = 0;

  boolean dropDownIsOpen=false; 

  float minXvalue; 
  float maxXvalue; 

  float minYvalue; 
  float maxYvalue;

  ArrayList<Integer> indexOfButtons = new ArrayList(); 

  // ------------------------------------------------------------------

  // constr 
  Group( String name_, int minYvalue_ ) {
    //
    minYvalue = minYvalue_;
    name = name_;
  }// constr 
  //
}//class

```

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [August 21, 2021, 8:07pm UTC](https://discourse.processing.org/t/is-there-a-way-to-add-jmenubar-file-edit-to-my-program/31830/9 "2021-08-21T20:07:09Z")

</div>

```auto

// ********************************************************************************
// tab: classMenu.pde

// The core class for the demo: Menu.

class Menu {

  // The class' variables

  // buttons
  Button[] buttons;

  // consts for positions 
  final int POS_RIGHT = 0; 
  final int POS_LEFT = 1; 
  final int POS_TOP = 2; 
  final int POS_BOTTOM = 3; 
  int menuPosition = POS_RIGHT; // current 

  // on mouse pressed, data gets returned. Must all be negative (since command button returns its ID which is positive). 
  static final int menuReturnIgnore = -1; 
  static final int menuReturnRadioButton = -2;
  static final int menuReturnCheckBox = -3;

  // for init buttons 
  int iForNewButtons=0; 

  // register of groups (buttons are organized in groups)
  HashMap<String, Group> hmGroups = new HashMap();

  int groupsCounter=0; 

  boolean flagDropDown=false;

  // ---------------------------------------------------------------------

  //constr
  Menu () {
    buttons = new Button[0];
  } //constr

  void addButton(String text, int type, String groupName) {
    // parameters:
    // * text is the text 
    // * type is either headline, commandBtn, radio button, check box, see constants in class Button
    // * free name of the group 

    int unit=29; // distY

    // we manage the group names
    Group group;
    // Is the group new? 
    if (hmGroups.containsKey(groupName)) {
      //No, old group - update values 
      group = hmGroups.get(groupName); 
      group.maxYvalue = (iForNewButtons*unit+20) + 19;
      // when entry (button) is a headline, we manage this 
      if (type==Button.IS_HEADLINE) {
        group.headline=text; 
        if ( group.hasHeadline ) {
          println("Warning: Double assigning of headline to a group "
            + text
            +" in group "+groupName);
        } else {
          group.hasHeadline = true;
        }//else
      }//if
    } else
    {
      //Yes, new group - make group and put it in hm
      groupsCounter++; 
      group=new Group(groupName, (iForNewButtons*unit+20) );
      // when entry (button) is a headline, we manage this 
      if (type==Button.IS_HEADLINE) {
        group.headline=text; 
        group.hasHeadline = true;
      }//if
      hmGroups.put(groupName, group);
    }//else 

    // make button 
    Button newButton = new Button( text, type, groupName, 
      width-134, iForNewButtons*unit+20, 
      104, unit-6, 
      iForNewButtons ); 

    // If it's a radio button some adjustments are necessary 
    if (type==Button.IS_RADIO_BUTTON) {
      group.isRadioButtonGroup=true; 
      newButton.id_Within_Group = group.id_Within_Group_Counter;
      group.id_Within_Group_Counter++;
    }//if
    group.indexOfButtons.add(iForNewButtons);

    // add button to array 
    buttons = (Button[]) append (buttons, newButton);
    iForNewButtons++;
  } // method 

  void addGroupHelp(String groupName, String helpText) {
    // adds one help text to a group
    Group currentGroup = hmGroups.get ( groupName );
    if (currentGroup!=null) {
      currentGroup.helpText=helpText;
    } else {
      // error 
      println("Error 331: addGroupHelp: unknown groupname: "+groupName);
      exit();
    }//else
  }// method

  // ----------------------------------------------------------------------

  void display() {
    // show Menu
    if (flagDropDown) {
      // drop down menu
      for (Button but : buttons) {
        but.update();
        Group currGroup=hmGroups.get(but.groupName);
        but.displayForDropDownMenu(currGroup);
      }//for
    } else {
      // no drop down menu
      for (Button but : buttons) {
        but.update();
        but.display();
      }//for
    }//else
  }//method

  int getValueFromGroup( String groupNameLocal ) {
    return 
      hmGroups.get(groupNameLocal).groupReturnValue;
  }

  PVector getHelpBoxPos() {
    // Just a small function for the help screen, that returns a free spot,
    // where a general help text can be placed by the programmer.
    // This is not the position of the help texts of the menus.

    if (flagDropDown) {
      return new PVector(800, 330);
    }

    // Non drop down menus 
    switch(menuPosition) {
    case POS_RIGHT:
      return new PVector(100, 330);
    case POS_LEFT:
      return new PVector(800, 330);
    case POS_TOP:
      return new PVector(100, 330);
    case POS_BOTTOM:
      return new PVector(600, 330);
    default:
      // error
      println("Error 107 : "+menuPosition);
      exit();
      break;
    }//switch
    return new PVector(600, 330);
  }//method

  // ------------------------------------------------------------

  void displayHelp() {
    // show help 
    if (flagDropDown) 
      displayHelpForDropDown();
    else 
    displayHelpForNonDropDown();
  } // method

  void displayHelpForNonDropDown() {
    // helper for displayHelp() 
    if (menuPosition==POS_LEFT || menuPosition==POS_RIGHT) {
      showTexts1();
    } //if
    else {
      showTexts2();
    }//else 

    // show Menu as HELP buttons 
    fill(0); 
    for (Button but : buttons) {
      but.displayHelpText();
    }//for

    // back to default
    textAlign(LEFT);
  }//method 

  void displayHelpForDropDown() {
    // helper for displayHelp()
    // close all 
    closeAllMenus();
    // show help texts for groups 
    showTexts3();
  }//method 

  void showTexts1() {
    // version for menuPosition POS_RIGHT and POS_LEFT
    int xValue=0;
    // for the meaning of the variables see method forkHorizontal 
    PVector pvA=new PVector(); 
    PVector pvB=new PVector(); 
    PVector pvC; 
    switch(menuPosition) {
    case POS_RIGHT:
      xValue=1170;
      pvA.x = xValue+10;
      pvB.x = buttons[0].x - 7;
      textAlign(RIGHT);
      break;   
    case POS_LEFT:
      xValue=buttons[0].x+buttons[0].sizeWidth+93;
      pvA.x=xValue-10;
      pvB.x= buttons[0].x + buttons[0].sizeWidth + 8;
      textAlign(LEFT);
      break;
    default:
      println("Error 108");
      exit();
      break;
    }//switch 

    // GROUPS 
    for (Map.Entry<String, Group> hmEntry : hmGroups.entrySet()) {
      Group currentGroup = hmEntry.getValue(); 
      text( currentGroup.helpText, 
        xValue, (currentGroup.minYvalue+currentGroup.maxYvalue)/2 +2);
      stroke(255, 0, 0);
      // for the meaning of the variables see method forkHorizontal  
      pvB.y=currentGroup.minYvalue;
      pvC=new PVector( pvB.x, currentGroup.maxYvalue );
      forkHorizontal(pvA, pvB, pvC);
    }//for 
    textAlign(LEFT);
  }//method 

  void showTexts2() {
    // version for menuPosition TOP and BOTTOM
    int yValue=0; 
    // for the meaning of the variables see method forkVertical  
    PVector pvA=new PVector(); 
    PVector pvB=new PVector(); 
    PVector pvC; 

    switch(menuPosition) {
    case POS_TOP:
      yValue=170;
      pvA.y = yValue-10;
      pvB.y = buttons[0].x + buttons[0].sizeHeight + 7;
      break;   
    case POS_BOTTOM:
      yValue=height-180;
      pvA.y = yValue+30;
      pvB.y = buttons[0].y - 7;
      break;
    default:
      println("Error 109");
      exit();
      break;
    }//switch 

    // loop over all GROUPS 
    for (Map.Entry<String, Group> hmEntry : hmGroups.entrySet()) {
      Group currentGroup = hmEntry.getValue(); 
      textAlign(CENTER);
      text( currentGroup.helpText, 
        (currentGroup.minXvalue+currentGroup.maxXvalue)/2, yValue, 
        180, 900 );
      stroke(255, 0, 0);
      // for the meaning of the variables see method forkVertical  
      pvB.x=currentGroup.minXvalue;
      pvC=new PVector( currentGroup.maxXvalue+buttons[0].sizeWidth, pvB.y);
      forkVertical(pvA, pvB, pvC);
    }//for

    textAlign(LEFT);
  }//method 

  void showTexts3() {  
    // version for drop down menus 
    int counter = 0; 
    // loop over all groups 
    for (Map.Entry<String, Group> hmEntry : hmGroups.entrySet()) {
      Group currentGroup = hmEntry.getValue(); 
      // loop over all buttons in group
      for (int ind : currentGroup.indexOfButtons) {
        if (buttons[ind].type == Button.IS_HEADLINE) {
          buttons[ind].displayForDropDownMenu(currentGroup);
        }//if
      }//for
      float xValue = buttons[currentGroup.indexOfButtons.get(0)].x + 
        buttons[currentGroup.indexOfButtons.get(0)].sizeWidth / 2;
      fill(255, 0, 0); 
      text( currentGroup.helpText, 
        xValue+50+4, (groupsCounter-counter) * 70 +4);
      stroke(255, 0, 0);
      // for the meaning of the variables see method rightAngle  
      PVector pvA=new PVector(xValue, 30) ;
      PVector pvB=new PVector(xValue+50, (groupsCounter-counter) * 70 );
      rightAngle( pvA, pvB );
      counter++;
    }//for 
    textAlign(LEFT);
  }//method 

  // -------------------------------------------
  // set positions and drop down mode 

  void setLeft() {
    menuPosition = POS_LEFT; 
    for (Button but : buttons) {
      but.x=4;
    }
  }

  void setRight() {
    menuPosition = POS_RIGHT; 
    for (Button but : buttons) {
      but.x=width-134;
    }
  }

  void setTop() {
    menuPosition = POS_TOP; 
    int i=0; 
    for (Button but : buttons) {
      but.x=i*(buttons[1].sizeWidth+4)+5; 
      but.y=5; 
      i++;
    }//for
    getSomeDataForGroups();
  }

  void setBottom() {
    menuPosition = POS_BOTTOM; 
    int i=0; 
    for (Button but : buttons) {
      but.x=i*(buttons[1].sizeWidth+4)+5; 
      but.y=height-25; 
      i++;
    }//for
    getSomeDataForGroups();
  }

  void setDropDown() {
    // changes menu to a drop down menu  
    flagDropDown=true;
    setTop();
    // x-position, y-position
    int xVal=20;
    int yVal=32;
    float textWidthHeadline=0; 
    for (Map.Entry<String, Group> hmEntry : hmGroups.entrySet()) {
      Group currentGroup = hmEntry.getValue();
      // loop over all buttons in group
      for (int ind : currentGroup.indexOfButtons) {
        if (buttons[ind].type == Button.IS_HEADLINE) {
          // make headline button (the menu header from which the menu drops down) 
          buttons[ind].x=xVal; 
          buttons[ind].sizeWidth=int(textWidth(buttons[ind].btnText)+14); 
          textWidthHeadline = textWidth(buttons[ind].btnText)+17;
        }//if
        else {
          // make buttons that drop down
          buttons[ind].x=xVal+3; // x-position little right of menu
          buttons[ind].y=yVal; // y-position 
          yVal+=23; // next line
        }//else
      }//for
      // prepare for next menu: 
      // increase x-position, reset y-position 
      xVal += textWidthHeadline;
      yVal=32;
    } //for
  } //method

  // -------------------------------------------

  void getSomeDataForGroups() {
    // setTop() and setBottom() use this function to set minXvalue and maxXvalue for the groups 
    for (Map.Entry<String, Group> hmEntry : hmGroups.entrySet()) {
      Group currentGroup = hmEntry.getValue();
      // pre-init 
      currentGroup.minXvalue=10000;
      currentGroup.maxXvalue=-1000;
      // loop over all buttons in grouo 
      for (int ind : currentGroup.indexOfButtons) {
        if (buttons[ind].x<currentGroup.minXvalue)
          currentGroup.minXvalue=buttons[ind].x;
        if (buttons[ind].x>currentGroup.maxXvalue)
          currentGroup.maxXvalue=buttons[ind].x;
      }//for
    }//for
  }//method 

  // -------------------------------------------

  int checkMouseOnMenu() {
    // one of the core functions of the class. 
    // Handling mouse pressed.
    int result=menuReturnIgnore; // no button found.
    if (flagDropDown) {
      // drop down menu --- 
      // step 1 : check headlines
      if (checkMouseOnMenuHeadlines())
        return result;
      // step 2 : check menu content of open menu   
      result=checkMouseOnMenuForDropDown();
    } else 
    {
      // not drop down menus ---
      result=checkMouseOnMenuForNonDropDownMenu();
    }//else 
    return result;
  }//method    

  boolean checkMouseOnMenuHeadlines() {
    // helper for checkMouseOnMenu() 
    if (!flagDropDown) 
      return false; 

    for (Button but : buttons) {
      but.press(); 
      if (but.pressed&&but.type==Button.IS_HEADLINE) {
        //drop down menu 
        Group currGroup=hmGroups.get(but.groupName);
        if (currGroup.dropDownIsOpen) {
          // close an open menu            
          currGroup.dropDownIsOpen=false;
        } else {
          // close all 
          closeAllMenus(); 
          // open this menu 
          currGroup.dropDownIsOpen=true;
        }//else 
        but.pressed=false; 
        return true;
      }//if
    }//for 
    return false;
  }// method 

  int checkMouseOnMenuForDropDown() {
    // helper for checkMouseOnMenu() 

    if (!flagDropDown) 
      return menuReturnIgnore; 

    int result = menuReturnIgnore; // no button found.

    // loop over all groups 
    for (Map.Entry<String, Group> hmEntry : hmGroups.entrySet()) {
      Group currentGroup = hmEntry.getValue();

      if (currentGroup.dropDownIsOpen) {

        // loop over all buttons in grouo 
        for (int ind : currentGroup.indexOfButtons) {
          Button but = buttons[ind];

          but.press(); 
          if (but.pressed) {
            // some analysis depending on type
            switch(but.type) {

            case Button.IS_HEADLINE : 
              if (flagDropDown) {
                //drop down menu 
                Group currGroup=hmGroups.get(but.groupName);
                if (currGroup.dropDownIsOpen) {
                  // close an open menu            
                  currGroup.dropDownIsOpen=false;
                } else {
                  // close all 
                  closeAllMenus(); 
                  // open this menu 
                  currGroup.dropDownIsOpen=true;
                }//else 
                but.pressed=false; 
                // return menuReturnIgnore; // just leave
                result = menuReturnIgnore;
              } else {
                // NOT drop down menu 
                // ignore 
                return menuReturnIgnore; // just leave
              } // else and end of case
              break; 

            case Button.IS_COMMAND_BUTTON : 
              // returning positive value
              return but.index; // result. Other buttons won't be pressed, just leave

            case Button.IS_RADIO_BUTTON : 
              Group currentGroup1 = hmGroups.get ( but.groupName ); 
              currentGroup1.groupReturnValue = but.id_Within_Group; 
              setInactive(currentGroup1); 
              but.isActive=true; 
              return menuReturnRadioButton; 

            case Button.IS_CHECKBOX : 
              // toggle 
              but.isActive = 
                ! but.isActive; 
              return menuReturnCheckBox; 

            default : 
              // error 
              println("Error 263: type: "
                + but.type 
                + ", button text: "
                + but.btnText); 
              exit(); // terminate sketch  
              return menuReturnIgnore; // Error. Just leave.
              //
            }//switch 
            //
          } else {
            // but.isActive=false;
          }//else
        }//for
      }
    }
    return result;
  } //method 

  int checkMouseOnMenuForNonDropDownMenu() {
    // helper for checkMouseOnMenu() 

    // not suited for drop down menu
    if (flagDropDown) 
      return menuReturnIgnore;

    int result = menuReturnIgnore; // no button found.
    for (Button but : buttons) {
      but.press(); 
      if (but.pressed) {
        // some analysis depending on type
        switch(but.type) {

        case Button.IS_HEADLINE :  
          // ignore 
          return menuReturnIgnore; // just leave

        case Button.IS_COMMAND_BUTTON : 
          // returning positive value
          return but.index; // result. Other buttons won't be pressed, just leave

        case Button.IS_RADIO_BUTTON : 
          Group currentGroup = hmGroups.get ( but.groupName ); 
          currentGroup.groupReturnValue = but.id_Within_Group; 
          setInactive(currentGroup); 
          but.isActive=true; 
          return menuReturnRadioButton; 

        case Button.IS_CHECKBOX : 
          // toggle 
          but.isActive = 
            ! but.isActive; 
          return menuReturnCheckBox; 

        default : 
          // error 
          println("Error 263: type: "
            + but.type 
            + ", button text: "
            + but.btnText); 
          exit(); // terminate sketch  
          return menuReturnIgnore; // Error. Just leave.
          //
        }//switch 
        //
      }//if
    }//for
    return result;
  } //method 

  // -------------------------------------------
  // minor tools 

  void forkHorizontal (PVector pvA, PVector pvB, PVector pvC) {
    // 
    // draws :
    // (E) _________ B 
    // |
    // A ---------|(D)
    // |
    // (F)--------- C

    // (The x-values of B and C should be the same)  

    // pvA's y-value gets overwritten btw.
    pvA.y = (pvB.y + pvC.y) / 2 ;

    PVector pvD = new PVector ( (pvA.x + pvB.x) / 2, (pvB.y + pvC.y) / 2 );

    PVector pvE = new PVector ( pvD.x, pvB.y ); 
    PVector pvF = new PVector ( pvD.x, pvC.y );  

    linePV ( pvA, pvD ) ; 
    linePV ( pvE, pvF ) ;

    linePV ( pvE, pvB ) ;
    linePV ( pvF, pvC ) ;
  }//method 

  void forkVertical (PVector pvA, PVector pvB, PVector pvC) {
    // 
    // draws :
    // A
    // |
    // |
    // E-----D----F
    // | |
    // | |
    // | |
    // B C

    // (The y-values of B and C should be the same)  

    // pvA's x-value gets overwritten btw.
    pvA.x = (pvB.x + pvC.x) / 2 ;

    PVector pvD = new PVector ( (pvB.x + pvC.x) / 2, (pvA.y + pvB.y) / 2 );

    PVector pvE = new PVector ( pvB.x, pvD.y); 
    PVector pvF = new PVector ( pvC.x, pvD.y);  

    linePV ( pvA, pvD ) ; 
    linePV ( pvE, pvF ) ;

    linePV ( pvE, pvB ) ;
    linePV ( pvF, pvC ) ;
  }//method 

  void rightAngle( PVector pvA, PVector pvB ) {
    //draws:
    //
    // A
    // |
    // |
    // |
    // (C)---------B
    // 
    PVector pvC = new PVector (pvA.x, pvB.y); 
    linePV( pvA, pvC );
    linePV( pvC, pvB );
  }

  void linePV(PVector pv1, PVector pv2) {
    line(pv1.x, pv1.y, 
      pv2.x, pv2.y);
  }//method

  boolean closeAllMenus() {
    // close all menus.
    // Returns failure (false) when 
    // we are not in Drop Down Mode
    // or when no menu was open.
    // When a menu was closed, success (true) is returned by the variable result. 

    // When we are not in Drop Down Mode return failure 
    if (!flagDropDown)
      return false; // return failure

    boolean result=false; 
    for (Map.Entry<String, Group> hmEntry : hmGroups.entrySet()) {
      Group currentGroup = hmEntry.getValue();
      if (currentGroup.dropDownIsOpen) {
        result=true;
      }
      currentGroup.dropDownIsOpen=false;
    }//for
    return result;
  }//method 

  void setInactive( Group currGroup ) {
    // for radio buttons: set entire group inactive
    for (int ind : currGroup.indexOfButtons) {
      buttons[ind].isActive=false;
    }
  }//method

  void printlnCurrentButtonID() {
    // during adding buttons user can retrieve the last ID 
    println(iForNewButtons-1
      +": "
      +buttons[iForNewButtons-1].btnText);
  }
  //
}//class
//

// ********************************************************************************
// tab: inputsKeyboard.pde

// INPUT FUNCTIONS keyboard 

void keyPressed() {

  statusBarText=statusBarTextDefault;

  if (state==HELP) {
    if (key==ESC) {
      key=0; // kill ESC
      state=NORMAL;
    }//if
    return;
  }//if

  // Normal 
  if (state==NORMAL) {
    // menu position 
    if (key=='l')menu.setLeft();
    else if (key=='r')menu.setRight();
    else if (key=='t')menu.setTop();
    else if (key=='b') menu.setBottom();
    else if (key=='d') menu.setDropDown();
    else if (key==ESC) {
      // when a menu is open, close it (and return true)
      if (menu.closeAllMenus()) 
        key=0; // kill Esc when a menu was closed
    }//else if
    return;
  }//if
}//func 
//

// ********************************************************************************
// tab: inputsMouse.pde

// INPUTS Mouse 

void mousePressed() {

  // state Help 
  if (state==HELP) {
    state=NORMAL; 
    return;
  }//if

  // state Normal 
  if (state==NORMAL) {
    // the menu
    if (mouseButton==LEFT) {
      int menuReturn = menu.checkMouseOnMenu(); 
      doCommand(menuReturn);
    } //if
  } //if
} // func 
//

// ********************************************************************************
// tab: toolsDoCommand.pde

// Tools for buttons 

void doCommand(int menuReturn) {

  statusBarText = statusBarTextDefault;

  switch(menuReturn) {

    // menuReturn is not necessary a button ID
    // but can be Menu.menuReturnIgnore, Menu.menuReturnRadioButton,
    // Menu.menuReturnCheckBox which are all negative.
    // Positive values are IDs and are used for command buttons. 

    //--------------------------
    // step 1 : three negative vars 

  case Menu.menuReturnIgnore:
    //ignore (headlines, errors etc.)
    break; 

  case Menu.menuReturnRadioButton:
    // radio button:
    // to make things easier, we just update all variables (in this case 2) that are connected to radio buttons / groups.
    // Programmer using the lib needs to know which int switch is connected to which group of radio buttons
    mode = menu.getValueFromGroup( "Modes_Group" );
    viewMode = menu.getValueFromGroup( "Views_Group" ); 
    break; 

  case Menu.menuReturnCheckBox:
    // Check Box Button:
    // to make things easier, we just update all variables (in this case 1) that are connected to check box buttons.
    // you need to know IDs of buttons.
    // cam view ON/OFF     
    boolTest = menu.buttons[13].isActive;
    break; 

    // -------------------------------------------
    // step 2 : just IDs of buttons for command buttons  

  case 15:
    // Export
    statusBarText="Export (nothing happening, just a demo)";
    break;

  case 16: 
    //Help
    state = HELP; 
    break;

  default:
    // Error situation - doesn't need to be changed by user of library 
    statusBarText="Error";
    println ("Error 170 : in doCommand: "
      +menuReturn); 
    exit();
    return; // leave here
  }//switch
}//func 
//

// ********************************************************************************
// tab: toolsStates.pde

// states 

void drawForNormal() {

  background(255); 

  // distinguish between modes (it's not a state)
  fill(0);
  text("Mode is "+mode  
    +"\nView Mode is "+viewMode
    +"\nCamera View (boolean) is "+boolTest, 160, 300);

  // in ALL modes: ---------- 

  // show status
  if (menu.menuPosition != menu.POS_BOTTOM) {
    fill(0);
    text(statusBarText, 5, height-4);
    stroke(0);
    line(0, height-21, 
      width, height-21);
  }

  // show text help 
  fill(0) ;
  text(helpText, 160, 107);

  menu.display(); 
  //
}// func 

void drawForHelp() {

  background(255);

  PVector pos = menu.getHelpBoxPos();
  fill(0, 255, 0); 
  text("Help Screen - "
    +"\n\nPress ESCAPE to leave this help screen. ", 
    pos.x, pos.y, 300, 700);

  fill(255, 0, 0); 
  menu.displayHelp(); 
  //
} // func 
//

// End of joined file. *************************************************

```

---

<div class="post-metadata">

**Author:** ![Flolo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/flolo/32/13874_2.png) [@Flolo](https://discourse.processing.org/u/Flolo)\
**Post date:** [August 21, 2021, 8:23pm UTC](https://discourse.processing.org/t/is-there-a-way-to-add-jmenubar-file-edit-to-my-program/31830/10 "2021-08-21T20:23:48Z")

</div>

This is also a possibility, thank you for your efforts 😄

I just found how to create a menu:

> [@Show an desktop menu bar](https://discourse.processing.org/t/show-an-desktop-menu-bar/9651/2):
>
> The trick here is not to extend JFrame to create the menubar, rather use the one created by Processing for the sketch. This will not work with P2D and P3D because they use OpenGL so the sketch is shown in a GLWindow not a JFrame Menu\_bar mp; void setup() { buildMenuBar(); } void draw() { } void buildMenuBar() { mp = new Menu\_bar(this, "Media", 100, 100); } Menubar tab import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JFrame; import javax.swing…

I’ve revised that a bit:

**Main:**

```auto
import javax.swing.filechooser.FileSystemView;
import javax.swing.JFileChooser;
Menu_bar mp;

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

void draw() {
  background(0);
  fill(255);
  ellipse(mouseX, mouseY, 30, 30);
}

void buildMenuBar() {
  mp = new Menu_bar(this, getClass().getSimpleName(), width, height);
}

```

**Menu\_bar:**

```auto
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

public class Menu_bar implements ActionListener {
  JFrame frame;

  public Menu_bar(PApplet app, String name, int width, int height) {
    System.setProperty("apple.laf.useScreenMenuBar", "true");
    frame = (JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas)app.getSurface().getNative()).getFrame();
    frame.setTitle(name);

    // Creates a menubar for a JFrame
    JMenuBar menu_bar = new JMenuBar();
    // Add the menubar to the frame
    frame.setJMenuBar(menu_bar);
    // Define and add two drop down menu to the menubar
    JMenu import_menu = new JMenu("File");
    JMenu text_menu = new JMenu("Edit");
    JMenu shape_menu = new JMenu("Sketch");
    JMenu image_menu = new JMenu("Tools");
    JMenu video_menu = new JMenu("Help");

    menu_bar.add(import_menu);
    menu_bar.add(text_menu);
    menu_bar.add(shape_menu);
    menu_bar.add(image_menu);
    menu_bar.add(video_menu);

    // Create and add simple menu item to one of the drop down menu
    JMenuItem new_file = new JMenuItem("Save");
    JMenuItem new_folder = new JMenuItem("Save As...");
    JMenuItem action_exit = new JMenuItem("Exit");

    new_file.addActionListener(this);
    new_folder.addActionListener(this);
    action_exit.addActionListener(this);

    import_menu.add(new_file);
    import_menu.add(new_folder);
    import_menu.addSeparator();
    import_menu.add(action_exit);

    frame.setVisible(true);
  }
  @Override
    public void actionPerformed(ActionEvent e) {
    JFileChooser jfc = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());
    jfc.setDialogTitle("Choose destination.");
    jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);

    String ae = e.getActionCommand();

    if (ae.equals("Save")) {
      println("Save");
    } else if (ae.equals("Save As...")) {
      println("Save As...");
    } else if (ae.equals("Exit")) {
      println("Exit");
      System.exit(0);
    }
  }
}

```
