I'm using a JPopupMenu which contains multiple jCheckBoxMenuItem. User can check/uncheck several CheckBox. But when I click on JFrame the PopupMenu is not hiding.
This the entire code.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PopupTest extends JFrame {
JButton button1;
public PopupTest() {
setTitle("Popup Test !");
setSize(400, 400);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
button1 = new JButton("Click me!");
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int count = 250; // this count value is dynamic
JPopupMenu menu = new JPopupMenu();
JCheckBoxMenuItem item = null;
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
JScrollPane scrollPane = new JScrollPane(panel,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setPreferredSize(new Dimension(125, 200));
for (int i = 1; i <= count; i++) {
item = new JCheckBoxMenuItem("Page : " + i, new ImageIcon("test.png"));
item.setHorizontalTextPosition(JMenuItem.RIGHT);
item.addActionListener(new OpenAction(menu, button1));
panel.add(item);
}
menu.add(scrollPane);
JCheckBoxMenuItem selectAll = new JCheckBoxMenuItem("Select All", new ImageIcon("test.png"));
selectAll.addActionListener(new OpenAction(menu, button1));
menu.insert(selectAll, 0);
if (!menu.isVisible()) {
Point p = button1.getLocationOnScreen();
menu.setLocation((int) p.getX(), (int) p.getY() + button1.getHeight());
menu.setVisible(true);
} else {
menu.setVisible(false);
}
}
});
add(button1);
}
private static class OpenAction implements ActionListener {
private JPopupMenu menu;
private JButton button;
private OpenAction(JPopupMenu menu, JButton button) {
this.menu = menu;
this.button = button;
}
#Override
public void actionPerformed(ActionEvent e) {
String chkBoxText = e.getActionCommand().toString();
AbstractButton aButton = (AbstractButton) e.getSource();
boolean selected = aButton.getModel().isSelected();
Icon checkedIcon = new ImageIcon("test1.png");
Icon uncheckedIcon = new ImageIcon("test.png");
JScrollPane pane = null;
JViewport viewport = null;
JPanel panel = null;
JCheckBoxMenuItem item = null;
pane = (JScrollPane) menu.getComponent(1); //0th component is "Select All" check box
viewport = pane.getViewport();
panel = (JPanel) viewport.getComponent(0);
int totalChkBoxComponent = panel.getComponentCount();
if (selected) {
System.out.println(chkBoxText + " is Checked!");
if (chkBoxText.trim().equalsIgnoreCase("select all")) {
for (int i = 0; i < totalChkBoxComponent; i++) {
item = (JCheckBoxMenuItem) panel.getComponent(i);
item.setSelected(selected);
item.setIcon(item.isSelected() ? checkedIcon : uncheckedIcon);
}
}
} else if (!selected) {
System.out.println(chkBoxText + " is Un-Checked!");
if (chkBoxText.trim().equalsIgnoreCase("select all")) {
for (int i = 0; i < totalChkBoxComponent; i++) {
item = (JCheckBoxMenuItem) panel.getComponent(i);
item.setSelected(selected);
item.setIcon(item.isSelected() ? checkedIcon : uncheckedIcon);
}
} else { // this is for, after checking "Select All", if any other is unchecked, then "Select ALL" should be unchecked.
item = (JCheckBoxMenuItem) menu.getComponent(0);
item.setSelected(selected);
item.setIcon(selected ? checkedIcon : uncheckedIcon);
}
}
aButton.setIcon(aButton.isSelected() ? checkedIcon : uncheckedIcon);
}
}
public static void main(String args[]) {
new PopupTest();
}
}
Please help. Thanks.
First of all, your code is not really the best way to do such thing. You shouldn't create a new menu each time the button is clicked but rather create it once and keep a reference to it as field.
The reason PopupMenu does not hide is that you explicitly call setVisible(true); and you try to setVisible(false); in the very same ActionListener which is assigned to the button, not the frame.
You could:
1. Add another listener to the frame to set menu visiblity to false when clicked
2. Use show method instead of setVisible:
menu.show(button1, 0, button1.getHeight());
instead of
menu.setLocation((int) p.getX(), (int) p.getY() + button1.getHeight());
menu.setVisible(true);
However in our case, this causes other issues with menu disappearing. IMO the best way is to redesign your code.
Related
I want to add a number of buttons to a JPanel dynamically, When I add it only shows a fixed number of buttons,
So I would like to add a left right moving for viewing all buttons
How we can do this, Is there any java component to do this?
public class TestJPanel extends JFrame {
JPanel statusBar;
public TestJPanel() {
setLayout(new BorderLayout());
statusBar = new JPanel();
statusBar.setLayout(new BoxLayout(statusBar, BoxLayout.LINE_AXIS));
add("South", statusBar);
for (int i = 1; i < 20; i++) {
statusBar.add(new Button("Button" + i));
}
} }
Here is some old code I had lying around that will automatically add/remove left/right buttons as required:
import java.awt.*;
import java.util.List;
import java.util.ArrayList;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.basic.*;
public class ScrollContainer extends JPanel
implements ActionListener, ComponentListener
{
private Container container;
private List<Component> removedComponents = new ArrayList<Component>();
private JButton forwardButton;
private JButton backwardButton;
public ScrollContainer(Container container)
{
this.container = container;
setLayout( new BorderLayout(5, 0) );
addComponentListener( this );
// Create buttons to control scrolling
backwardButton = new BasicArrowButton( BasicArrowButton.WEST );
configureButton( backwardButton );
forwardButton = new BasicArrowButton( BasicArrowButton.EAST);
configureButton( forwardButton );
// Layout the panel
add( backwardButton, BorderLayout.WEST );
add( container );
add( forwardButton, BorderLayout.EAST );
}
// Implement the ComponentListener
public void componentResized(ComponentEvent e)
{
// When all components cannot be shown, add the forward button
int freeSpace = getSize().width - container.getPreferredSize().width;
if (backwardButton.isVisible())
freeSpace -= backwardButton.getPreferredSize().width;
forwardButton.setVisible( freeSpace < 0 );
// We have free space, redisplay removed components
while (freeSpace > 0 && ! removedComponents.isEmpty())
{
if (removedComponents.size() == 1)
freeSpace += backwardButton.getPreferredSize().width;
Object o = removedComponents.get(removedComponents.size() - 1);
Component c = (Component)o;
freeSpace -= c.getSize().width;
if (freeSpace >= 0)
{
container.add(c, 0);
removedComponents.remove(removedComponents.size() - 1);
}
}
// Some components still not shown, add the backward button
backwardButton.setVisible( !removedComponents.isEmpty() );
// repaint();
}
public void componentMoved(ComponentEvent e) {}
public void componentShown(ComponentEvent e) {}
public void componentHidden(ComponentEvent e) {}
// Implement the ActionListener
public void actionPerformed(ActionEvent e)
{
Object source = e.getSource();
// Scroll the components in the container
if (source == forwardButton)
scrollForward();
else
scrollBackward();
}
/*
* Simulate scrolling forward
* by remove the first component from the container
*/
private void scrollForward()
{
if (container.getComponentCount() == 1)
return;
// Remove and save the first component
Component c = container.getComponent(0);
container.remove( c );
removedComponents.add( c );
// Allow for backwards scrolling
backwardButton.setVisible( true );
// All components are showing, hide the forward button
int backwardButtonWidth = backwardButton.getPreferredSize().width;
int containerWidth = container.getPreferredSize().width;
int panelWidth = getSize().width;
if (backwardButtonWidth + containerWidth <= panelWidth)
forwardButton.setVisible( false );
// Force a repaint of the panel
revalidate();
repaint();
}
/*
* Simulate scrolling backward
* by adding a removed component back to the container
*/
private void scrollBackward()
{
if (removedComponents.isEmpty())
return;
// Add a removed component back to the container
Object o = removedComponents.remove(removedComponents.size() - 1);
Component c = (Component)o;
container.add(c, 0);
// Display scroll buttons when necessary
if (removedComponents.isEmpty())
backwardButton.setVisible( false );
forwardButton.setVisible( true );
revalidate();
repaint();
}
private void configureButton(JButton button)
{
button.setVisible( false );
button.addActionListener( this );
}
private static void createAndShowGUI()
{
JToolBar toolBar = new JToolBar();
toolBar.setFloatable(false);
toolBar.add( new JButton("one") );
toolBar.add( new JButton("two222222") );
toolBar.add( new JButton("three") );
toolBar.add( new JButton("four") );
toolBar.add( new JButton("five") );
toolBar.add( new JButton("six666666666") );
toolBar.add( new JButton("seven") );
toolBar.add( new JButton("eight") );
toolBar.add( new JButton("nine9999999") );
toolBar.add( new JButton("ten") );
ScrollContainer container = new ScrollContainer(toolBar);
JFrame frame = new JFrame("Scroll Container");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(container, BorderLayout.NORTH);
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
public TestJPanel()
{
setLayout(new BorderLayout());
statusBar = new JPanel();
statusBar.setLayout(new BoxLayout(statusBar, BoxLayout.LINE_AXIS));
JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewportView(statusBar)
add(scrollPane, BorderLayout.SOUTH);
for (int i = 1; i < 20; i++) {
statusBar.add(new Button("Button" + i));
}
}
If the look does not satisfy you, see for example Custom design JScollPane Java Swing and read about custom Look and Feels
I got one solution , we can implement left right navigation by using JViewport
public class StatusBar extends JFrame {
private final JPanel statusBar;
private final JPanel leftrightPanel;
private final JPanel myPane;
private final JButton rightButton;
private final JButton leftButton;
private final JViewport viewport;
private final JPanel iconsPanel;
private JButton button;
public StatusBar() {
setLayout(new BorderLayout());
statusBar = new JPanel();
statusBar.setLayout(new BorderLayout());
iconsPanel = new JPanel();
iconsPanel.setLayout(new BoxLayout(iconsPanel, BoxLayout.LINE_AXIS));
iconsPanel.setBackground(Color.LIGHT_GRAY);
viewport = new JViewport();
viewport.setView(iconsPanel);
leftrightPanel = new JPanel();
leftrightPanel.setBackground(Color.WHITE);
rightButton = new BasicArrowButton(BasicArrowButton.WEST);
rightButton.addActionListener((ActionEvent e) -> {
int iconsPanelStartX = iconsPanel.getX();
if (iconsPanelStartX < 0) {
Point origin = viewport.getViewPosition();
if (Math.abs(iconsPanelStartX) < 20) {
origin.x -= Math.abs(iconsPanelStartX);
} else {
origin.x -= 20;
}
viewport.setViewPosition(origin);
}
});
leftButton = new BasicArrowButton(BasicArrowButton.EAST);
leftButton.addActionListener((ActionEvent e) -> {
Point origin = viewport.getViewPosition();
origin.x += 20;
viewport.setViewPosition(origin);
});
leftrightPanel.add(rightButton);
leftrightPanel.add(leftButton);
statusBar.add(viewport);
statusBar.add(leftrightPanel, BorderLayout.LINE_END);
add(statusBar,BorderLayout.SOUTH);
myPane = new JPanel();
add(myPane, BorderLayout.CENTER);
for (int i = 1; i < 20; i++) {
button =new JButton("Button " + i);
iconsPanel.add(button);
}
}}
I have next structure: JPopupMenu contains JPanel which contains JMenuItems. The problem is, I cannot use it because JPopupMenu disappears when mouse enters to any menu item.
SSCCE:
public class PopupTest {
public static void main(String[] a) {
final JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createLineBorder(Color.RED));
panel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
final JPopupMenu menu = new JPopupMenu();
JPanel menuPanel = new JPanel();
menuPanel.setBorder(BorderFactory.createLineBorder(Color.GREEN));
menuPanel.setLayout(new BoxLayout(menuPanel, BoxLayout.Y_AXIS));
for (int i = 0; i < 10; i++) {
JMenuItem item = new JMenuItem(String.valueOf(i));
menuPanel.add(item);
}
menu.add(menuPanel);
menu.show(panel, e.getX(), e.getY());
}
}
});
frame.setContentPane(panel);
frame.setUndecorated(true);
frame.setBackground(new Color(50, 50, 50, 200));
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
frame.setVisible(true);
}
});
}
}
BTW, problem does not repeats when there is no JPanel between JPopupMenu and its items.
Does anyone know how to prevent that?
Not directly answering your question but I think, you are unnecessarily adding a panel with box layout to JPopupMenu when it supports adding JMenuitem directly to it. check the following code fragment:
final JPopupMenu menu = new JPopupMenu();
JPanel menuPanel = new JPanel();
menuPanel.setBorder(BorderFactory.createLineBorder(Color.GREEN));
// menuPanel.setLayout(new BoxLayout(menuPanel, BoxLayout.Y_AXIS));
for (int i = 0; i < 10; i++) {
JLabel item = new JLabel(i+"");
menuPanel.add(item);
}
menu.add(menuPanel);
menu.show(panel, e.getX(), e.getY());
Some tips:
Define your pop up menu just once instead every time a button is pressed.
You need to override mouseReleased or mousePressed method: Bringing Up a Popup Menu
Use MouseEvent.isPopupTrigger to find out if pop up should be shown.
Add menuItems directly to menu and not to a JPanel
Suggested changes:
final JPopupMenu menu = new JPopupMenu();
menu.setLayout(new GridLayout(2,5)); // How do you can, for example, lay out your menu items horizontally in 2 rows?
for (int i = 0; i < 10; i++) {
JMenuItem item = new JMenuItem(String.valueOf(i));
menu.add(item);
}
MouseListener mouseListener = new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
if(e.isPopupTrigger()){
menu.show(panel, e.getX(), e.getY());
}
}
};
panel.addMouseListener(mouseListener);
Picture
I'm writing a program in Java where I'm using JTabbedPane. Each tab is associated with a different panel with labels, textfields and a button. I have used GridBagLayout in the panels.
I have added an actionlistener to the button, but when I click it nothing happens.
EDIT: I also have other buttons outside the JTabbedPane which works perfectly fine.
I can see that nothing is happening because I do this:
public void actionPerformed( ActionEvent e ) {
if ( e.getSource() == button ) {
System.out.println("blablabla");
}
and nothing is printed out.
Is there any common problems with using buttons and GridBagLayout/JTabbedPane?
EDIT with SSCCE
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.*;
public class Hjelp extends JFrame {
private FlowLayout layout;
private JButton button1;
private JButton button2;
private JPanel menu, frontpage;
private JPanel present, previous, something;
public Hjelp() {
layout = new FlowLayout(FlowLayout.CENTER, 10, 20);
setLayout(layout);
setSize(900, 900);
setLocationRelativeTo(null);
setVisible(true);
setPanels();
something = something();
add(something, BorderLayout.CENTER);
something.setVisible(false);
button1 = new JButton("CLICK ME");
add(button1);
buttonListener();
}
private void buttonListener() {
Buttonlistener listener = new Buttonlistener();
button1.addActionListener(listener);
button2.addActionListener(listener);
}
private void setPanels() {
menu = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 0));
frontpage = new JPanel();
previous = frontpage;
present = frontpage;
add(menu);
}
public void visiblePanel() {
previous.setVisible(false);
present.setVisible(true);
}
private JPanel something() {
visiblePanel();
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1, 1));
JTabbedPane tabbedPane = new JTabbedPane();
JComponent panel1 = tab();
tabbedPane.addTab("Click me", panel1);
tabbedPane.setMnemonicAt(0, KeyEvent.VK_1);
tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
panel.add(tabbedPane);
return panel;
}
private JComponent tab() {
JPanel panel = new JPanel(false);
panel.setPreferredSize(new Dimension(870, 300));
panel.setLayout(new GridBagLayout());
GridBagConstraints cs = new GridBagConstraints();
cs.fill = GridBagConstraints.HORIZONTAL;
button2 = new JButton("Click me");
cs.gridx = 1;
cs.gridy = 6;
cs.gridwidth = 1;
panel.add(button2, cs);
return panel;
}
private class Buttonlistener implements ActionListener {
#Override
public void actionPerformed( ActionEvent e ) {
if ( e.getSource() == button1 ) {
present = something;
button1.setVisible(false);
something();
previous = something;
}
else if (e.getSource() == button2) {
System.out.println("Blablabla");
}
}
}
public static void main(String [] args) {
final Hjelp vindu = new Hjelp();
vindu.addWindowListener(
new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
} );
}
}
SOLVED
Solution
You don't need the getSource check at all—your listener is (hopefully) attached to just one button, so if it was invoked, that already means the button was clicked. Remove the check and unconditionally print your string. If you still don't see anything, then you have a problem.
You may not have attached a handler to the actual button, and therefore the event will never get called.
Part 1:
ButtonHandler handler = new ButtonHandler();
button.addActionListener( handler );
Part 2:
public class ButtonHandler implements ActionListener
{
#Override
public void actionPerformed(ActionEvent event) {
}
}
ALSO: Java GUI can be finicky, rather than using "e.getSource() == button" you could try "button..isFocusOwner()"
I am designing a GUI to emulate a Nurikabe game (description here). I basically have two JPanels, and when one of buttons in the control panel (panel 2) is clicked, I want to change the buttons in the game panel (panel 1).
Panel 1 has 36 buttons, either non-clickable buttons displaying numbers or clickable blank buttons, all contained in a GridLayout.
Panel 2 has three buttons, new puzzle, check puzzle, and reset current puzzle.
The problem I am running into is that I cannot figure out how to change Panel 1's buttons when either the reset or new puzzle button is clicked without having to display a new window.
Is there a way to do this?
Code: (I have removed the check puzzle and reset puzzle buttons)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SSCCE extends JFrame {
private static final int[][] puzzle1 = { { 0, 1 }, { 1, 0 } };
private static final int[][] puzzle2 = { { 1, 0 }, { 0, 1 } };
private int[][] puzzle;
private JFrame frame;
private JPanel gridPanel;
private JPanel buttonPanel;
public SSCCE(final int puzzleNum) {
frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
if (puzzleNum == 1) {
puzzle = puzzle1;
} else {
puzzle = puzzle2;
}
setLayout(new BorderLayout());
gridPanel = new JPanel(new GridLayout(2, 2));
for (int i = 0; i < this.puzzle.length; i++) {
for (int j = 0; j < this.puzzle[0].length; j++) {
JButton button;
if (this.puzzle[i][j] > 0) {
button = new JButton("" + this.puzzle[i][j]);
} else {
button = new JButton();
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
JButton temp = ((JButton) event.getSource());
if (temp.getBackground() == Color.BLACK) {
// if the button is black, set it to white
temp.setBackground(Color.WHITE);
} else if (temp.getBackground() == Color.WHITE) {
// if the button is white, set it to black
temp.setBackground(Color.BLACK);
}
}
});
}
button.setBorderPainted(false);
button.setContentAreaFilled(false);
button.setOpaque(true);
button.setBackground(Color.WHITE);
gridPanel.add(button);
}
}
buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
JButton changePuzzle = new JButton("New Puzzle");
changePuzzle.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
loadNewPuzzle(puzzleNum);
}
});
buttonPanel.add(changePuzzle);
add(gridPanel, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
setTitle("SSCCE");
setLocation(100, 100);
pack();
setSize(150, 150);
}
private void loadNewPuzzle(int puzzleNum) {
if (puzzleNum == 1) {
puzzleNum = 2;
} else {
puzzleNum = 1;
}
// I know this is the wrong way to do it, but I'm not sure how
// to do it.
SSCCE newGame = new SSCCE(puzzleNum);
newGame.setVisible(true);
}
public static void main(String[] args) {
SSCCE game = new SSCCE(1);
game.setVisible(true);
}
}
// suppose you want to make button 2 visible and hide button 1 in panel 1 on clicking
// button 3 from panel 2, you can do something like this:
// add everything you want to display or not in respective panels.
// Then the contents that you dont want to get displayed,make them invisible by calling
setVisible(false).
// Then for button 3 in panel 2, write actionlistener like this:
button3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
// make the visible buttons invisible by using setVisible(false);
// make the invisible buttons visible by using setVisible(true);
}
});
Post some code.
As long as you have references to the JPanels or JButtons, you are free to change them as you see fit. You can remove components, add components etc.
You might use a CardLayout.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class tictac2 implements ActionListener{
static boolean blue = true; //used to keep track of turns. if true, blue's turn, else, red's turn. Blue is x, red is o
static int bWins = 0, rWins = 0;
JFrame mainWindow;
JPanel board;
JButton[] buttons;
public tictac2() {
init();
}
private void init() {
try { //Try to set the L&F to system
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e) {
e.toString();
System.out.println("Couln't change look and feel. Using default");
}
mainWindow = new JFrame("Tic Tac Toe!");
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setVisible(true);
mainWindow.setSize(800,600);
JMenuBar bar = new JMenuBar(); //Menu bar init
JMenu file = new JMenu("File");
JMenuItem newGame = new JMenuItem("New Game"), quitItem = new JMenuItem("Quit");
file.add(newGame);
file.addSeparator();
file.add(quitItem);
bar.add(file);
mainWindow.getContentPane().add(bar, BorderLayout.NORTH); //Menu bar done
newGameBoard(); //New Game Board
JPanel infoPane = new JPanel();
infoPane.setLayout(new GridLayout(1,3));
JLabel turn = new JLabel("Blue Player's Turn"), spacer = new JLabel(""), score = new JLabel("Blue: 0, Red: 0");
infoPane.add(turn);
infoPane.add(spacer);
infoPane.add(score);
mainWindow.getContentPane().add(infoPane,BorderLayout.SOUTH);
newGame.addActionListener(this); //Add action listeners
quitItem.addActionListener(this);
}
private void newGameBoard() {
board = new JPanel(); //Game Pane init
board.setLayout(new GridLayout(3,3));
buttons = new JButton[9];
for (int i = 0; i <9; i++){
buttons[i] = new JButton("");
buttons[i].setOpaque(true);
buttons[i].setFont(new Font("sansserif", Font.BOLD, 90));
board.add(buttons[i]);
buttons[i].addActionListener(this);
}
mainWindow.getContentPane().add(board,BorderLayout.CENTER); //Finish game pane init
}
public void actionPerformed(ActionEvent e){
if (e.getSource() instanceof JButton){
JButton j = (JButton)e.getSource();
j.setForeground(tictac2.blue ? Color.BLUE:Color.RED);
j.setText(tictac2.blue ? "X" : "O");
j.setEnabled(false);
tictac2.blue = !tictac2.blue;
}
else if (e.getSource() instanceof JMenuItem){
JMenuItem j = (JMenuItem) e.getSource();
if (j.getText().equals("Quit")) {
System.exit(0);
}
else if (j.getText().equals("New Game")) {
board.removeAll();
mainWindow.remove(board);
board = null;
for (int i = 0; i < 9; i++) {
buttons[i] = null;
}
newGameBoard();
tictac2.bWins = 0;
tictac2.rWins = 0;
tictac2.blue = true;
mainWindow.repaint(100);
}
}
}
public static void main(String[] args) {
new tictac2();
}
}
I am working on a tic tac toe program. In it I have 2 buttons. Whenever I hit new game, the newGameBoard function is supposed to run and make a new board. However, the screen just goes blank! I can't figure it out and would appreciate help. Sorry if I am not posting in the correct format, I am new here.
Thanks so much!
Move mainWindow.setVisible(true) to the end of init(). You don't want to set the frame to visible until you've added everything to it. That way it will validate and layout its subcomponents.
Another solution is to manually call mainWindow.validate() at the end of init(). That's what you have to do if you add components to the frame after making it visible.
use paintAll() or validate() on mainWindow:
mainWindow.validate();
instead of :
mainWindow.repaint(100);
validate and paintAll() as described in API doc.
Your changed code looks like:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class TicTac2 implements ActionListener{
static boolean blue = true; //used to keep track of turns. if true, blue's turn, else, red's turn. Blue is x, red is o
static int bWins = 0, rWins = 0;
JFrame mainWindow;
JPanel board;
JButton[] buttons;
public TicTac2() {
init();
}
private void init() {
try { //Try to set the L&F to system
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e) {
e.toString();
System.out.println("Couln't change look and feel. Using default");
}
mainWindow = new JFrame("Tic Tac Toe!");
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setVisible(true);
mainWindow.setSize(800,600);
JMenuBar bar = new JMenuBar(); //Menu bar init
JMenu file = new JMenu("File");
JMenuItem newGame = new JMenuItem("New Game"), quitItem = new JMenuItem("Quit");
file.add(newGame);
file.addSeparator();
file.add(quitItem);
bar.add(file);
mainWindow.getContentPane().add(bar, BorderLayout.NORTH); //Menu bar done
newGameBoard(); //New Game Board
JPanel infoPane = new JPanel();
infoPane.setLayout(new GridLayout(1,3));
JLabel turn = new JLabel("Blue Player's Turn"), spacer = new JLabel(""), score = new JLabel("Blue: 0, Red: 0");
infoPane.add(turn);
infoPane.add(spacer);
infoPane.add(score);
mainWindow.getContentPane().add(infoPane,BorderLayout.SOUTH);
newGame.addActionListener(this); //Add action listeners
quitItem.addActionListener(this);
}
private void newGameBoard() {
board = new JPanel(); //Game Pane init
board.setLayout(new GridLayout(3,3));
buttons = new JButton[9];
for (int i = 0; i <9; i++){
buttons[i] = new JButton("");
buttons[i].setOpaque(true);
buttons[i].setFont(new Font("sansserif", Font.BOLD, 90));
board.add(buttons[i]);
buttons[i].addActionListener(this);
}
mainWindow.getContentPane().add(board,BorderLayout.CENTER); //Finish game pane init
}
public void actionPerformed(ActionEvent e){
if (e.getSource() instanceof JButton){
JButton j = (JButton)e.getSource();
j.setForeground(TicTac2.blue ? Color.BLUE:Color.RED);
j.setText(TicTac2.blue ? "X" : "O");
j.setEnabled(false);
TicTac2.blue = !TicTac2.blue;
}
else if (e.getSource() instanceof JMenuItem){
JMenuItem j = (JMenuItem) e.getSource();
if (j.getText().equals("Quit")) {
System.exit(0);
}
else if (j.getText().equals("New Game")) {
board.removeAll();
mainWindow.remove(board);
board = null;
for (int i = 0; i < 9; i++) {
buttons[i] = null;
}
newGameBoard();
TicTac2.bWins = 0;
TicTac2.rWins = 0;
TicTac2.blue = true;
mainWindow.validate();
//mainWindow.repaint();
}
}
}
public static void main(String[] args) {
new TicTac2();
}
}