changing Jpanels - java

i'm trying to make it display one JPanel and remove the other depended on which timer is off in java. here is the snip it of code. mainMenu and pongField are the JPanels and this is inside a timer that acts every millisecond;
if (SwingUtilities.getAncestorOfClass(JFrame.class, pongField) != null){
if (!pongField.getTimer().isRunning())
{
mainMenu = new MainMenu(screenX, screenY, myColor, background, contentPane);
contentPane.remove(pongField);
}}
if (SwingUtilities.getAncestorOfClass(JFrame.class, mainMenu) != null){
if (!mainMenu.getTimer().isRunning())
{
switch(mainMenu.getButton())
{
case 1:
pongField = new PongField(screenX, screenY, 0, moderator, player1UpControl, player2UpControl, player1DownControl, player2DownControl, myColor, background, contentPane, speed);
mainMenu.setButton(0);
contentPane.remove(mainMenu);
break;
case 2:
break;
case 3:
break;
case 4:
break;
}
}}
let me be a little more specific.
I am trying to make Pong, and one JPanel is the actual game while the other is the main menu. if the game ends the timer stops and if i press a button on the main Menu the timer stops and set getButton() to a number depending on which is pressed. for example if button single player is pressed it creates the game and gets rid of the current Jpanel. but if the game ends it get rid of the current JPanel and displays the main menu. Also each JPanel when created set it's own bounds, background color, and adds itself to the JFrame.
The problem is when i run it and the game ends it doesn't change back unless i minimize it and bring it back up but then the button won't work. here is the code for MainMenu. PongField's code is too long but i think i summed up what it did good enough but i can post it too if you want.
public class MainMenu extends JPanel
{
private static final long serialVersionUID = 1L;
//JButtons
private JButton singleJButton, multiJButton, settingsJButton, exitJButton;
//timer if game is still on
private Timer runningTimer;
//JLabel for title
private JLabel titleJLabel;
//screen size
int screenX, screenY;
//color of text and background
private Color myColor, background;
//Container of the JFrame
private Container contentPane;
//which button was clicked
private int buttonPressed;
public MainMenu(int x, int y, Color myC, Color backg, Container contentP)
{
super();
//Initialize all given variables
screenX = x;
screenY = y;
myColor = myC;
background = backg;
contentPane = contentP;
setBounds(0,0,screenX,screenY);
setBackground(background);
contentPane.add(this);
setFocusable(true);
requestFocusInWindow();
singleJButton = new JButton();
singleJButton.setBounds(100, 100, 100, 50);
singleJButton.setText("Single Player");
singleJButton.setFocusable(false);
contentPane.add(singleJButton);
singleJButton.addActionListener(new ActionListener()
{public void actionPerformed( ActionEvent event )
{singleJButtonAction(event);}});
runningTimer = new Timer( 30, new ActionListener()
{public void actionPerformed( ActionEvent event )
{}});
runningTimer.start();
}
public Timer getTimer()
{
return runningTimer;
}
public int getButton()
{
return buttonPressed;
}
public void setButton(int val)
{
buttonPressed = val;
}
private void singleJButtonAction(ActionEvent e)
{
runningTimer.stop();
buttonPressed = 1;
}
//make this panel have focus
public void focus()
{
requestFocusInWindow();
}

What, is it not working? I'm just guessing because you don't say.
The first thing I see if you're creating and removing panes dynamically. It would be more efficient to just hide them. Of course, I don't know what your layout looks like. The other option is to just construct them on startup with all your other GUI stuff and go ahead and add and remove them, but don't recreate them based on the timer. Just show them and hide them as needed. Like this:
mainMenu.setVisible( true );
mainMenu.setVisible( false );
Every millisecond if also pretty fast. I look at ratcheting down, to say one second or so. Of course, it depends on what you're doing.
HTH

I still have problem understanding what your question is?
One thing that seems to be missing in the code is where you add the mainMenu and pongField you create. You remove them from the contentPane by contentPane.remove(pongField); and contentPane.remove(mainMenu); is that your problem?

Related

Two different buttons in one Panel in my own Component

I'm trying to create JPanel with two different buttons which one of them increasing and second decreasing size of text or window. I have class with button declaration. Everything is working when I put these buttons on JFrame separately.
I don't know how to get Action Listener in JPanel of each buttons. All I possibly do is listener of mouse click on JPanel...
Could you help me? I'm really begginer with coding so be polite please :]
public class ButtonMy extends Component {
private ButtonIncrease increase;
private PropertyChangeSupport propertyChangeSupport;
public ButtonMy() {
setPreferredSize(new Dimension(30,30));
kolor = Color.blue;
setForeground(kolor);
propertyChangeSupport = new PropertyChangeSupport(this);
increase = ButtonIncrease.Powieksz;
}
public ButtonIncrease getIncrease() {
return increase;
}
public void setIncrease(ButtonIncrease increase) {
ButtonIncrease oldIncrease = this.increase;
this.increase = increase;
propertyChangeSupport.firePropertyChange("increase", oldIncrease, increase);
}
public void addPropertyChangeListener(PropertyChangeListener l) {
propertyChangeSupport.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
propertyChangeSupport.removePropertyChangeListener(l);
}
}
There is JPanel for bind 2 buttons. Here is the biggest problem :/ I'm lack of ideas.
public class ButtonB extends JPanel implements ActionListener{
public ButtonMy b1 = new ButtonMy();
public ButtonMy b2 = new ButtonMy();
public ButtonB (){
init();
}
public final void init(){
setLayout(new GridLayout(1,2));
this.przycisk1.setIncrease(ButtonIncrease.Powieksz);
this.przycisk2.setIncrease(ButtonIncrease.Zmniejsz);
add(b1);
add(b2);
}
}
JFrame where I test this component is very common. Code below shows only function for inc and dec size when separate button is clicked (not in JPanel).
private void buttonMy3MouseClicked(java.awt.event.MouseEvent evt) {
switch(buttonMy3.getIncrease()) {
case Powieksz: setSize(1);
break;
case Zmniejsz: setSize(0);
break;
}
}
I didn't paste full of my code. There some of math functions left which I think they are not needed here (setSize for example).
I'm not sure if i understand the problem correctly but I think under the actionListener class you should have a method called actionPerformed& it will say that if button1 is clicked increase the number, if button2 is clicked decrease the number:
public void actionPerformed( ActionEvent event ) {
if (event.getSource()== b1) // your "increase size" code
if(event.getSource()== b2)// your "decrease size" code
}
button listeners are actually different from mouse listeners; buttons implements ActionListeners and have the actionPerformed method with event variable. you could handle the event by:
getSource() -this method is inherited from java.util.EventObject and returns the OBJECT on which the event initially occurred (the button itself)
or by getActionCommand() -this method is available to action events, or any event that inherits from ActionEvent and returns the command STRING associated with this action.
however mouse listeners implements MouseListener and has a lot of methods depending on what the mouse does (pressed, clicked, released, etc.).

Resize JPanel and JPopupMenu automatically on JPanel expand

I am currently facing a small issue that goes like this: I have a button which, when clicked, will trigger the display of a JPopupMenu under it ( I grab the location of the button, substract a bit from it's height and display the JPopupMenu). This is all made in NetBeans with the GUI builder.
The JPopupMenu is composed of several JPanels, which contain a JLabel, a Button, a TextField and a CheckBox. Those JPanels, I want them to be first initialized in a "minimized" mode( display only the label), but, when the user clicks on them, to expand and display the other components as well. On a second click, the JPanel will revert to the "minimized" state.
Now, I don't know exactly where the issue is, whether in the way the JPanel is resized or not, but although when I click the button the popup menu is displayed correctly and everything else, if I expand a JPanel inside it, the popup menu does not get resized -> it has the same width/height no matter what I do. I tried to change the Layout Manager used by JPopupMenu to FlowLayout,BoxLayout, but ultimately they had no effect. Now, a few snippets of points of interest in the code:
public class WifiItem extends javax.swing.JPanel {
private final Dimension maxDimension;
private final Dimension minDimension;
private boolean maximized;
public WifiItem() {
initComponents();
setBorder(BorderFactory.createLineBorder(Color.black, 1));
maxDimension = new Dimension(386, 62);
minDimension = new Dimension(386, 32);
maximized = false;
setSize(minDimension);
setPreferredSize(minDimension);
setMinimumSize(minDimension);
setMaximumSize(minDimension);
this.setPreferredSize(minDimension);
this.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (maximized) {
setToMin();
} else {
setToMax();
}
}
});
}
public final void setToMax() {
setSize(maxDimension);
setPreferredSize(maxDimension);
setMinimumSize(maxDimension);
setMaximumSize(maxDimension);
maximized = true;
getParent().revalidate();
}
public final void setToMin() {
setSize(minDimension);
setPreferredSize(minDimension);
setMinimumSize(minDimension);
setMaximumSize(minDimension);
maximized = false;
getParent().revalidate();
}
This is where I build the JPopupMenu and set up the display.
public class WifiConnections {
private static final List<WifiItem> connectionsList = new ArrayList<>();
public static JPopupMenu displayPanel;
public WifiConnections() {
displayPanel = new JPopupMenu();
displayPanel.setLayout(new BoxLayout(displayPanel, BoxLayout.Y_AXIS));
WifiItem newItem = new WifiItem();
newItem.setConnectionId("Connection 1.");
WifiItem newItem2 = new WifiItem();
newItem2.setConnectionId("Connection 2.");
connectionsList.add(newItem);
connectionsList.add(newItem2);
connectionsList.forEach((item) -> {
displayPanel.add(item);
});
}
public void displayPopup(Point p) {
displayPanel.setLocation(p.x, p.y + 34);
displayPanel.setVisible(true);
}
public void hidePopup() {
displayPanel.setVisible(false);
}
}
As you can see, if I expand one item, the other one gets covered and the popup does not resize to fit the JPanels, and I am really at a loss at how to continue.

