I am making a Simon Says style game, there are four colored squares and the computer does a sequence, then you copy that, etc. and am at a point where I want to add some more advanced features. The current feature I am looking at is looking to change the color panels actual colors at the users will and being able to change them individually from one another.
How can I get the 'color panel(s)' to change to a new color via JColorChooser while keeping everything else set up?
At the moment I have it split up into a few different classes and am having issues getting them all to communicate and just work properly.
Main class(Only a snippet):
public class Simonish implements ActionListener, MouseListener {
private ColorPanel colorPanel[] = new ColorPanel[4];
private ScorePanel scorePanel = new ScorePanel();
private Menu menuBar = new Menu();
private JPanel gameBoard = new JPanel();
private Random rand = new Random();
private ArrayList<ColorPanel> compSeq = new ArrayList<ColorPanel>();
private Iterator<ColorPanel> iter;
private JFrame frame = new JFrame();
private boolean playerTurn = false;
private int speed = 500;
public Simonish(Color[] colors){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel pane = (JPanel)frame.getContentPane();
pane.setLayout(new BorderLayout());
gameBoard.setLayout(new GridLayout(2,2));
gameBoard.setPreferredSize(new Dimension(400,400));
for (int i=0;i<colorPanel.length;i++){
colorPanel[i] = new ColorPanel(colors[i]);
colorPanel[i].addMouseListener(this);
gameBoard.add(colorPanel[i]);
}
scorePanel.addStartListener(this);
frame.setJMenuBar(menuBar);
pane.add(scorePanel, BorderLayout.NORTH);
pane.add(gameBoard, BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
My Menu code (builds the menubar and implements the actions):
public class Menu extends JMenuBar {
private JMenuBar menuBar = new JMenuBar();
private JMenu settings = new JMenu("Settings");
private JMenu stats = new JMenu("Stats");
private JMenu help = new JMenu("Help");
private JMenuItem chooseColor = new JMenuItem(new ChooseColorAction("Choose Color"));
private JMenuItem colorMode = new JMenuItem(new ColorModeAction("Color Mode"));
private JMenuItem hScore = new JMenuItem("High Scores");
private JMenuItem history = new JMenuItem("History");
private JMenuItem about = new JMenuItem("About");
private JMenuItem rules = new JMenuItem("Rules");
public Menu(){
this.add(settings);
this.add(stats);
this.add(help);
settings.add(chooseColor);
settings.add(colorMode);
stats.add(hScore);
stats.add(history);
help.add(about);
help.add(rules);
}
}
Action class to house the color changing code:
public class ColorModeAction extends AbstractAction {
public ColorModeAction(String name){
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
Color[] colors = {Color.CYAN, Color.BLACK, Color.WHITE, Color.GREEN};
//new Simonish(colors);
//JOptionPane.showMessageDialog(null, "Color Mode");
}
}
Use interfaces to communicate your classes. For example; ColorModeAction needs to change colors so it should take an interface as parameter which able to change colors:
public interface ColorChanger {
public void changeColor(int index, Color newColor);
}
Make Simonish implement that interface:
public class Simonish implements ActionListener, MouseListener, ColorChanger {
public void changeColor(int index, Color new Color) {
//Change the given panel's color
}
}
Pass Simonish as parameter to the menu, and move new ColorModeAction("Color Mode") to the constructor. Then pass ColorChanger to the ColorModeAction as a parameter.
public class Menu extends JMenuBar {
...
private JMenuItem colorMode;
...
public class Menu(ColorChanger colorChanger) {
colorMode = new JMenuItem(new ColorModeAction(colorChanger, "Color Mode"));
}
}
And the new ColorModeAction:
public class ColorModeAction extends AbstractAction {
private ColorChanger colorChanger;
public ColorModeAction(ColorChanger colorChanger, String name) {
super(name);
this.colorChanger = colorChanger;
}
#Override
public void actionPerformed(ActionEvent e) {
Color[] colors = { Color.CYAN, Color.BLACK, Color.WHITE, Color.GREEN };
colorChanger.changeColor(index, Color)
}
}
It is not fully working code but I think you got the idea.
Related
I'm trying to display a grid of coloured JLabels inside a JPanel. I created a custom class PixelMatrix which extends JPanel and I populated it with a custom class Pixel which extends JLabel.
The problem is: when I put my Pixel objects inside my GridLayout in the PixelMatrix object, I don't get the number of rows and columns I desire.
This is my Pixel class:
public class Pixel extends JLabel{
private Color color = null;
private int dimension;
public Pixel(Color c, int dim) {
this.setPreferredSize(new Dimension(dim, dim));
this.dimension = dim;
this.color = c;
this.setBackground(color);
this.setOpaque(true);
}
public Pixel(int dim) {
this(new Color(0x000000), dim);
}
public Color getColor() {
return color;
}
public void setColor(Color c) {
color = c;
}
}
This is my PixelMatrix class:
public class PixelMatrix extends JPanel{
private int resolution;
private Pixel[][] pixels = null;
private GridLayout layout;
public PixelMatrix(int res) {
resolution = res;
layout = new GridLayout(0, res);
pixels = new Pixel[res][res];
for(int x = 0; x < res; x++) {
for(int y = 0; y < res; y++) {
pixels[x][y] = new Pixel(50);
this.add(pixels[x][y]);
}
}
}
}
And this is the class is use to display all the stuff:
public class EditorPanel extends JPanel{
private BorderLayout layout = new BorderLayout();
private JMenuBar menuBar = new JMenuBar();
private JMenu fileMenu = new JMenu("File");
private JMenu settingsMenu = new JMenu("Settings");
private JMenu sizeSubMenu = new JMenu("Size");
private JMenuItem newItem = new JMenuItem("New");
private JMenuItem openItem = new JMenuItem("Open...");
private JMenuItem saveItem = new JMenuItem("Save");
private JRadioButtonMenuItem size6x6Item = new JRadioButtonMenuItem("6 x 6", true);
private JRadioButtonMenuItem size8x8Item = new JRadioButtonMenuItem("8 x 8");
private ButtonGroup sizeButtonGroup = new ButtonGroup();
private PixelMatrix matrix = new PixelMatrix(6);
public EditorPanel() {
setup();
}
private void setup() {
fileMenu.add(newItem);
fileMenu.add(openItem);
fileMenu.add(saveItem);
sizeButtonGroup.add(size6x6Item);
sizeSubMenu.add(size6x6Item);
sizeButtonGroup.add(size8x8Item);
sizeSubMenu.add(size8x8Item);
settingsMenu.add(sizeSubMenu);
menuBar.add(fileMenu);
menuBar.add(settingsMenu);
this.setLayout(layout);
this.add(menuBar, BorderLayout.NORTH);
this.setPreferredSize(new Dimension(600, 600));
this.add(matrix, BorderLayout.CENTER);
}
}
And this is what I get. I don't understand what I am doing wrong.
Result
I created a custom class PixelMatrix which extends JPanel
layout = new GridLayout(0, res);
That doesn't do anything. That just creates a variable.
The default layout manager is the FlowLayout, and that hasn't been changed. The components flow one after another and wrap to the next line.
You need to set the layout of the panel if you want to use a GridLayout.
So you could do:
layout = new GridLayout(0, res);
setLayout( layout );
Or, even easier don't bother to use a variable:
setLayout( new GridLayout(0, res) );
Also, why would you call the variable "resolution". That term is normally used for the "resolution of your screen in terms of pixels". A layout has nothing to do with resolution. You area attempting to specify the "columns" in the grid, that would be a better variable name.
I have problem with JOptionPane. I have created contructor in which I defined JOptionPane. I need to create object of that class in another class where I created JFrame. The problem is that JOptionPane opens before JFrame does and I want it to be just the opposite.
Every time i create an object of the class with JOptionPane it shows up.
I simply want to JOptionPane show and change "delay" only when I click "play" on my JMenu.
public class Gameplay extends Paint implements KeyListener, ActionListener {
private Timer timer;
private int q = 0;
private int delay;
public Gameplay() {
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
timer = new Timer(delay=Integer.parseInt(JOptionPane.showInputDialog("set Speed")), this);
timer.start();
}
public class PlayGame implements IbeVisible {
JFrame f2 = new JFrame("Snake");
Gameplay gameplay = new Gameplay();
public void openGame() {
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
f2.setSize(900, 700);
f2.setResizable(false);
f2.setLocation(dim.width / 2 - f2.getWidth() / 2, dim.height / 2 - f2.getHeight() / 2);
f2.add(gameplay);
}
public void beVisible() {
f2.setVisible(true);
}
public class Menu {
PlayGame playGame = new PlayGame();
JFrame menu = new JFrame();
void create() throws IOException {
createMenuBar();
menu.setContentPane(new JLabel(new ImageIcon(ImageIO.read(new File("logo.png")))));
menu.setTitle("Menu");
menu.setVisible(true);
menu.setSize(355, 400);
menu.setResizable(false);
menu.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void createMenuBar() {
JMenuBar menubar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenuItem play = new JMenuItem("Play");
play.addActionListener((ActionEvent event) -> {
playGame.openGame();
playGame.beVisible();
});
I'm working on a text editor using Java (Swing). So far I have made the body. I'm having problem with this feature:
New (JMenuItem) (empties the content of the JTextArea).
When the user clicks on the button, the JTextArea content should be replaced with an empty string.
This is my code (I'm ommiting code that's not relevant to the problem, such as menu creation, menu items addition, only adding the classes.)
This is the TextArea class:
class MyTextArea extends JTextArea implements ActionListener {
JTextArea myTextArea;
public MyTextArea() {
init();
}
public void init(){
setLineWrap(true);
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
(Empty, as you can see.)
This is the MenuBar class:
class MyMenuBar extends JMenuBar implements ActionListener {
private JMenu mArchivo;
private JMenuItem mNuevo;
public MyMenuBar(){
init();
add(mArchivo);
}
private void init() {
mArchivo = settingUpMenus("Archivo", "Archivo", 'A');
mNuevo = settingUpMenuItems("Nuevo", "Nuevo", 'N');
mArchivo.add(mNuevo);
}
private JMenu settingUpMenus(String mTitle, String mDescription,
char mMnemonic) {
JMenu mMenu;
mMenu = new JMenu(mTitle);
mMenu.setMnemonic(mMnemonic);
mMenu.getAccessibleContext().setAccessibleDescription(mDescription);
mMenu.setActionCommand(mTitle);
mMenu.addActionListener(this::actionPerformed);
return mMenu;
}
private JMenuItem settingUpMenuItems(String mTitle, String
mDescription, char mMnemonic) {
JMenuItem mMenuItem;
mMenuItem = new JMenuItem(mTitle);
mMenuItem.setMnemonic(mMnemonic);
mMenuItem.getAccessibleContext().
setAccessibleDescription(mDescription);
mMenuItem.setActionCommand(mTitle);
mMenuItem.addActionListener(this::actionPerformed);
return mMenuItem;
}
#Override
public void actionPerformed(ActionEvent e) {
switch(e.getActionCommand()) {
case "Nuevo":
onNew();
break;
}
}
private void onNew() {
}
}
And this is the class constructor where I add the JTextArea and the JMenu with it's items and all.
public Editor() {
JScrollPane myScrollPane = new JScrollPane(new MyTextArea(),
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
systemLook();
setTitle("Text editor");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(new Dimension(800, 700));
setVisible(true);
setJMenuBar(new MyMenuBar());
add(myScrollPane);
}
However, I have tried many ways for my new button to get access to the current instance of JTextArea and to modify it, such as getting the parent classes with the ActionEvent object in the actionPerformed method inside the JMenu class. But none of the intents I have done can access to the JTextArea. Any ideas? Should I implement it another way?
Just pass it as a parameter in the constructor of the menu bar like
...
private JTextArea myTextArea;
public MyMenuBar(MyTextArea myTextArea){
init();
add(mArchivo);
this.myTextArea = myTextArea;
}
...
and in the main would look like
MyTextArea myTextArea = new MyTextArea();
JScrollPane myScrollPane = new JScrollPane(myTextArea,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
systemLook();
setTitle("Text editor");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(new Dimension(800, 700));
setVisible(true);
setJMenuBar(new MyMenuBar(myTextArea));
I am in the early stages of trying to create a Java 2d graphics paint program. I'm using a flow layout, and I'm using three panels. The first two are rows of buttons, combo boxes, etc. and the third is meant to be a large, blank, white panel that will be used to paint on. The first two panels show up beautifully, but the paint panel appears as a small white box next to the second button panel. Any help would be appreciated.
public class DrawingApp extends JFrame
{
private final topButtonPanel topPanel = new topButtonPanel();
private final bottomButtonPanel bottomPanel = new bottomButtonPanel();
private final PaintPanel paintPanel = new PaintPanel();
public DrawingApp()
{
super("Java 2D Drawings");
setLayout(new FlowLayout());
add(topPanel);
add(bottomPanel);
add(paintPanel);
}
public static void main(String[] args)
{
DrawingApp frame = new DrawingApp();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(750,500);
frame.setVisible(true);
}
}
public class topButtonPanel extends JPanel
{
private final String[] names = {"Line", "Oval", "Rectangle"};
private final JButton undo = new JButton("Undo");
private final JButton clear = new JButton("Clear");
private final JLabel shape = new JLabel("Shape:");
private final JComboBox<String> shapesComboBox = new JComboBox(names);
private final JCheckBox filled = new JCheckBox("Filled");
public topButtonPanel()
{
super();
setLayout(new FlowLayout());
add(undo);
add(clear);
add(shape);
shapesComboBox.setMaximumRowCount(3);
add(shapesComboBox);
add(filled);
}
}
public class bottomButtonPanel extends JPanel
{
private final JCheckBox useGradient = new JCheckBox("Use Gradient");
private final JButton firstColor = new JButton("1st Color");
private final JButton secondColor = new JButton("2nd Color");
private final JLabel lineWidthLabel = new JLabel("Line Width:");
private final JLabel dashLengthLabel = new JLabel("Dash Length:");
private final JTextField lineWidthField = new JTextField(2);
private final JTextField dashLengthField = new JTextField(2);
private final JCheckBox filled = new JCheckBox("Dashed");
public bottomButtonPanel()
{
super();
setLayout(new FlowLayout());
add(useGradient);
add(firstColor);
add(secondColor);
add(lineWidthLabel);
add(lineWidthField);
add(dashLengthLabel);
add(dashLengthField);
add(filled);
}
}
public class PaintPanel extends JPanel
{
public PaintPanel()
{
super();
setBackground(Color.WHITE);
setSize(700,400);
}
}
Basically, it's a misunderstanding of how the Swing API works.
Swing relies (heavily) on the layout management API which is used to make decisions about how large components should be (and where they should be placed)
Using setSize is pointless, as the layout manager will make it's own decisions about what it thinks the size of your component should be and will adjust it accordingly.
You can make suggestions to the layout manager about how large you'd like the component to be using getPreferred/Minimum/MaximumSize, for example
public class PaintPanel extends JPanel
{
public PaintPanel()
{
super();
setBackground(Color.WHITE);
}
public Dimension getPreferredSize() {
return new Dimension(700, 400);
}
}
Just remember, layout managers are well within their right to ignore these values, so you need to have a better understanding of how these managers work
See Laying Out Components Within a Container for more details
There are a number of similar posts, notably:
Java Swing JLayeredPane not showing up
and
Top layer in JLayeredPane not displaying
But none of them seem to solve my specific problem.
I have the following code:
public class PlayScreen{
private JLayeredPane playScreen;
private Player player;
private JPanel towerButtons;
private JPanel detailPanel;
private JLabel map;
public PlayScreen(Player player){
this.player = player;
playScreen = new JLayeredPane();
playScreen.setLayout(new BorderLayout());
setTowerButtons();
playScreen.add(towerButtons, BorderLayout.EAST);
playScreen.setLayer(towerButtons, 0);
setDetailLabels();
playScreen.add(detailPanel, BorderLayout.WEST);
playScreen.setLayer(detailPanel, 0);
setMap(player.getNextMap());
playScreen.add(map, BorderLayout.CENTER);
playScreen.setLayer(map, 0);
JButton playButton = new JButton("play");
playScreen.add(playButton, BorderLayout.NORTH);
playScreen.setLayer(playButton, 0);
playButton.addActionListener(new playListener());
playScreen.setVisible(true);
}
where setTowerButtons(), setDetailLabels() and setMap() methods called in the constructor basically initialize the towerButtons, detailPanel and map fields.
When the "play" button is pressed, the following code is called:
public class playListener implements ActionListener{
public void actionPerformed(ActionEvent e){
Image image = null;
try{
image = ImageIO.read(new File("mob1.bmp"));
}
catch (Exception e1){
System.out.println("image creation failed");
}
ImageIcon img = new ImageIcon(image);
JLabel mob1Button = new JLabel(img);
System.out.println("hi");
playScreen.add(mob1Button, BorderLayout.CENTER);
playScreen.setLayer(mob1Button, 1);
mob1Button.setVisible(true);
}
}
I know that this is definitely called, because "hi" appears on the output stream.
(The playScreen is a JLayeredPane that is constructed from this:)
public class View {
private JFrame frame;
private Container contentPane;
private Player player;
private LoadScreen loadScreen;
private PlayScreen playScreen;
public View(Player player){
frame = new JFrame("Display");
contentPane = frame.getContentPane();
contentPane.setLayout(new BorderLayout());
this.player = player;
frame.setLocationRelativeTo(null); //puts frame in middle of screen
frame.pack();
frame.setVisible(true);
}
public void makeLoadScreen(){
loadScreen = new LoadScreen();
contentPane.add(loadScreen.getLoadScreen(), BorderLayout.CENTER);
frame.pack();
}
public void makePlayScreen(Player player){
contentPane.remove(loadScreen.getLoadScreen());;
playScreen = new PlayScreen(player);
contentPane.add(playScreen.getPlayScreen());
frame.pack();
}
public class LoadScreen{
private JPanel loadScreen;
public LoadScreen(){
loadScreen = new JPanel();
JButton play = new JButton("Play");
JButton load = new JButton("Load");
loadScreen.setLayout(new GridLayout(2,1,0,0));
loadScreen.add(play);
loadScreen.add(load);
play.addActionListener(new OpenActionListener());
load.addActionListener(new LoadActionListener());
}
public JPanel getLoadScreen(){
return loadScreen;
}
public class OpenActionListener implements ActionListener{
public void actionPerformed(ActionEvent e){
makePlayScreen(player);//might not be receiving correct player variable?
}
}
public class LoadActionListener implements ActionListener{
public void actionPerformed(ActionEvent e){
}
}
}
}
public GameManager(){
player = new Player();
player.setNextMap("map.bmp");
//Tower tower = new Tower1();
//player.addUnlockedTower(tower);
view = new View(player);
view.makeLoadScreen();
}
A GameManager Class is created. This creates the loadScreen, which has two buttons, "play" and "load." Clicking on "play" creates the playScreen, which is governed by a separate class.
Sorry for all the code, but I have no idea anymore where it is going wrong, I thought it was to do with not setting the sizes of the playScreen, towerButtons etc, as in the similar post, but that didn't seem to work when I added preferred /min / max sizes.
Currently an image of the map comes up, but the image of the "mob1" does not appear at all, and I would expect it to overlay the map image.