HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

UI-based memory game

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
memorygamebased

Problem

I have created a UI shown in the screenshot. I am initalizing too many JPanels within a panel in my code to achieve the UI which will lead to bad code design and slower performance.

Is there any good practices to follow in writing such a UI?

```
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingConstants;

public class GameUI extends JFrame {

static JLabel blankCardLabel;
static JLabel cardOne;
JLabel cardTwo;
JLabel cardThree;
JLabel cardFour;
JLabel cardFive;
JLabel cardSix;
JLabel cardSeven;
JLabel cardEight;
JLabel cardNine;
JLabel cardTen;
JLabel cardEleven;
JLabel cardTwelve;
JLabel cardThirteen;
JLabel cardFourteen;
BufferedImage blankCardPic;
JLabel deck;
BufferedImage revealCardPic;
JPanel eastPanel;
JPanel southPanel;
JPanel messagePanel;
JPanel cardPanel;
BoxLayout eastPanelBL;
BoxLayout southPanelBL;
BoxLayout cardPanelBL;
JLabel playerOne = new JLabel("Player One");
JLabel playerTwo = new JLabel("Player Two");
JLabel playerThree = new JLabel("Player Three");
JLabel playerFour = new JLabel("Player Four");
JLabel c;
public GameUI() {
setLayout(new BorderLayout());

add(new JLabel("Memory Game", SwingConstants.CENTER), BorderLayout.NORTH);
/*cardOne = new JLabel("One");
cardTwo = new JLabel("Two");
cardThree = new JLabel("Three");
cardFour = new JLabel("Four");
cardFive = new JLabel("Five");
cardSix = new JLab

Solution

Goal

Alright, before diving into the code, let's take a look at the screenshot you attached and break down what you're trying to accomplish. I see the following UI components:

  • A game title area



  • A panel to keep track of whose turn it is



  • A chat area



  • The main 'game space'



From the looks of it, you've already accomplished this to some extend. You've created JPanels for each main section:

  • JPanel eastPanel



  • JPanel southPanel



  • JPanel messagePanel



  • JPanel cardPanel



The naming can be improved, but good start breaking things up!

What we want to do is break up this massive GameUI class into components that are modular, and have a single responsibility (Single Responsibility Principle). Also, I'm partial to the MVP (Model-View-Presenter) design pattern, and will be following that as we go. This isn't the only correct way to build a UI application, but I find it to be pretty intuitive once you're used to it, and is a great way to see the Single Responsibility Principle in action.

Another added benefit of splitting everything up is that we avoid a massive block of unrelated variable declarations at the top of a class :)

Design

I just mentioned the MVP pattern, so what we'll do here is outline what that looks like for each UI component (from above) and what classes will be needed.

Game Title

Frankly, this should really just be the title of the JFrame:

final JFrame frame = new JFrame("Memory Game");


Now we're left with just 3 UI components.

User Panel

The basis of MVP is that you have 3 types of classes: models, views, presenters.

  • The view is obviously what you see. The view should be very dumb, and not contain business logic (any logic that determines what should be shown if some event occurs)



  • The presenter will listen listen for events from the view, then do the business logic, then turn around and then update the view.



  • The models are mostly POJOs that keep the state of the application. The models are updated via the presenter.



That's a very over-simplified overview, so I recommend reading some other sources and looking at other examples.

With that in mind, let's look at this user panel. We will want a class to represent the UI aspect (the V in MVP):

public class UserPanelView {
    public UserPanelView() {
        // Setup all the UI elements
    }
}


We also want a presenter:

public class UserPanelPresenter {
    public UserPanelPresenter() {
        // ...
    }
}


Chat Area

Just like the User Panel, we want a view and a presenter:

public class ChatPanelView {
    public ChatPanelView() {
        // Setup all the UI elements
    }
}

public class ChatPanelPresenter {
    public ChatPanelPresenter() {
        // ...
    }
}


Game Area

Again, we want a view and a presenter:

public class GameBoardView {
    public GameBoardView() {
        // Setup all the UI elements
    }
}

public class GameBoardPresenter {
    public GameBoardPresenter() {
        // ...
    }
}


This is all fine and great, but now we're left with 6 classes that don't have any connection to each other! To remedy this, we can realize that we have a fourth (or fifth if you want to count the game title still) UI component: time entirety of the application window!

Game Window

As before:

public class MemoryGameView {
    public MemoryGameView() {
        // Setup all the UI elements
    }
}

public class MemoryGamePresenter {
    public MemoryGamePresenter() {
        // ...
    }
}


I'm also going to introduce one last class which will have our main method:

public class MemoryGameApplication {
    public static void main(String... args) {
        // ...
    }
}


The classes are still disjoint, but we're getting closer - now we have a main class to begin to tie everything together!

Bringing the classes together

Recall that earlier I had mentioned that a presenter needs to listen to the view. To accomplish this, we create a listener interface for each view which the presenter will implement. We will then inject the view into the presenter, so that the presenter can add itself as a listener to the view. That's a lot of confusing words, so put concretely, we can do the following with the Chat Area, for example:

```
public interface ChatPanelViewListener {
/**
* Method to be called when the Send button is clicked.
*/
public void onSendButtonClicked();
}

public class ChatPanelPresenter implements ChatPanelViewListener {
private final ChatPanelView view;

public ChatPanelPresenter(final ChatPanelView view) {
this.view = view;
view.addListener(this);
}

@Override
public void onSendButtonClicked() {
// ... the business logic ...
// ... call some method(s) on the view to update it ...
}
}

public class ChatPanelView {
private final List listeners;

public ChatPanelView() {
listeners = new ArrayList();
// ...
final JButton sendButton = new

Code Snippets

final JFrame frame = new JFrame("Memory Game");
public class UserPanelView {
    public UserPanelView() {
        // Setup all the UI elements
    }
}
public class UserPanelPresenter {
    public UserPanelPresenter() {
        // ...
    }
}
public class ChatPanelView {
    public ChatPanelView() {
        // Setup all the UI elements
    }
}

public class ChatPanelPresenter {
    public ChatPanelPresenter() {
        // ...
    }
}
public class GameBoardView {
    public GameBoardView() {
        // Setup all the UI elements
    }
}

public class GameBoardPresenter {
    public GameBoardPresenter() {
        // ...
    }
}

Context

StackExchange Code Review Q#129522, answer score: 3

Revisions (0)

No revisions yet.