JPanel not displaying after button pressed in another JPanel

Hi I'm building a game which includes 3 JPanels on a JFrame, a Startscreen, a DrawingPanel and a GameOver screen. If I just create the DrawingPanel and tell the GameController class to begin updating it works fine, but if I create a StartScreen with a button to start the game, then when I press the start game button the game window does not display, although the game code runs.
EDIT:
I have created a new program which mimics the creation of the JPanels, but excludes all of the game code to make it a bit simpler to follow. Below I have included all the relevant classes:
This class creates a JFrame and two JPanels. It also runs the code that updates the game state and tells the DrawingPanel to repaint.
public class TestController{
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
private final int FRAME_WIDTH = (int)screenSize.getWidth();
private final int FRAME_HEIGHT = (int)screenSize.getHeight();
public boolean gameStarted = false;
private JFrame gameWindow;
private TestDrawingPanel myDrawingPanel;
private TestStartGame startGame;
int counter;
Set<Rectangle> rects;
//creates a JFrame and all the JPanels
public TestController(String title)
{
gameWindow = new JFrame(title);
gameWindow.setSize(FRAME_WIDTH, FRAME_HEIGHT);
gameWindow.setVisible(true);
gameWindow.setResizable(false);
gameWindow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
startGame = new TestStartGame(getAvailableWidth(), getAvailableHeight());
startGame.addAL(new StartButton());
myDrawingPanel = new TestDrawingPanel(getAvailableWidth(), getAvailableHeight());
gameWindow.add(startGame);
gameWindow.add(myDrawingPanel);
myDrawingPanel.setVisible(false);
myDrawingPanel.setEnabled(false);
rects = new HashSet();
}
private int getAvailableWidth()
{
return gameWindow.getWidth() - gameWindow.getInsets().left - gameWindow.getInsets().right;
}
private int getAvailableHeight()
{
return gameWindow.getHeight() - gameWindow.getInsets().top - gameWindow.getInsets().bottom;
}
//starts the game running
public void startTheGame()
{
myDrawingPanel.setEnabled(true);
startGame.setVisible(false);
startGame.setEnabled(false);
myDrawingPanel.setVisible(true);
gameStarted = true;
update();
}
public boolean getGameStarted()
{
return gameStarted;
}
//loop that runs the game code
public void update()
{
counter = 0;
while(gameStarted)
{
updatePictureState();
myDrawingPanel.draw(rects);
myDrawingPanel.repaint();
}
}
//updates the game state
public void updatePictureState()
{
rects.clear();
for (int i = counter + 10; i < counter + 100; i = i + 10)
{
rects.add(new Rectangle(i,i,10,10));
}
}
//an action listener to be added to the start screen
private class StartButton implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
Object buttonPressed = e.getSource();
if(buttonPressed.equals(TestStartGame.start))
{
startTheGame();
}
}
}
}
This class is an extended JPanel with a single button to start the game:
public class TestStartGame extends JPanel{
private final JPanel buttons;
public static JButton start;
//creates a JPanel with a single button to start the game
public TestStartGame(int width, int height)
{
setSize(width, height);
setLayout(new GridLayout(2,1));
setBackground(Color.GREEN);
buttons = new JPanel();
buttons.setSize(width, height / 2);
buttons.setBackground(Color.red);
start = new JButton("Start");
buttons.add(start);
add(buttons, BorderLayout.SOUTH);
}
//adds an action listener to the button
public void addAL(ActionListener al)
{
start.addActionListener(al);
}
}
This class is an extended JPanel and acts as the main screen for the game, being updated to with each cycle of the game to display it's current state:
public class TestDrawingPanel extends JPanel{
Set<Rectangle> drawSet;
//creates the drawing panel and sets the size and background
public TestDrawingPanel(int width, int height)
{
setSize(width, height);
this.setBackground(Color.CYAN);
drawSet = new HashSet();
}
public void draw(Set<Rectangle> platforms)
{
drawSet.clear();
drawSet = platforms;
}
//draws the game window
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
System.out.println("works here");
g.setColor(Color.red);
for (Rectangle r : drawSet)
{
g.fillRect((int)r.getX(), (int)r.getY(), (int)r.getWidth(), (int)r.getHeight());
}
}
}
If I just add the TestDrawingPanel, it displays fine, but if I start with a TestStartScreen then when I click the start game button the TestStartScreen does not disappear and the TestDrawingPanel never displays. Interestingly, if I have both screens but do not call the update method is TestController then the start game button works correctly and the TestDrawingPanel displays, although obviously nothing happens as the update method is where the game state is changed.
I have discovered the problem is that if the TestDrawingPanel is not the only JPanel created then the call to repaint it fails.
Here:
Thread.sleep(20);
You are most likely sleeping on the Event Dispatcher Thread. That will freeze your whole application. You have to step back and look into invokeLater to ensure "correct" threading within your UI.
Problem solved courtesy of #Andrew-Thompson:
"while(gameStarted) .. No, no a thousand times no. An infinite loop will likely freeze the GUI. Use a Swing based Timer to call those code statements in the loop, in the actionPerformed method of an ActionListener"

