This has been asked before but I would like clarification, I'm new to java coding (sort of, started coding last month) and would like to know simply how can I switch between UIs in one JFrame, Picture this, a settings menu, How do I make it in one JFrame window instead of just make a new window with all the settings, If you don't get it, ask for clarification.
You can implement a frame (JFrame) and, for example, two panels (JPanel). Initially you embed panel A inside frame, when you want to show panel B then call the method showPanelB()
public class MyFrame extends JFrame {
PanelA panelA = new PanelA();
PanelB panelB = new PanelB();
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new MyFrame().setVisible(true);
}
});
}
public MyFrame() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
getContentPane().setLayout(new BorderLayout());
showPanelA();
}
public void showPanelA() {
getContentPane().add(panelA, BorderLayout.CENTER);
}
public void showPanelB() {
getContentPane().add(panelB, BorderLayout.CENTER);
}
}
class PanelA extends JPanel {
// Panel implementation
}
class PanelB extends JPanel {
// Panel implementation
}
Related
My Professor ask me to create one JSwing application which have three tabbed panes each hold a single game.
I have created three different java applications for three different games (Snake, MineSweaper, and Packman) according to zetcode.com website. Each Application contains a Main Class which hold the JFrame and the main method, and another class (extends JPanel) to create the board of the game and lunch it.
Here is an example:
public class Minesweeper_Main extends JFrame {
JFrame jfrm;
Container pane;
JLabel statusbar;
public Minesweeper_Main () {
jfrm= new JFrame("Minesweeper");
jfrm.setSize(500,700);
jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jfrm.setLocationRelativeTo(null);
jfrm.setResizable(false);
pane=jfrm.getContentPane();
statusbar = new JLabel("");
add(statusbar, BorderLayout.SOUTH);
add(new MineSweeper_Board(statusbar));
jfrm.setVisible(true);
}
public static void main(String[] args) {
new Minesweeper_Main ();
}
}
public class MineSweeper_Board extends JPanel {
……..
public MineSweeper_Board(JLabel statusbar) {
this.statusbar = statusbar;
………
setDoubleBuffered(true);
addMouseListener(new MinesAdapter());
newGame();
}
……..
}
Now, I would like to create a new Java Application (Swing Interface), which contains three Tabbed Panes, each hold or call one specific game. Unfortunately, I am either getting error all the times or getting blanks tabs.
The code for the new JSwing application is as following:
public class MF_GameHub extends JFrame {
JFrame jfrm;
Container pane;
JTabbedPane jtp;
public MF_GameHub(){
jfrm= new JFrame("GameHub");
jfrm.setSize(500,700);
jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jfrm.setLocationRelativeTo(null);
jfrm.setResizable(false);
pane=jfrm.getContentPane();
………
jtp = new JTabbedPane();
jtp.addTab("MineSweeper", new MineSweeper());
jtp.addTab("PacMan", new PacMan());
jtp.addTab("Snake", new Snake());
pane.add(jtp);
jfrm.setVisible(true);
}
public static void main(String[] args) {
new MF_GameHub();
}
}
class MineSweeper extends JPanel {
//I DO NOT KNOW HOW TO CALL THE OTHER JAVA APPLICATION FROM HERE
}
class PacMan extends JPanel {
//I DO NOT KNOW HOW TO CALL THE OTHER JAVA APPLICATION FROM HERE
}
class Snake extends JPanel {
//I DO NOT KNOW HOW TO CALL THE OTHER JAVA APPLICATION FROM HERE
}
How can I integrate all three games under one application?
In this case, I will have split my JFrame and the JFrame's contentPane.
After that, you just have to use the contentpane and import this into your app where you want!
Example with your code:
public class Minesweeper_Main extends JFrame {
Container pane;
JLabel statusbar;
public Minesweeper_Main (JPanel contentPane) {
super("Minesweeper");
setSize(500,700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setResizable(false);
setContentPane(contentPane); // << Add
setVisible(true);
}
public static void main(String[] args) {
new Minesweeper_Main (new MineSweeper_Pane()); // << Changed
}
}
public class MF_GameHub extends JFrame {
Container pane;
JTabbedPane jtp;
public MF_GameHub(){
super("GameHub");
setSize(500,700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setResizable(false);
pane=getContentPane();
………
jtp = new JTabbedPane();
jtp.addTab("MineSweeper", new MineSweeper_Pane());
jtp.addTab("PacMan", new PacMan_Pane());
jtp.addTab("Snake", new Snake_Pane());
pane.add(jtp);
setVisible(true);
}
public static void main(String[] args) {
new MF_GameHub();
}
}
And you add this:
public class MineSweeper_Pane extends JPanel {
public MineSweeper_Pane() {
statusbar = new JLabel("");
add(statusbar, BorderLayout.SOUTH);
add(new MineSweeper_Board(statusbar));
}
}
EDIT I'm tired I think; you are using JFrame attribute in a JFrame extended class; Remove the JFrame attribute and use this (or nothing) instead of using the attribute jfrm ;)
I want to change the JPanel of a JFrame, using the CardLayout class.
I have already run this example and it works.
Now I want to use as action listener, the JMenuItem; so If I press that JMenuItem, I want to change it, with a specific panel. So this is the JFrame:
public class FantaFrame extends JFrame implements Observer {
private static final long serialVersionUID = 1L;
private JPanel cardPanel = new JPanel();
private CardLayout cardLayout = new CardLayout();
public FantaFrame(HashMap<String, JPanel> fantaPanels) {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("FantaCalcio App");
setSize(500, 500);
cardPanel.setLayout(cardLayout);
setPanels(fantaPanels);
}
public void update(Observable o, Object arg) {
cardLayout.show(cardPanel, arg.toString());
}
private void setPanels(HashMap<String, JPanel> fantaPanels) {
for (String name : fantaPanels.keySet()) {
cardPanel.add(fantaPanels.get(name), name);
}
}
}
Those are the Menu, the Controller and the Main:
private void pressed(){
home.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
controller.changePanel(home.getText());
}
});
}
public class Controller extends Observable {
public void changePanel(String panel){
setChanged();
notifyObservers(panel);
}
}
public static void main(String[] args) {
fantaPanels.put("Login", new LoginPanel());
Controller controller = new Controller();
MenuBarApp menuApp = new MenuBarApp(controller);
FantaFrame frame = new FantaFrame(fantaPanels);
frame.setJMenuBar(menuApp);
controller.addObserver(frame);
frame.setVisible(true);
}
The problem is that the JPanel doesn't change. What do you think is the problem ?
I've already debugged it, and in the update() method, the correct String value arrives.
You never add the cardPanel JPanel, the one using the CardLayout and displaying the "cards" to anything. You need to add it to your JFrame's contentPane for it to display anything. i.e.,
public FantaFrame(HashMap<String, JPanel> fantaPanels) {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("FantaCalcio App");
setSize(500, 500);
cardPanel.setLayout(cardLayout);
add(cardPanel, BorderLayout.CENTER); // ****** add this line ******
setPanels(fantaPanels);
}
Background
I had a simple game. I had one JPanel class and there were every thing (menu, game, game end).
Then I decided, that I should make my game better and I made two panels(one for menu, and second for game lvls).
Every thing were good, but my KeyAdapter class doesn't work at my JPanel. I don't know why it doesn't want to focus.
There is what I have:
Main class which extends JFrame and here I add my panels (and KeyListener to first panel)
public class JavaGame2 extends JFrame {
public JavaGame2(){
gamePanel = new GamePanel();
menuPanel = new MenuPanel();
setContentPane(menuPanel);
menuPanel.addKeyListener(new KeyListener() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) {
menuPanel.changeCursor();
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
menuPanel.changeCursor();
}
if (menuPanel.getCursorPos()==1){
if ((e.getKeyCode() == KeyEvent.VK_ENTER)) {
setContentPane(gamePanel);
//add(gamePanel);
}
}
else{
if ((e.getKeyCode() == KeyEvent.VK_ENTER)) {
System.exit(0);
}
}
}
});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);
setLocationRelativeTo(null);
setTitle("JavaGame2");
setResizable(false);
}
public static void main(String[] args) {
JFrame jgame = new JavaGame2();
jgame.setVisible(true);
}
}
MenuPanel class extends JPanel
public class MenuPanel extends JPanel implements ActionListener{
public MenuPanel(){
setFocusable(true);
setBackground(Color.BLACK);
setDoubleBuffered(true);
setSize(800,600);
}
public void actionPerformed(ActionEvent e) {
}
}
And here GamePanel class
public class GamePanel extends JPanel implements ActionListener{
public GamePanel (){
addKeyListener(new GameAdapter());
setFocusable(true);
requestFocus();
setBackground(Color.BLACK);
setDoubleBuffered(true);
setSize(800,600);
}
private class GameAdapter extends KeyAdapter{
public void keyReleased(KeyEvent e) {
ship.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
ship.keyPressed(e);
}
}
}
It doesn't work. GamePanel don't want to focus, I tried to do every thing that I read.
I think u will say that JPanel is not focusable component. But when there was one panel it somehow worked.
How can I fix this focus problem?
Maybe u will say that u prefer don't use KeyAdapter, but I think it looks pretty nice in my code.
setFocusable()? or requestFocus()? requestFocusInWindow()? How should I use them? Maybe I have mistake before and this is not my first problem?
Thanks in advance.
And Thanks for editing.
Short answer, use the key bindings API, it allows you to control the level of focus that a component requires before key events are triggered.
Longer answer, the active panel needs to have keyboard focus. You can use requestFocusInWindow, but there is no guarantee that the component will actually receive focus. When to call this is a tricky thing. You could try overriding addNotify of the panels and calling to there, just make sure you call super.addNotify first, weird things happen when you don't
You will also need to consider what will happen if the component loses focus
As a side note:
setDoubleBuffered(true); is irrelevant, as Swing components are double buffered by default. Generally you might disable this if you wanted to print the component. No harm in calling it though
Calling setSize on your components is irrelevant, as you components will be under the control of a layout manager, which will determine the size of the component itself. You'd be better off overriding getPreferredSize and returning an appropriate size for the layout manager
Calling setSize on JFrame is also a bad idea. Frames have borders, this means that your viewable area will be the frame size - the frames border insets, which will be less the 800x600 you've specified. Better to utilise the previous comment and call pack on the JFrame, which will pack the frame around the content so that it meets the contents requirements...
Personally, I would also localise the KeyListener to the actually component itself, this allows the component to act as it's own controller making it more portable...IMHO
Updated with controller idea...
A "really" simplified concept would be to have some kind of "controller" that the menu and game panel could communicate through, for example...
public interface GameController {
public void showMenu();
public void showGame();
}
You would then pass a reference of this interface to the MenuPanel...
public class MenuPanel extends JPanel implements ActionListener{
public MenuPanel(GameController controller){
//...
}
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
And the GamePanel...
public class GamePanel extends JPanel implements ActionListener{
public GamePanel (GameController controller){
//...
}
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
You would, obviously, need to construct a implementation of the controller...
public class CardLayoutGameController implements GameController {
public static final String GAME_PANEL = "GamePanel";
public static final String MENU_PANEL = "MenuPanel";
private Container container;
private CardLayout cardLayout;
public CardLayoutGameController(Container parent, CardLayout layout) {
container = parent;
cardLayout = layout;
}
public void showMenu() {
cardLayout.show(container, MENU_PANEL);
}
public void showGame() {
cardLayout.show(container, GAME_PANEL);
}
}
You would then construct your UI around this controller, for example...
public class JavaGame2 extends JFrame {
public JavaGame2(){
CardLayout layout = new CardLayout();
setLayout(layout);
GameController controller = new CardLayoutGameController(getContentPane(), layout);
gamePanel = new GamePanel(controller);
menuPanel = new MenuPanel(controller);
add(gamePanel, CardLayoutGameController.GAME_PANEL);
add(menuPanel, CardLayoutGameController.MENU_PANEL);
controller.showMenu();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setTitle("JavaGame2");
setResizable(false);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame jgame = new JavaGame2();
jgame.setVisible(true);
}
});
}
}
Is this just an "example" to help spark the idea, haven't tested this, just hacked out here so it might blow up :P
I have a frame and a panel.Permanently I remove the panel and add another panel.After adding a new panel I need the JTextField to get focused.How can I do this?
I tried panel.requestFocus() method but it didnt work.
Example Code:
public class Test{
public static void main(String[] args){
JFrame frame = new JFrame();
// ... frame options
// MyPanel extends JPanel
// and has a JTextField
contentPane.add(new MyPanel());
// Permanently I need to add another panel
contentPane.removeAll();
contentPane.add(new MyPanel());
}
}
Calling panel.requestFocus() attempts to give focus to the container itself rather than on any of its child components.
Use requestFocusInWindow on the JTextField after the component has been added to the JFrame. Add an public method in MyPanel for calling this method.
Avoid using requestFocus. From the docs:
requestFocus, is discouraged because it tries to give the focus to the component's window, which is not always possible. As of JDK 1.4, you should instead use the requestFocusInWindow method, which does not attempt to make the component's window focused.
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Focus JTextField");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyPanel myPanel = new MyPanel();
frame.add(myPanel);
frame.setVisible(true);
frame.pack();
myPanel.focusTextField();
}
});
}
}
class MyPanel extends JPanel {
private JTextField textField;
public MyPanel() {
textField = new JTextField(20);
add(textField);
}
public void focusTextField() {
textField.requestFocusInWindow();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 100);
}
}
Add a method like this to MyPanel:
public void gainFocus() {
tf.requestFocus();
}
Call it from the main method, or elsewhere whenever you need it to be focused.
Use. textfield.setText(""); when you need to get the focus or try something like you will take your control to your field try
You will need a method either to get the TextField from MyPanel, like getTextField, or a method to just directly focus on the TextField. These methods must be inside your MyPanel class.
Example method:
public class MyPanel extends JPanel {
private JTextField textField;
//your code here
public void getTextFieldFocus() {
textField.requestFocus();
}
}
Then you call this getTextFieldFocus method when you need to focus.
Else, if you extract the TextField from the MyPanel class using a getTextField method, you call this when you need the focus:
panel.getTextField().requestFocus();
I have a JFrame and JPanel full of Jsomethings with an actionlistener. When the user clicks an object I want to open another JFrame. Here is what I did:
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == rejectionbutton){
RejectApp ra = new RejectApp();
ra.main(null);
}
}
(RejectApp calls a new JFrame.) So another JFrame opens on the screen with more options. It works OK (so far), but I want to know is this standard? I mean calling the main method like this?
Another question is, without using a cardlayout (which I don't want to use), is the best way to handle multiple panels, by doing this sort of thing?
I would change a few things. First off, usually an application has one JFrame and then if it needs to show another window does so as a modal or non-modal dialog such as can be obtained with a JDialog or JOptionPane. Having said that, it's even more common to have one JFrame and swap "views" in the JFrame -- swap contentPanes or other large panels via a CardLayout as this would mimic the behavior of many gui programs we all currently use.
Personally, I also try to gear my GUI creation towards creating a JPanel or JComponent rather than towards creating a top-level window. This way if I want to display the GUI as a stand alone app, a dialog, or an applet I can pop it into the contentPane of a JFrame or JDialog or JApplet respectively, or if as an inner panel of a more complex GUI, then insert it there, or in an application with a swapping view, then as a card in a CardLayout as noted above. The bottom line is I feel that this structure gives you the developer a lot more options in how you can use this GUI.
Also, I would avoid calling another class's main as you're doing (assuming this is the public static void main method) as you lose all benefits of OOPs. You also seem to be trying to call a static method in a non-static way (assuming I understand your program structure correctly).
For your second question, it begs a question of my own: why do you not want to use CardLayout?
edit: an example of what I meant is as follows:
import java.awt.Dimension;
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class SwingEg {
private static void createAndShowUI() {
JFrame frame = new JFrame("Main JFrame");
frame.getContentPane().add(new MainGUI().getMainPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class MainGUI {
private static final Dimension MAIN_PANEL_SIZE = new Dimension(450, 300);
private JPanel mainPanel = new JPanel();
private JDialog modalDialog;
private JDialog nonModalDialog;
public MainGUI() {
JButton openModalDialogBtn = new JButton("Open Modal Dialog Window");
openModalDialogBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
openModalDialogBtnActionPerformed(e);
}
});
JButton openNonModalDialogBtn = new JButton("Open Non-Modal Dialog Window");
openNonModalDialogBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
openNonModalDialogBtnActionPerformed(e);
}
});
mainPanel.setPreferredSize(MAIN_PANEL_SIZE);
mainPanel.add(openModalDialogBtn);
mainPanel.add(openNonModalDialogBtn);
}
private void openModalDialogBtnActionPerformed(ActionEvent e) {
if (modalDialog == null) {
Window topWindow = SwingUtilities.getWindowAncestor(mainPanel);
modalDialog = new JDialog(topWindow, "Modal Dialog", ModalityType.APPLICATION_MODAL);
modalDialog.getContentPane().add(new DialogPanel().getMainPanel());
modalDialog.pack();
modalDialog.setLocationRelativeTo(topWindow);
modalDialog.setVisible(true);
} else {
modalDialog.setVisible(true);
}
}
private void openNonModalDialogBtnActionPerformed(ActionEvent e) {
if (nonModalDialog == null) {
Window topWindow = SwingUtilities.getWindowAncestor(mainPanel);
nonModalDialog = new JDialog(topWindow, "Non-Modal Dialog", ModalityType.MODELESS);
nonModalDialog.getContentPane().add(new DialogPanel().getMainPanel());
nonModalDialog.pack();
nonModalDialog.setLocationRelativeTo(topWindow);
nonModalDialog.setVisible(true);
} else {
nonModalDialog.setVisible(true);
}
}
public JPanel getMainPanel() {
return mainPanel;
}
}
class DialogPanel {
private static final Dimension DIALOG_SIZE = new Dimension(300, 200);
private JPanel dialogPanel = new JPanel();
public DialogPanel() {
dialogPanel.add(new JLabel("Hello from a dialog", SwingConstants.CENTER));
dialogPanel.setPreferredSize(DIALOG_SIZE);
}
public JPanel getMainPanel() {
return dialogPanel;
}
}
I would rather make a new instance of JFrame or a subclass, or call a new method who makes a new JFrame:
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == rejectionbutton){
JFrame frame = new JFrame("New Frame");
//or
makeNewFrame();
}
}
Another simple Layout-Manager is the BorderLayout, it´s the default Layout-Manager of the JFrame class.
new YourJFrameNameHere().setVisible(true);
Replace YourJFrameNameHere with the JFrame name.
Simple, no?