0

Working on a Java application that opens a window and allows the user to draw on the window, like a canvas.

I've just added a JMenuBar that is going to eventually allow the user to use different drawing tools. The issue is that the JMenuBar opens in a separate window from the "canvas" window, and I want the JMenuBar to be a part of the same window.

How do I work around this and get this to happen?

This is the method that creates the menu bar:

// Create JFrame with MenuBar Components
public static void initializeMenu() {
    frame = new JFrame();

    // JMenu Bar
    menuBar = new JMenuBar();
    menuBar.setBackground(Color.GRAY);

    // JMenu
    fileMenu = new JMenu("File");
    editMenu = new JMenu("Edit");
    menuBar.add(fileMenu);
    menuBar.add(editMenu);

    // JMenu Items
    jItem = new JMenuItem("Save");
    fileMenu.add(jItem);

    // Make JMenuBar Visible in Application
    frame.setJMenuBar(menuBar);
    frame.pack();
    frame.setVisible(true);

}

And the main method:

// Main method
    public static void main(String[] args) {
        Paint paint = new Paint();
        paint.setSize(800, 500);
        paint.setVisible(true);
        paint.setLayout(new FlowLayout());
        initializeMenu();

    }
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
freddiev4
  • 2,501
  • 2
  • 26
  • 46

1 Answers1

1

Try returning an instance of JMenuBar from the initializeMenu and apply it to the Paint class

public static JMenuBar initializeMenu() {
    // JMenu Bar
    menuBar = new JMenuBar();
    menuBar.setBackground(Color.GRAY);

    // JMenu
    fileMenu = new JMenu("File");
    editMenu = new JMenu("Edit");
    menuBar.add(fileMenu);
    menuBar.add(editMenu);

    // JMenu Items
    jItem = new JMenuItem("Save");
    fileMenu.add(jItem);

    return menuBar;    
}

Then apply it yo the Paint class...

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            Paint paint = new Paint();
            paint.setJMenuBar(initializeMenu());        
            paint.setLayout(new FlowLayout());
            paint.setSize(800, 500);
            paint.setVisible(true);
        }
    });
}

Personally, I'd favour pack over setSize, it will generally result in a viewable area which will meet your needs (assuming you're using the layout management API properly)

Updated...

You've broken the paint chain

public class Paint extends JFrame implements ... {

    //...

    // Method for different drawing stencils
    public void paint(Graphics g) {
        if (p != null) {
            g.setColor(c);
            switch (shapeType) {
                case 0:
                    g.drawOval(p.x - w / 2, p.y - h / 2, w, h);
                    break;
                case 1:
                    g.drawRect(p.x - w / 2, p.y - h / 2, w, h);
                    break;

            }

        }

        // Resets application window surface to white (clears the canvas)
        if (Refresh == true) {
            g.setColor(Color.white);
            g.fillRect(0, 0, 1500, 1500);

        }
        g.drawImage(key, 0, 0, this);

        if (widthincrease == true) {
            w += 1;
        }
        if (heightincrease == true) {
            h += 1;
        }
        if (widthdecrease == true) {
            w -= 1;

            if (w < 1) {
                w = 50;
            }
        }

        if (heightdecrease == true) {
            h -= 1;

            if (h < 1) {
                h = 50;
            }
        }

        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        repaint();
    }

    public void update(Graphics g) {
        paint(g);
    }
}

Basically, by overriding paint, but never calling super.paint, you've prevented the frame from ever painting it's content.

First, you should avoid overriding paint of top level containers, this is just one example of way, but JFrame has a bunch of other components which reside on top it.

RootPane

These can (and will) paint over anything you are trying to paint to the frame.

The frame has borders, which are paint within the frames area, by overriding paint, you can paint under these borders, see How to get the EXACT middle of a screen, even when re-sized for an example of what I'm talking about.

Instead, create a custom class that extends from JPanel and override it's paintComponent method, move the rest of the "painting" related to code this class (and don't forget to call super.paintComponent before doing any custom painting).

See Performing Custom Painting for more details

Avoid KeyListener, seriously, it's just a paint, instead, use the key bindings API, see How to Use Key Bindings for more details

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • OK. That makes sense. My Paint class extends Frame though. So, I get the error `The method setMenuBar(JMenuBar) is undefined for the type Paint` so I extended JFrame and the error was fixed, though I cannot see the JMenuBar in the application window still. Should I post the rest of my code? – freddiev4 Jan 19 '15 at 02:58
  • Well, then you have a problem. You can't mix `Swing` and AWT this way. In fact, based on you comments in your question, I would strong advise against using `java.awt.Canvas` and instance use a `JPanel`, that way, you could extend `Paint` from `JFrame` and solve your problems... – MadProgrammer Jan 19 '15 at 03:00
  • Consider providing a [runnable example](https://stackoverflow.com/help/mcve) which demonstrates your problem. This will result in less confusion and better responses – MadProgrammer Jan 19 '15 at 03:01
  • Oh. I'm not using `java.awt.Canvas`, I'm simply saying that the window is like a canvas. – freddiev4 Jan 19 '15 at 03:02
  • @Freddie_V4 Going to need to see more code to know why the menubar isn't visible... – MadProgrammer Jan 19 '15 at 03:03
  • OK. Great. I will take a look at all of the docs you've given me and will get this to work! Thank you – freddiev4 Jan 19 '15 at 03:19