How do I retain the new background colour of a jlabel after it has been clicked and to make it go back to default on a second click?

I want my jLabel component to have a different background colour when clicked. I have actually written my code for the background colour to change but I need it to retain the new colour after the click and go back to default on a second click. I need help on this.
private void jLabel1MouseEntered(java.awt.event.MouseEvent evt) {
jLabel1.setOpaque(true);
jLabel1.setBackground(Color.orange);
}
private void jLabel1MouseExited(java.awt.event.MouseEvent evt) {
jLabel1.setBackground(Color.white);
jLabel1.setOpaque(false);
}
private void jLabel1MouseClicked(java.awt.event.MouseEvent evt) {
jLabel1.setBackground(Color.green);
}
You should put the command in Mouse Clicked or pressed event
and you need to set the JLable setOpaque to true otherwise the background is not going to be painted because the default of opaque is false for JLabel.
i.e
private void jLabel1MouseClicked(java.awt.event.MouseEvent evt) {
jLabel1.setOpaque(true);
jLabel1.setBackground(Color.red);
}
How do I retain the new background colour of a jlabel after it has been clicked and to make it go back to default on a second click?
There are many ways to do it, but the ultimate concept is similar. You just need to keep a record of the new background colour in a variable.
In this case, I used 2 variables to retain the colour oldColor and newColor.
class MainPanel extends JPanel{ //Not necessary must be a JPanel. For e.g. only
private Color oldColor;
private Color newColor;
private JLabel lbl;
private JButton btn;
//Constructors, initializations, getters, setters not shown
public void init(){
lbl.setOpaque(true);
btn = new JButton("Click to switch color");
btn.addActionListener(new ButtonHandler());
oldColor = lbl.getBackground(); //can be any color you want
newColor = Color.GREEN; //can be any color you want
}
private class ButtonHandler implements ActionListener{
#Override
public void actionPerformed(ActionEvet e){
if(lbl.getBackground().equals(oldColor))
lbl.setBackground(newColor);
else
lbl.setBackground(oldColor);
}
}
}
If you have more colours, you can always use an array, an ArrayList or any other data structure which is suitable.
You should make a boolean that stores the state of the button
boolean isClicked = false;
And then in your action listener, check it's value, update the labels then make it the opposite of what it was
if(isClicked)
{
label.setBackground(Color.BLUE);
isClicked = false;
}
else
{
label.setBackground(Color.GRAY);
isClicked = true;
}

