0

I'm building a game with several sequentially created JFrames. For two of these frames (the lobby and the actual game frame) I'm taking user inputs like F11 for fullscreen mode. To enter or leave this fullscreen mode I obviously have to dispose the current frame and create a new one as the setting for setUndecorated() can only be set before making the frame visible.

As other UI elements within the JFrames would take focus I have to use key bindings. Hence I made a class for entering or leaving fullscreen mode. To clarify whether the JFrame should be created in fullscreen or not I pass an int windowState as parameter. As it should be possible to instantiate two different screens I can't simply call the class itself but rather need to look at the frame passed to the Action event.

This is what I tried to do so far:

public class EnterFullscreen extends AbstractAction{

    private static final long serialVersionUID = 1773898497666165938L;
    
    private JFrame frame;
    private Class<?> frameType;
    private Constructor<?> c;
    
    public EnterFullscreen(JFrame frame) {
        
        this.frame = frame;
        
        try {
            frameType = frame.getClass();
            c = frameType.getConstructor(String.class);
        } catch (NoSuchMethodException | SecurityException e) {
            e.printStackTrace();
        }
        
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
        
        try {
            
            frame.setVisible(false);
            if (frame.isUndecorated()) {
                c.newInstance(0);
            } else {
                c.newInstance(1);
            }

            frame.dispose();
            
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException e1) {
            e1.printStackTrace();
        }
        
    }
    
}

Error message:

java.lang.NoSuchMethodException: de.munchkin.frontend.Lobby.<init>(java.lang.String)
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.getConstructor(Class.java:1825)
    at de.munchkin.keybindings.EnterFullscreen.<init>(EnterFullscreen.java:24)
    at de.munchkin.frontend.Lobby.<init>(Lobby.java:45)
    at de.munchkin.frontend.MatchCreation.lambda$1(MatchCreation.java:169)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
    at java.awt.Component.processMouseEvent(Component.java:6539)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
    at java.awt.Component.processEvent(Component.java:6304)
    at java.awt.Container.processEvent(Container.java:2239)
    at java.awt.Component.dispatchEventImpl(Component.java:4889)
    at java.awt.Container.dispatchEventImpl(Container.java:2297)
    at java.awt.Component.dispatchEvent(Component.java:4711)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4904)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4535)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4476)
    at java.awt.Container.dispatchEventImpl(Container.java:2283)
    at java.awt.Window.dispatchEventImpl(Window.java:2746)
    at java.awt.Component.dispatchEvent(Component.java:4711)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:760)
    at java.awt.EventQueue.access$500(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:709)
    at java.awt.EventQueue$3.run(EventQueue.java:703)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:84)
    at java.awt.EventQueue$4.run(EventQueue.java:733)
    at java.awt.EventQueue$4.run(EventQueue.java:731)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:730)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at de.munchkin.keybindings.EnterFullscreen.actionPerformed(EnterFullscreen.java:40)
    at javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1668)
    at javax.swing.JComponent.processKeyBinding(JComponent.java:2882)
    at javax.swing.JComponent.processKeyBindings(JComponent.java:2943)
    at javax.swing.JComponent.processKeyEvent(JComponent.java:2845)
    at java.awt.Component.processEvent(Component.java:6316)
    at java.awt.Container.processEvent(Container.java:2239)
    at java.awt.Component.dispatchEventImpl(Component.java:4889)
    at java.awt.Container.dispatchEventImpl(Container.java:2297)
    at java.awt.Component.dispatchEvent(Component.java:4711)
    at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1954)
    at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:835)
    at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1103)
    at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:974)
    at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:800)
    at java.awt.Component.dispatchEventImpl(Component.java:4760)
    at java.awt.Container.dispatchEventImpl(Container.java:2297)
    at java.awt.Window.dispatchEventImpl(Window.java:2746)
    at java.awt.Component.dispatchEvent(Component.java:4711)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:760)
    at java.awt.EventQueue.access$500(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:709)
    at java.awt.EventQueue$3.run(EventQueue.java:703)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:84)
    at java.awt.EventQueue$4.run(EventQueue.java:733)
    at java.awt.EventQueue$4.run(EventQueue.java:731)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:730)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

The problem is that I get this error but couldn't find what the issue is, as I think I'm doing what most other SO articles on this topic describe: Article 1 Article 2 etc.

What is described in these articles is that I need to get the constructor and call newInstance() on it, which is what I do, if I'm not wrong.

So, what do I need to do differently in order for this to work? I'm not really seeing any difference to the solutions proposed in the other SO posts linked above.

Samaranth
  • 385
  • 3
  • 16
  • 1) Are you extending the JFrame class somewhere? `getClass()` returns the runtime type of the object (dynamic type); if you're just using plain JFrames, then `getClass()` will just return the type `JFrame`. 2) `getConstructor(String.class)` attempts to retrieve a constructor which accepts a `String` as a parameter. Yet, when you use it later, you pass it an integer (0 or 1). 3) I'm a bit confused on your goal, but reflection is likely unnecessary; there are likely simple design patterns and language mechanisms that can achieve your desired result (e.g. factories, polymorphism, etc) – Alexander Guyer Jan 07 '21 at 21:12
  • I was able to get it to work by calling `getConstructors()` on the class and using the first value in the returned array - however there also was only one constructor stored in the array. I also won't put this as the final answer to the question since this still doesn't answer how I would do this by calling `getConstructor()`. – Samaranth Jan 07 '21 at 21:13
  • @Nerdizzle Both my lobby and game frames extend JFrame. The constructors of both these classes take a primitive int instead of an Integer, so it might be that this is the reason I wasn't able to get the correct constructor, as I already tried replacing `String.class` with `Integer.class` but it resulted in the same error. The reason why I do this using reflection is because this was the first thing that came to my mind on how to do this. I'm not really sure how to solve this differently. – Samaranth Jan 07 '21 at 21:16
  • Well, you *could* just use a polymorphic function similar to the traditional `clone()` paradigm but which constructs the clone defaultly. This would require a class in-between `JFrame` and the game / lobby frames in the class hierarchy in which you'd define this function abstractly. After all, you're trying to achieve behavior based on the dynamic type of an object; that's the entire point of polymorphism. – Alexander Guyer Jan 07 '21 at 21:19

1 Answers1

1

The stack trace says that your class Lobby doesn't have a constructor with one parameter of type String.

From your usage like c.newInstance(0), I assume your constructor takes an int/Integer. So, you should write:

    c = frameType.getConstructor(Integer.class);
  • This works, but only partially, i.e. I need to change the parameter from the primitive type int to Integer, as otherwise it's not possible to find a constructor taking an Integer class argument. But is there any possibility accept for using wrappers to get the correct constructor when using primitives? – Samaranth Jan 07 '21 at 21:49
  • 1
    If you use a primitive int in a constructor, it should be: `frameType.getConstructor(int.class);` – Patrycja Wegrzynowicz Jan 07 '21 at 22:28