0

Im attempting to make a standard menu UI in java and I'm having an issue.

So essentially Code 1 sets up the Jframe and calls code 2.
The problem I'm having is that when the menu button is pressed I want it to load code 3 and then stay there until the exit button is pressed. But what is happening at the moment is that the mouse pressed is detected, it runs through the entirety of code 3 and returns to code 2 without repainting the menu bar or exit button that code 3 contains.

So what I'm looking to happen is that when code 3 is called I want it to stay there and display the content (that being the menu) until a mouse click is detected in the area on the exit_but.

Any help would be great.

My code is show below;


Code 1:

import java.awt.*;
import java.awt.Graphics;

import javax.swing.*;

public class demo_project 
{
public static void main(String[] args) 
{
    JFrame frame = new JFrame("Funhaus Project");

    frame.setSize(720, 1280);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    frame.getContentPane().add(new demo_main_screen());
    frame.pack();
    frame.setVisible(true);
}

}

Code 2:

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

import javax.swing.*;

public class demo_main_screen extends JPanel
{  
private ImageIcon menu_button;

private MouseListener listener = new MouseAdapter()
{
    public void mouseClicked(MouseEvent e)
    {
        // Detects if the Video button was pressed
        if (e.getPoint().x > 15 && e.getPoint().x < 183 && e.getPoint().y > 15 && e.getPoint().y < 85)
        {   
            System.out.println("Menu Button Pressed");
            new demo_menu();
        }
    }
};

// Paints the content to the screen
public void paint(Graphics g)
{
    super.paintComponent(g);

    menu_button.paintIcon(this, g, 15, 15);
}

// main screen constructor
public demo_main_screen()
{
    addMouseListener(listener);

    menu_button = new ImageIcon("res/menu_but.png");

    setBackground(Color.white);
    setPreferredSize(new Dimension(1280, 720));
    setFocusable(true);
}

}

Code 3:

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

import javax.swing.*;

public class demo_menu extends JPanel
{

private ImageIcon menu, exit_but;

private MouseListener listener = new MouseAdapter()
{
    public void mouseClicked(MouseEvent e)
    {
        if (e.getPoint().x > 230 && e.getPoint().x < 255 && e.getPoint().y > 15 && e.getPoint().y < 48)
        {   
            return;
        }
    }   
};

// main screen constructor
public demo_menu()
{
    addMouseListener(listener);

    menu = new ImageIcon("res/menu.png");
    exit_but = new ImageIcon("res/exit_but.png");

    setBackground(Color.white);
    setPreferredSize(new Dimension(1280, 720));
    setFocusable(true);
}

// Paints the content to the screen
public void paint(Graphics g)
{
    super.paintComponent(g);

    menu.paintIcon(this, g, 0, 0);
    exit_but.paintIcon(this, g, 230, 15);

    System.out.println("repaint");
}   

}

Nick
  • 57
  • 8
  • To get a JPanel to repaint itself, you need to explicitly call repaint(). Did you try doing that? – Jarred Allen Feb 27 '17 at 00:06
  • You never add `demo_menu` to anything that would display it. My suggestion is to have a look at `CardLayout`. You could also implement your own controller, which would allow you to "push" new views onto the view stack and when required, "pop" them off again, updating the UI as it goes automatically – MadProgrammer Feb 27 '17 at 00:09
  • @MadProgrammer I'll look into `CardLayout`, thanks. – Nick Feb 27 '17 at 00:30
  • @JarredAllen Where about would you suggest me to add `repaint()`? I attempted to put it in the constructor but it doesn't seem to be called. I know this because I added a `System.out` in the `repaint()` so that I could tell if the repaint was occuring at all. – Nick Feb 27 '17 at 00:35

1 Answers1

3

The main issue is you never actually add you new panel to anything which could display it (let alone update the UI to display it)

There are a number of ways you might be able to achieve this (more simply), CardLayout is one. Another might be to make your own controller which can "push" and "pop" views as needed. This decouples the navigation as the current view does not need to know what the last view "should" be

For example...

import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Stack;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    BufferedImage background = ImageIO.read(new File("/Users/shane/Dropbox/MegaTokyo/issue142.jpg"));
                    DefaultTableModel model = new DefaultTableModel(new String[]{"A", "B", "C", "D", "E", "F"}, 10);

                    JFrame frame = new JFrame("Test");
                    JPanel contentPane = new JPanel(new BorderLayout());
                    frame.setContentPane(contentPane);
                    ViewController controller = new ViewController(contentPane);
                    controller.push(new MainMenu(controller));

                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    public class MainMenu extends JPanel {

        private ViewController controller;

        public MainMenu(ViewController controller) {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.insets = new Insets(100, 100, 100, 100);
            JButton btn = new JButton("Sub Menu");
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    controller.push(new SubMenu(controller));
                }
            });
            add(btn, gbc);
        }

    }

    public class SubMenu extends JPanel {

        private ViewController controller;

        public SubMenu(ViewController controller) {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            add(new JLabel("This is the sub menu"), gbc);
            JButton btn = new JButton("Return");
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    controller.pop();
                }
            });
            add(btn, gbc);
        }

    }

    public class ViewController {

        private Stack<JComponent> views;
        private JComponent rootView;

        public ViewController(JComponent rootView) {
            this.rootView = rootView;
            views = new Stack<>();
        }

        public void push(JComponent view) {
            if (views.size() > 0) {
                JComponent current = views.peek();
                if (current != null) {
                    rootView.remove(current);
                }
            }
            views.push(view);
            rootView.add(view);
            rootView.revalidate();
            rootView.repaint();
        }

        public void pop() {
            if (views.size() > 1) {
                JComponent current = views.pop();
                if (current != null) {
                    rootView.remove(current);
                }
                current = views.peek();
                rootView.add(current);
                rootView.revalidate();
                rootView.repaint();
            }
        }

    }
}

There's nothing stopping you from coupling this with a CardLayout and using "names" instead of JComponent when pushing elements on the Stack instead

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Thanks for that @MadProgrammer. All this code is a little to overwhelming for me at the moment but I will work at it and see if I can get it too work for me. Thanks. – Nick Feb 27 '17 at 03:20
  • If you want to see something complex, I'll show you how you can use a MVC to manage a `CardLayout` – MadProgrammer Feb 27 '17 at 04:34
  • I'd love to see that @MadProgrammer :P – Frakcool Feb 27 '17 at 22:43
  • 1
    @Frakcool For [example](http://stackoverflow.com/questions/30925564/why-is-my-jlabel-not-showing-up/30926625#30926625), [example](http://stackoverflow.com/questions/29571722/java-application-with-multiple-scenes/29639672#29639672), [example](http://stackoverflow.com/questions/27663306/open-a-jpanel-after-pressing-a-button-in-a-jframe/27663749#27663749), [example](http://stackoverflow.com/questions/31602113/listener-placement-adhering-to-the-traditional-non-mediator-mvc-pattern/31604919#31604919) – MadProgrammer Feb 27 '17 at 22:51
  • I guess I'll take a look at it tonight at least one of them carefully and tomorrow the rest. Thank you, it's gonna help me on the project I'm working on these days :) – Frakcool Feb 27 '17 at 22:59