My Jbuttons randomly grab bits of the frame and added it to the button background when clicked

I am making a little tick tac toe game to get the hang of gui in java.
It was going very well till I ran into the problem I mentioned in the title. My Jbuttons have a transparent background. However, when my mouse entered the button, the button's background became little pieces of the background that last had focus. For Example, if my frame had the focus it would take a little bit of that and set it as the background.
By adding this.setRolloverEnabled(false) to the code it no longer had this weird bug when I hovered over it, but the bug still occurs when I click the button.
When the button is clicked it changes it icon to either an x or an o image but the problem still occurs
Here is my code for my buttons
public class Tile extends JButton implements ActionListener
{
private Board myBoard;
private int ID;
private int state; //0 = blank, 1 = x, 2 = O
private Icon x;
private Icon o;
private Icon blank;
public Tile()
{
blank = new ImageIcon(getClass().getResource("/Resources/Tiles/blank.png"));
x = new ImageIcon(getClass().getResource("/Resources/Tiles/x.png"));
o = new ImageIcon(getClass().getResource("/Resources/Tiles/o.png"));
state = 0;
setIcon(blank);
addActionListener(this);
this.setBorder(new BorderUIResource.EmptyBorderUIResource(0,0,0,0));
this.setBorderPainted(false);
this.setContentAreaFilled(false);
this.setFocusPainted(false);
this.setRolloverEnabled(false);
}
public Tile(int ID)
{
this();
this.ID = ID;
}
public Tile(int ID, Board myBoard)
{
this(ID);
this.myBoard = myBoard;
}
public void updateState(EnumTileState newState)
{
switch(newState)
{
case BLANK : state = 0;
break;
case X_STATE : state = 1;
break;
case O_STATE : state = 2;
break;
default: return;
}
update();
}
private void update()
{
switch(state)
{
case 1: this.setIcon(x);
break;
case 2: setIcon(o);
break;
default: setIcon(blank);
break;
}
}
public int getID()
{
return ID;
}
public int getState()
{
return state;
}
public void actionPerformed(ActionEvent event)
{
Tile clickedTile = (Tile) event.getSource();
if(myBoard != null)
{
myBoard.clickReceived(clickedTile.getID());
}
}
}
I would attach images but I don't have a high enough reputation so here is a link to an Imgur album
Hope I didn't make any silly mistakes when posting this. Its my first question. Anyway thanks in advance for any help you are able to provide
This has to how the paint engine deals of opaque components. Basically, when dealing with opaque components, the paint engine doesn't prepare the background the component (that is, it won't paint what is actually behind the component). Instead, it leaves it up to the component at hand to "clear" the Graphics context as is needed.
Try making the button transparent by using setOpaque(false)
Updated
The major problem is you're supply alpha based colors (new Color(0, 0, 0, 0)) to opaque components. This means that the paint engine does not consider the components it is painting to be transparent, so it makes no special effort to prepare the Graphics context, but when the component tries to fill it's content (with the background color), it is filling it with a transparent color, which is pretty much the same as not calling super.paintComponent.
Make ALL your JPanel based components transparent except the base panel.

Categories

Resources