I want to create two JPanel containers nested in another panel, but why does it show nothing as the code below? It seems that my two panels are not on the ABC panel?
public class ABC extends JPanel
{
Frame frame;
public ABC(Frame frame)
{
super();
this.frame = frame;
setLayout(new BorderLayout());
JPanel one = new JPanel();
JPanel two = new JPanel();
add(one,BorderLayout.NORTH);
add(two,BorderLayout.CENTER);
one.setVisible( true );
two.setVisible( true );
}
public class one extends JPanel {
public one() {
setLayout(new FlowLayout(FlowLayout.LEFT));
createA();
setVisible(true);
}
}
public class two extends JPanel {
public two() {
setLayout(new FlowLayout(FlowLayout.LEFT));
createB();
setVisible(true);
}
}
private void createA(){
add(ButtonA);
add(ButtonAA);
add(ButtonAAA);
}
private void createB(){
add(ButtonB);
}
}
Ur using it in the wrong way, u must use youre own clases (one, two) not the JPANEL:
JPanel one = new one();
JPanel two = new two();
add(one,BorderLayout.NORTH);
add(two,BorderLayout.CENTER);
Btw, try to change the name of your clases can be confusing, to One, Two
try to change the prefererSize of the panel one because when you put a panel in NORTH OR anywhere else but the CENTRE it should have a size
use border to see the edge of the panel
one.setBorder(BorderFactory.createLineBorder(Color.black));
two.setBorder(BorderFactory.createLineBorder(Color.blue));
one.setpreferredsize(new new dimension(width,height));
add(one,BorderLayout.NORTH);
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'm trying to add a JPanel to another JPanel from another class. The program does not longer throw an error and all methods have been run, but the new panel just has a black screen. A basic version of the program looks as follows:
package ninjadragon;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class NinjaDragon extends JFrame implements ActionListener{
public JPanel panelMain;
public JPanel panelTurnBase;
public static void main(String[] args) {
NinjaDragon();
}
public static void NinjaDragon() {
NinjaDragon frame;
frame = new NinjaDragon();
frame.CreateMenuScreen();
JFrame.setDefaultLookAndFeelDecorated(true);
frame.setSize(750, 750);
frame.show();
frame.setResizable(false);
frame.pack();
}
private void CreateMenuScreen() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container window = getContentPane();
panelMain =new JPanel();
panelMain.setPreferredSize(new Dimension(750,750));
panelMain.setBackground(Color.BLACK);
panelMain.setLayout (new FlowLayout());
window.add(panelMain);
PanelTop();
PanelButtons();
PanelIcon();
}
#Override
public void actionPerformed(ActionEvent event) {
Object eventSource = event.getSource();
if (eventSource == buttonStart) {
panelMain.removeAll();
TurnBase TB = new TurnBase();
TB.CreateTurnBase();
}
}
The other class looks something like this:
public void CreateTurnBase() {
panelMain=new JPanel();
panelTurnBase =new JPanel();
setLayout(new FlowLayout());
setPreferredSize(new Dimension(750,750));
setBackground(Color.BLUE);
panelTurnBase.setLayout (new FlowLayout());
panelMain.add(panelTurnBase);
System.out.println("1");
PanelTurnBaseTop();
PanelGameScreen();
PanelTurnBaseBottom();
repaint();
revalidate();
buttonAttack = new JButton("Attack");
buttonAttack.addActionListener(this);
panelTurnBase.add(buttonAttack);
System.out.println("2");
}
The reason the panel has "just a black screen" is because you dont add anything to it, and you tell it to have a black screen.
i.e
panel.setBackground(Color.BLACK);
You never actually do anything to that first panel inside of any of those methods, which I can assume based on your representation of your second "class" (it's a method). Hence why it stays black.
You say:
panelMain=new JPanel();
panelTurnBase =new JPanel();
You're creating new JPanels every time and just call them panelMain and they just sit inside of that method, never leaving. You either need to return a JPanel or give it a JPanel as an argument.
The program is doing exactly what you tell it to do.
Also, do not compare Objects like this:
eventSource == buttonStart
You should use:
eventSource.equals(buttonStart);
Any idea why my code is not connected to the frame?
Frame:
import javax.swing.*;
import java.awt.*;
public class CourseGUI extends JFrame {
public CourseGUI()
{
super("CourseGUI Frame");
JPanel topPane = new TopPanel();
JPanel topPanel = new JPanel();
topPanel.setBackground(java.awt.Color.WHITE);
Dimension d = new Dimension(800,600);
topPanel.setPreferredSize(d);
this.setLayout(new BorderLayout());
this.add(topPanel, BorderLayout.NORTH);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(800,600);
this.setVisible(true);
}
public static void main(String[] args)
{
new CourseGUI();
}
}
Panel:
import javax.swing.*;
import java.awt.*;
public class TopPanel extends JPanel {
public TopPanel() {
TopPanel tp = new TopPanel();
tp.add(new JLabel("Course Info"));
tp.setSize(300,300);
tp.setVisible(true);
}
}
With the panel, I tried to get it where it will be on the NORTH of the Frame, sadly, it's not working. I am a beginner programmer, well In SCHOOL this year to actually learn this, Our teacher taught us this 4 days ago and I can not be anymore confused. Tried to get help several times on this, even from professor, with no avail, someone please help me out and explain. Thanks in advance.
public class TopPanel extends JPanel {
public TopPanel() {
TopPanel tp = new TopPanel();
tp.add(new JLabel("Course Info"));
tp.setSize(300,300);
tp.setVisible(true);
}
}
By creating a TopPanel object inside its own constructor you are causing near infinite recursion:
your TopPanel constructor will create a new TopPanel object
whose constructor will create a new TopPanel object
whose constructor will create a new TopPanel object
whose constructor will create a new TopPanel object whose constructor ,....
... etc -- recursion until your memory runs out. Don't do this.
Instead, don't do this:
public class TopPanel extends JPanel {
public TopPanel() {
// get rid of the recursion
// TopPanel tp = new TopPanel();
// add the label to the current TopPanel object, the "this"
add(new JLabel("Course Info"));
// setSize(300,300); // generally not a good idea
// tp.setVisible(true); // not needed
}
// this is an overly simplified method. You may wish to calculate what the
// preferred size should be, or simply don't set it and let the components
// size themselves.
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
Edit
Also, while not in error, this:
JPanel topPane = new TopPanel();
JPanel topPanel = new JPanel();
is very confusing since the two JPanel variables are close enough in name to confuse us, and more importantly to confuse your future self. You will want to use more logical and distinct variable names.
When you choose a state, the frame's content pane removes its components. Then depending on the state you chose, another class takes the content pane and adds onto it. After doing so, the frame gets packed to resize accordingly.
I want free control over whats in the Frame, such as being able to put panels side by side, above one another, ect.. so I really don't want to use CardLayout. (I'd much rather have 1 panel handle both loginscreen and chat. Then, be able to display another panel next to that one).
I'm using the JFrame's content pane for my login and chat screen, but when I run my code, I get a small frame (has SOME size, but hardly any) that's white on the inside.
show frame
switch to chat
remove everything on pane (currently nothing)
add components onto pane
pack frame so it can size accordingly to the pane
revalidate if needed (not sure when I need to revalidate or not)
Please tell me what I'm doing wrong, and maybe guide me in the right direction.
PS: There are no errors
EDIT: The only thing I can think of is that since I'm passing frame.getContentPane() through the method, and methods are pass-by-value, the actual reference to frame.getContentPane() might not be noticing the changes I'm asking for. But then I don't know why the inside of the frame would be white (as if my JTextArea tried rendering), and there's padding on the inside of the frame, so there has to be something happening..
Main.java:
package main;
import ui.Frame;
public class Main {
public static Frame frame = new Frame();
public static void main(String[] args) {
frame.show();
frame.switchState(State.chat);
}
public static enum State {
login, chat;
}
}
Frame.java:
package ui;
import main.Main.State;
import javax.swing.JFrame;
public class Frame {
private Panel currentpanel; //from package ui, not AWT
private ChatPanel chatpanel = new ChatPanel();
private JFrame frame;
public Frame() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
}
public void show() {
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void switchState(State state) {
frame.removeAll();
switch(state) {
case chat:
currentpanel = chatpanel;
currentpanel.addComponentsTo(frame.getContentPane());
break;
}
frame.pack();
frame.revalidate();
}
}
Panel.java:
package ui;
import java.awt.Container;
public interface Panel {
public void addComponentsTo(Container pane);
}
ChatPanel.java:
package ui;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JTextArea;
public class ChatPanel implements Panel {
private JTextArea toparea = new JTextArea();
private JTextArea bottomarea = new JTextArea();
#Override
public void addComponentsTo(Container pane) {
pane.setPreferredSize(new Dimension(500, 500));
pane.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridy = 0;
gbc.gridx = 0;
gbc.ipadx = 450;
gbc.ipady = 350;
pane.add(toparea, gbc);
gbc.gridy = 1;
gbc.ipady = 100;
pane.add(bottomarea);
}
}
I know that can be quite frustrating.
have you tried calling
pack(); or repaint();
I found the problem. It was calling frame.removeAll(); before adding anything to it.
When I tried if(frame.getComponents().length > 0), it still triggered removeAll(), but the problem wasn't fixed. Seeing how I haven't added anything yet, I checked to see what the component was (by printing out the object), and it was a JRootPane.
After that, I tried printing out frame.getContentPane().getComponents().length, it gave me 0 as expected.
Long story short: This is how switchPanel(State state) should look:
public void switchState(State state) {
if(frame.getContentPane().getComponents().length > 0)
frame.removeAll();
switch(state) {
case chat:
currentpanel = chatpanel;
currentpanel.addComponentsTo(frame.getContentPane());
break;
}
frame.pack();
frame.revalidate();
}
NOTE: I still recommend CardLayout, but if you insists in dynamically setting the frame's content pane the here it is.
The frame class
public class SwitchingFrame extends JFrame {
public static enum State {ONE, TWO}
private PanelONE panel1 = new PanelONE();
private PanelTWO panel2 = new PanelTWO();
public SwitchingFrame() {
getContentPane().setLayout(new BorderLayout());
pack();
setVisible(true);
}
public void switchState(State state) {
setVisible(false);
getContentPane().removeAll();
if (state.equals(State.ONE))
getContentPane().add(panel1, BorderLayout.CENTER);
else
getContentPane().add(panel2, BorderLayout.CENTER);
pack();
setVisible(true);
}
}
The two panel classes which are switched
public class PanelONE extends JPanel {
public PanelONE() {
add(new JLabel("ONE"));
}
}
public class PanelONE extends JPanel {
public PanelTWO() {
add(new JLabel("TWO"));
}
}
The main method which includes buttons to simulate changing the panels
public class TestSwitchingFrame {
public static void main(String[] args) {
final SwitchingFrame sframe = new SwitchingFrame();
JFrame frame = new JFrame();
JButton b1 = new JButton("ONE");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
sframe.switchState(SwitchingFrame.State.ONE);
}
});
JButton b2 = new JButton("TWO");
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
sframe.switchState(SwitchingFrame.State.TWO);
}
});
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(b1);
frame.getContentPane().add(b2);
frame.pack();
frame.setVisible(true);
}
}
You do not need (not should) write your own interface (Panel). Your two panels should extend JPanel and set within the frames content pane. Your frame should extend JFrame and does not need to override its show method (let Swing do it for you). The specific implementation of the switchState function should eventually depend on the end result you want. There are similar ways to accomplish almost the same result.
I've looked around a while and also played around trying to add multiple panels to a JTabbedPane.
My question is: Is it possible to add the same Jpanel to multiple TabbedPanes. Everything way that I tried, it doesn't seem to work correctly. This is how it it works.
public MainGUI() {
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
getContentPane().add(tabbedPane, BorderLayout.CENTER);
JEditorPane instructionalEditorPane = new JEditorPane();
tabbedPane.addTab("Instructional", instructionalEditorPane);
JPanel codePanel = new JPanel();
JPanel drawPanel = new JPanel();
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, codePanel, drawPanel);
splitPane.setResizeWeight(0.75);
tabbedPane.addTab("Code Panel", splitPane);
JEditorPane unifiedInstPane = new JEditorPane();
JPanel unifiedCodePanel = new JPanel();
JPanel unifiedDrawPanel = new JPanel();
JSplitPane unifiedSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, unifiedCodePanel, unifiedDrawPanel);
unifiedSplitPane.setResizeWeight(0.75);
JSplitPane unifiedPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT,unifiedInstPane, unifiedSplitPane);
unifiedPanel.setResizeWeight(0.40);
tabbedPane.addTab("Unified Tab", unifiedPanel);
}
What I would like to do is just add the instructionalEditorPane and the splitPane to multiple tabbedPanes but when I do I loose the original Individual tabbedPanes. If I have to I can do it this way but I would then have to write to both the unifiedInstPane & the instructionalEditorPane to keep them updated. I would also have to do this for the 2 splitPanes which have the codePanel and drawPanels embedded. This will make it harder to keep all the panels in sync.
Any suggestions?
"Is it possible to add the same Jpanel to multiple TabbedPanes." -- no. You can only add a component to one container at a time. Your JPanels should share models but use unique components. The model will likely be a non-GUI class of your creation.
For example, here's a very simplistic rendering of my recommendations:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
public class MainGui2 extends JPanel {
private static final int TAB_COUNT = 3;
private JTabbedPane tabbedPane = new JTabbedPane();
private PlainDocument doc = new PlainDocument();
private Action btnAction = new ButtonAction("Button");
public MainGui2() {
for (int i = 0; i < TAB_COUNT; i++) {
tabbedPane.add("Tab " + (i + 1), createPanel(doc, btnAction));
}
setLayout(new BorderLayout());
add(tabbedPane);
}
private JPanel createPanel(PlainDocument doc, Action action) {
JTextArea textArea = new JTextArea(doc);
textArea.setColumns(40);
textArea.setRows(20);
JPanel panel = new JPanel();
panel.add(new JScrollPane(textArea));
panel.add(new JButton(action));
return panel;
}
private class ButtonAction extends AbstractAction {
public ButtonAction(String title) {
super(title);
}
#Override
public void actionPerformed(ActionEvent evt) {
try {
String text = "Button Pressed!\n";
doc.insertString(doc.getLength(), text, null);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("MainGui2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MainGui2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Better would be to create a formal model class that gets injected into each view, each tabbed pane's individual panes.
Edit
You state in comment:
Yes I can fix that by making calls to the instances but then I'm back to my original problem of having to make calls to each instance to affect a change in all the panel. Say for example I have a drawing panel and I need to call repaint(), I would have to make a call to 2 different instances to get both tabbedPanes to update. Is there any way around this?
Yes, the solution is to use an MVC, or model-view-control, structure. Your model holds your overall program logic, the views are what the user sees, and the control interacts between the two.
Consider having your model notify either the control or the views that its been changed, and then this stimulates a repaint an all observer views.