I am a newbie, and I have already passed some days to get the idea, but could not solve it, if anyone can help me.
I have main two JPanel in one JFrame. I have some buttons in the first panel. I have One method to add a panel to theJTabbedPane by calling another method to create that JPanels then add it to the Tab.
I want a method which will add any buttons/components to the Selected tab which I want whenever I click the button from the first panel.
How can I do this. I can post those three method's code here if anyone wish to help me. Thanks in advance.
The first code add new tabs to the JTabbedPane,
private class TabPlus implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
JPanel panel = CreateSlice();
String title = "Slice " + String.valueOf(pane.getTabCount());
pane.insertTab(title, null, panel, null, pane.getTabCount() - 1);
}
}
The second code is for selecting the tabs,
private class TabSelect implements ChangeListener {
#Override
public void stateChanged(ChangeEvent e) {
JTabbedPane source = (JTabbedPane) e.getSource();
if (source.getSelectedComponent() != null) {
int index = source.getSelectedIndex();
System.out.print(index);
}
}
}
This creates the JPanel to be added to the JTabbedPane,
public JPanel CreateSlice() {
JPanel Slice = new JPanel();
Slice.setPreferredSize(new Dimension(550, 600));
return Slice;
}
The buttons are in another Panel with their own action.
GUI Image
You can add a panel with butttons this way:
public JPanel CreateSlice() {
JPanel Slice = new JPanel();
Slice.setPreferredSize(new Dimension(550, 600));
JPanel buttonsPanel = new JPanel();
buttonsPanel.add(new JButton("dumpButton"));
buttonsPanel.setVisible(false);
Slice.add(buttonsPanel);
return Slice;
}
And whenever a selection occurs set the visibility of buttonsPanel to true.
I think, I found one way to do this, My index variable int index = source.getSelectedIndex(); must be public variable, then in Action event of the buttons from another tab will add component to this selected JTabbedPane.
In my case I introduced and ArrayList of panel (network_slices), and every time I am adding a panel to the JTabbedPane, it is also adding to the ArrayList. then I called the panel from the ArrayList by using the index of selected JTabbedPane. Here is the part of the code.
private class TabSelect implements ChangeListener {
#Override
public void stateChanged(ChangeEvent e) {
JTabbedPane source = (JTabbedPane) e.getSource();
if (source.getSelectedComponent() != null) {
index = source.getSelectedIndex();
System.out.print(index);
}
}
}
private class AddTab implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
Slice panel = new Slice();
panel.setPreferredSize(new Dimension(550, 600));
String title = "Slice " + String.valueOf(pane.getTabCount());
pane.insertTab(title, null, panel, null, pane.getTabCount() - 1);
network_slices.add(panel);
}
}
private class AddNetworkFuncitons implements ActionListener {
public void actionPerformed(ActionEvent e) {
String buttonselected = (String) e.getActionCommand();
JButton button = new JButton(buttonselected);
network_slices.get(index).add(button).setVisible(true);
System.out.print(buttonselected);
}
}
Related
I'm working on a game which consists entirely of menus/screens which you interact with using buttons, essentially a text-based game but without the typing. To do this I have been working with Swing to create a basic UI, following this video series.
In order to have actions performed in one panel affect the state of another, I have followed the tutorial and created a UIListener interface, which extends EventListener. When a button is pressed in one JPanel, the fireUIEvent method of the panel is called, which in turn calls the sole method of the interface, uiEventOccurred, which is implemented in an anonymous class inside the main JFrame class. Then the JFrame can do whatever it wants with the event, and modify other JPanels it contains accordingly.
For example, I have a panel that represents the town. It has a button you click to travel to the dungeon. When this button is clicked, the town panel is replaced by the dungeon panel, which has a button you can click to return to the town.
I'll post the relevant classes:
the main frame class
public class GameMainFrame extends JFrame{
public JPanel rightPanel;
public GameMainFrame(String title) {
super(title);
/* Setting The Overall Layout */
setLayout(new BorderLayout());
/* Creating Individual UI Panels */
UIPanel uip_town = new Town_UI();
UIPanel uip_dung = new Dungeon_UI();
/* Creating A Nested Panel */
rightPanel = new JPanel();
rightPanel.setLayout(new BorderLayout());
rightPanel.add(uip_text, BorderLayout.WEST);
rightPanel.add(uip_town, BorderLayout.NORTH);
/* Creating A Listener To React To Events From The UI Panels */
uip_town.addUIListener(new UIListener() {
public void uiEventOccurred(UIEvent event) {
System.out.println("event text: " + event.getText());
if (event.getText().equals("goto_dungeon")) {
rightPanel.remove(uip_town);
rightPanel.add(uip_dung, BorderLayout.NORTH);
validate();
} else if (event.getText().equals("goto_town")) {
rightPanel.remove(uip_dung);
rightPanel.add(uip_town, BorderLayout.NORTH);
validate();
}
}
});
/* Adding Panels To The Content Pane Of The Frame */
Container c = getContentPane();
c.add(uip_info, BorderLayout.WEST);
c.add(rightPanel, BorderLayout.CENTER);
}
}
UIPanel class
public class UIPanel extends JPanel {
private EventListenerList listenerList;
public UIPanel() {
listenerList = new EventListenerList();
}
public void fireUIEvent(UIEvent event) {
Object[] listeners = listenerList.getListenerList();
for (int i = 0; i < listeners.length; i += 2) {
if (listeners[i] == UIListener.class) {
((UIListener) listeners[i + 1]).uiEventOccurred(event);
}
}
}
public void addUIListener(UIListener listener) {
listenerList.add(UIListener.class, listener);
}
public void removeUIListener(UIListener listener) {
listenerList.remove(UIListener.class, listener);
}
}
Town_UI class
public class Town_UI extends UIPanel {
public Town_UI() {
Dimension size = getPreferredSize();
size.height = 466;
setPreferredSize(size);
setBorder(BorderFactory.createTitledBorder("Town"));
JButton btn_dungeon_enter = new JButton("Enter the dungeon");
add(btn_dungeon_enter);
btn_dungeon_enter.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireUIEvent(new UIEvent(this, "goto_dungeon"));
}
});
}
}
Dungeon_UI class
public class Dungeon_UI extends UIPanel {
public Dungeon_UI() {
Dimension size = getPreferredSize();
size.height = 466;
setPreferredSize(size);
setBorder(BorderFactory.createTitledBorder("Dungeon"));
JButton btn_town_return = new JButton("Return to town");
add(btn_town_return);
btn_town_return.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireUIEvent(new UIEvent(this, "goto_town"));
}
});
}
}
UIEvent object
public class UIEvent extends EventObject {
private String text;
public UIEvent(Object source, String text) {
super(source);
this.text = text;
}
public String getText() {
return text;
}
}
UIListener interface
public interface UIListener extends EventListener {
public void uiEventOccurred(UIEvent e);
}
I have two problems with this. Number one, it is currently bugged. When I run the application, the Town_UI panel appears with its button "Enter the dungeon", and upon clicking on it the frame correctly updates, replacing the Town_UI panel with the Dungeon_UI panel. However, clicking on the "Return to town" button on the dungeon panel doesn't do anything. When trying to debug this I found that the cause was in the UIPanel method fireUIEvent. When the "Return to town" button is pressed, this method is correctly called, but when it creates the Object array using getListenerList, the array is empty, so it skips the for-loop and no action is performed. Because I am unfamiliar with ActionEvents and EventListeners in Java, though, I am not sure how to fix this.
My other problem is that all of the behaviors that occur when a button is pressed are handled in the anonymous class in the GameMainFrame class. This means that if I want to have a bunch of different buttons all do different things (which I do plan on implementing), I'll need a whole bunch of conditionals in the anonymous class to determine what button is pressed and perform the corresponding behavior. I feel like it would be a lot cleaner if the button behavior could be implemented in the anonymous ActionListener class of each button, but I'm not sure how I should restructure my code so that I can do this but also allow any action on any panel able modify any other panel.
In the tutorial I watched he claimed that this implementation of EventListeners was what you should do in order to avoid making your code a rat's nest, but it seems like that is where my code is heading if I use this implementation for what I am trying to do.
I have a ArrayList of JPanel. And each items of this list has a JButton.
Now, when JButton is clicked I want to remove its' parent JPanel from the ArrayList. So how can I make the JButton remove its' parent from the ArrayList?
Thanks in advance.
public class TestingArrayList extends JFrame {
JPanel grandPanel; // a JPanel for all the panels
ArrayList<JPanel> panelParent = new ArrayList<>(); // JPanel ArrayList
public TestingArrayList() {
super("Test");
setLayout(new FlowLayout());
grandPanel = new JPanel();
add(grandPanel);
for (int i = 0; i < 10; i++) { // adding 10 JPanel into grandPanel
panelParent.add(new JPanel());
grandPanel.add(panelParent.get(i));
// adding JButton in all panels
JButton btnParent = new JButton("X");
panelParent.get(i).add(btnParent);
// add new task button action
btnParent.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
System.out.println(getParent());
//What to do!!!
}
});
}
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1000, 100);
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
new TestingArrayList();
}
}
You have all you need right in your code. You just need a final reference to the JPanel of interest as this will allow you to use it within the anonymous inner ActionListener class:
for (int i = 0; i < 10; i++) {
// make it final so that it is accessible from inner anon class
final JPanel myPanel = new JPanel();
panelParent.add(myPanel);
grandPanel.add(myPanel);
JButton btnParent = new JButton("X");
myPanel.add(btnParent);
btnParent.addActionListener(event -> panelParent.remove(myPanel));
}
If you also want to remove it from the grandPanel, then you'll need more...
btnParent.addActionListener(event -> {
panelParent.remove(myPanel);
grandPanel.remove(myPanel);
grandPanel.revalidate();
grandPanel.repaint();
});
Note, that if you wanted to use Seymore's method of removing the JPanel, you first need to understand that the source object obtained by calling getSource() on the ActionEvent parameter is the object that the listener was added to -- here a JButton not a JPanel, and also the type of object returned is Object, and so no Swing component methods can be called on it without casting. And so you would need to wrap all in parenthesis in order to allow you to call methods of that type. For example:
parentPanel.remove((JPanel) ((JButton) event.getSource()).getParent());
or
parentPanel.remove((JPanel) ((JComponent) event.getSource()).getParent());
I find it easier to separate lines when code gets this convoluted:
// since a JButton extends from JComponent
JComponent source = (JComponent) event.getSource();
JPanel parent = (JPanel) source.getParent();
parentPanel.remove(parent);
btnParent.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
System.out.println(getParent());
panelParent.remove((JPanel)(event.getSource().getParent()));
}
});
I have a program utilizing JTabbedPane. On one pane I have a button that updates an arrayList of objects based on input from the same pane.
What I would like to happen is have the second pane update itself with the object information based on the arrayList in the first pane.
However, I am not sure how to pass the list between the panes. Is there some way to push the array to pane #2 when the update button on the first pane is pressed?
Here is the main file. Instantiating the two tabs
public class Assignment6 extends JApplet
{
private int APPLET_WIDTH = 650, APPLET_HEIGHT = 350;
private JTabbedPane tPane;
private StorePanel storePanel;
private PurchasePanel purchasePanel;
private ArrayList computerList;
public void init()
{
computerList = new ArrayList();
storePanel = new StorePanel(computerList, purchasePanel);
purchasePanel = new PurchasePanel(computerList);
tPane = new JTabbedPane();
tPane.addTab("Store Inventory", storePanel);
tPane.addTab("Customer Purchase", purchasePanel);
getContentPane().add(tPane);
setSize (APPLET_WIDTH, APPLET_HEIGHT); //set Applet size
}
}
The first panel instantiates a button listener that applies all of the logic to the array list "compList"
private class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
//Add Computer to list
Computer comp = new Computer();
comp.setBrandName(brandField.getText());
comp.setPrice(Double.parseDouble(priceField.getText()));
comp.setMemory(Integer.parseInt(memoryField.getText()));
comp.setCPU(typeField.getText(), Integer.parseInt(speedField.getText()));
compList.add(comp);
}
stringField.setText(listString);
alertLabel.setText("Computer Added");
}
}
Here is the other pane. The for loop at the end is what I need to push the arrayList to. After it receives the list, it populates a box with a checkbox for each object in the list
public PurchasePanel(ArrayList compList)
{
west = new JPanel();
east = new JPanel();
totalField = new JTextField();
this.compList = compList;
setLayout(new GridLayout(0,2));
add(west);
add(east);
east.setLayout(new BorderLayout());
east.add(currentTotalLabel, BorderLayout.NORTH);
east.add(totalField, BorderLayout.CENTER);
west.setLayout( new BoxLayout(west, BoxLayout.Y_AXIS));
for(Object c : compList){
System.out.println("Made it");
NumberFormat fmt = NumberFormat.getCurrencyInstance();
String str = ("BrandName:" + (((Computer) c).getBrandName() +"CPU:" + (((Computer) c).getCPU() +"Memory:" + ((Computer) c).getMemory() + "M" +"Price:" + fmt.format(((Computer) c).getPrice()))));
JCheckBox chk = new JCheckBox(str);
west.add(chk);
}
}
}
You can use the same listener used to update the first ArrayList, to update the second pane. Something like:
jButton1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// Update the first ArrayList
// Update the second pane
}
Good evening ladies and gentlemen,
I have a problem with Java Swing that I cannot solve, maybe you can help me. Here it is:
I have one JFrame which uses BorderLayout, and many JPanels.
Every time I need to put up a new screen (i.e. from the Main Menu, when Search button is clicked, go to the Search Menu), I simply remove the component (JPanel) which is located in the center, and put the new screen (new JPanel) in the center instead.
This way, I don't call all my header and footer objects every time I want to put up a new screen.
Everything works fine with this system except this little problem: I want to trigger some methods everytime I put up a new JPanel or change back to an existing JPanel (generally speaking, everytime a JPanel appears).
In order to do that, I tried to implement ComponentListener's componentShown(ComponentEvent e) method, and added a ComponentListener to a JPanel which I put up in the center of my JFrame, and it did NOT work. After this, I did some research and found out that this componentShown (#ComponentListener) method only works when the visibilty of the JPanel is changed (from invisible to visible or the opposite). Unfortunately, I'm not changing the visibility of a JPanel, just replacing it with another one: removing the current one, and adding the new one. Below code illustrates how I replace the JPanels.
// Get the JPanel located in the center of our JFrame
JPanel currentView = (JPanel) myFrame.getContentPane().getComponent( 2 );
if ( currentView != null )
{
// Remove it from the JPanel
myFrame.getContentPane().remove( currentView );
}
// Add the new JPanel
myFrame.getContentPane().add( otherView, BorderLayout.CENTER );
// Pack the JFrame and show it
myFrame.pack();
So here is what I have. I would really appreciate it if you could help me out.
I think that this issue corresponding with HierarchyListener, for comparing
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ContainerListener extends JFrame {
private static final long serialVersionUID = 1L;
public ContainerListener() {
super("Test");
setContentPane(new TestPanel());
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] parameters) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ContainerListener containerListener = new ContainerListener();
}
});
}
private class TestPanel extends JPanel {
private static final long serialVersionUID = 1L;
TestPanel() {
setLayout(new FlowLayout(FlowLayout.LEFT));
add(new JButton(new AbstractAction("Add label") {
private static final long serialVersionUID = 1L;
private int n = 0;
#Override
public void actionPerformed(ActionEvent event) {
TestPanel.this.add(new JLabel("Label " + ++n));
validate();
}
}));
addHierarchyListener(new HierarchyListener() {
#Override
public void hierarchyChanged(HierarchyEvent e) {
System.out.println("Components Change: " + e.getChanged());
if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) {
if (e.getComponent().isDisplayable()) {
System.out.println("Components: " + e.getChanged());
} else {
System.out.println("Components: " + e.getChanged());
}
}
}
});
addContainerListener(new ContainerAdapter() {
#Override
public void componentAdded(ContainerEvent event) {
System.out.println("componentAdded : " + event.getChild() + "containerName" + " was added");
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
}
I highly recommend listening to the advice given by #Jeffrey, but if you do proceed with this design, then perhaps implementing the ContainerListener interface may prove useful.
When in doubt, consult the API.
Current I can add a bunch of customed component objects to the JPanel by pressing "add" JButton. I also got a "delete" JButton which I wish to do the opposite of "add".
My intention is that I can select a component with a mouse and click the delete button and pressto!, the component is gone.
I hook a MouseListener to the panel, and use MouseEvent, e.getComponent() to get w/e current component the mouse clicks on. So if it returns a custom component then a variable "private myComponent current" (already set to null) will point to that component. Then I can just click on "delete" button to remove it. An actionListener already added in "delete" button and in the body it calls this.remove(current) (if current is not null).
However, this doesn't work as I can't remove a component! Any pointer?
If there is an elegant way to managing add/remove components please suggest!
public class MainDisplayPanel extends JPanel implements ActionListener, MouseListener{
private JButton newClassButton;
private JButton deleteButton;
private Resizable current;
private Resizable resizer;
public MainDisplayPanel(LayoutManager layout) {
super(layout);
newClassButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addResizer();
}
});
deleteButton = new JButton("Delete");
deleteButton.addActionListener(this);
this.addMouseListener(this);
this.add(newClassButton);
this.add(deleteButton);
}
public void addResizer() {
//JPanel panel = new JPanel();
//panel.setBackground(Color.white);
resizer = new Resizable( new ClassBox());
this.add(resizer);
this.revalidate();
this.repaint();
}
public void actionPerformed(ActionEvent e) {
if(current!=null)
{
this.remove(current);
this.revalidate();
this.repaint();
}
}
public void mouseClicked(MouseEvent e) {
System.out.println(e);
Component component = e.getComponent();
if(component instanceof Resizable)
current= (Resizable) e.getComponent();
}
public static void main(String[] args) {
JFrame jframe = new JFrame();
jframe.add(new MainDisplayPanel(null));
jframe.setSize(new Dimension(600,400));
jframe.setVisible(true);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Doh!
Now, in the addResizer() method. Every time I press the add button to add a new Resizable object, what'd happen to the previously added objects? I'm certain that they become null because resizer variable no longer referring to it them??? Even if this is the case, they are still displayed on the panel...And if I pressed delete only the newly added Resizable object gets removed. So am I on the right track here?
Edit: to sum up my problem, I hooked the MouseListener to wrong object. It should be Resizable object instead of the panel. Therefore, variable current is always null.
Your problem is your MouseLisetener. You are listening to the MainDisplayPanel, and so when you click on the JPanel, the MouseEvent#getComponent method returned by, e, in your mousePressed method will return the MainDisplayPanel instance since that is what is being listened to, not the Resizable instance that is under the mouse.
Solutions include:
creating one MouseListener object and adding this same object to each Resizable as a MouseListener for the Resizable, or
using your current set up, but hold your Resizable's in an ArrayList and then iterating through the array list in the mousePressed method to see if any Resizable has been clicked by using the componentAt(...) method.
Note that I had to create my own SSCCE to solve this. Again in the future, please do us all a favor and do this for us as it really is in your and our best interest, and shows that you respect our time and our help.
Edit 1
My SSCCE:
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
#SuppressWarnings("serial")
public class MainDisplayPanel extends JPanel {
private static final int RESIZABLE_COUNT = 40;
private JButton deleteButton;
private Resizable current;
private Resizable resizer;
private List<Resizable> resizableList = new ArrayList<Resizable>();
public MainDisplayPanel(LayoutManager layout) {
super(layout);
deleteButton = new JButton("Delete");
deleteButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
deleteButtonActionPerformed(e);
}
});
this.addMouseListener(new MyMouseAdapter());
this.add(deleteButton);
for (int i = 0; i < RESIZABLE_COUNT; i++) {
addResizer();
}
}
private void deleteButtonActionPerformed(ActionEvent e) {
if (current != null) {
this.remove(current);
resizableList.remove(current);
current = null;
this.revalidate();
this.repaint();
}
}
public void addResizer() {
resizer = new Resizable();
this.add(resizer);
resizableList.add(resizer);
this.revalidate();
this.repaint();
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
current = null;
Component c = getComponentAt(e.getPoint());
for (Resizable resizable : resizableList) {
if (resizable == c) {
current = resizable;
resizable.setFill(true);
} else {
resizable.setFill(false);
}
}
}
}
public static void main(String[] args) {
JFrame jframe = new JFrame();
// !! jframe.add(new MainDisplayPanel(null));
jframe.add(new MainDisplayPanel(new FlowLayout()));
jframe.setSize(new Dimension(600, 400));
jframe.setVisible(true);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
#SuppressWarnings("serial")
class Resizable extends JPanel {
private static final int RESIZE_WIDTH = 50;
private static final int RESIZE_HEIGHT = 40;
private static final int THICKNESS = 5;
private static final Color FILL_COLOR = Color.pink;
public Resizable() {
Random rand = new Random();
// different color border so we can see that it was the clicked one that was deleted.
Color color = new Color(
rand.nextInt(255),
rand.nextInt(255),
rand.nextInt(255));
setBorder(BorderFactory.createLineBorder(color, THICKNESS));
}
#Override // so we can see it
public Dimension getPreferredSize() {
return new Dimension(RESIZE_WIDTH, RESIZE_HEIGHT);
}
public void setFill(boolean fill) {
Color fillColor = fill ? FILL_COLOR : null;
setBackground(fillColor);
repaint();
}
}
it very crazy idea, but everything is possible, but
1) in case that you Layed JComponent by using some of LayoutManager you can remove JComponents from Container, and thenafter you must/have to call revalidate() + repaint(), but this actions has side effect -> ReLayout Container and then Container's contents could be look very ***
2) in case that you layed Container with AbsoluteLayout, that should be maybe nicest but question is what with emtpy space inside Container
there is very easy way how to do it, you need to add JPopupMenu to the Container,
on RightMouseClick you have to finding JComponent under the MouseCursor
then call Container#remove(myComponent), thenafter you have to call revalidate() + repaint() for refresh GUI
or is same for me
call myComponent.setVisible(false), no re-layout, no revalidate + repaint, JComponent waiting on same place for (eventually) reusing
excelent thread about how to LayoutManagers add/remove JComponents + revalidate + repaint
I believe the problem is you need to force Swing to layout the components again after removing one. After you remove(current), call revalidate().