i'm making a program, and I have 1 JFrame with JDesktopPane in this frame i open two JInternalFrame and I want to pass data between this two JInternalFrame but with JTextField.
I'm just made to pass the data but it doesn't update the JInternalFrame that i want to show. But if i choose to open again it show me the data.
Please Help me!
THANKS
In this JInternalFrame 2 i sent the data to another JInternalFrame 1
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
String word = jTxtIDACA.getText();
DatosPersonales frame = new DatosPersonales();
frame.getData(word);
frame.setVisible(true);
this.getDesktopPane().add(frame);
this.dispose();
}
this is JInternalFrame 1 and i have
public void getData(String word){
initComponents();
this.word = word;
jTxtIDACA.setText(word);
}
The basic idea is you want some kind of model, which holds the data and use Observer Pattern to provide notification to interested parties when the model changes in some way.
The two JInternalFrames would then be able to share that model, one could update it and the other could monitor for changes to it (strictly speaking the relationship can work both ways, but we'll leave that alone for the moment)...
Now, because I never know what or how people might like to use the model, I always start with an interface and the provide an abstract implementation and some kind of default implementation if I feel it's required....
public interface FruitBowl {
public void addFruit(String fruit);
public void removeFruit(String fruit);
public List<String> getFruit();
public void addFruitBowlListener(FruitBowlListener listener);
public void removeFruitBowlListener(FruitBowlListener listener);
}
public abstract class AbstractFruitBowl implements FruitBowl {
private EventListenerList listenerList;
public AbstractFruitBowl() {
}
protected EventListenerList getEventListenerList() {
if (listenerList == null) {
listenerList = new EventListenerList();
}
return listenerList;
}
#Override
public void addFruitBowlListener(FruitBowlListener listener) {
getEventListenerList().add(FruitBowlListener.class, listener);
}
#Override
public void removeFruitBowlListener(FruitBowlListener listener) {
getEventListenerList().remove(FruitBowlListener.class, listener);
}
protected void fireFruitAdded(String fruit) {
FruitBowlListener[] listeners = getEventListenerList().getListeners(FruitBowlListener.class);
if (listeners.length > 0) {
FruitBowlEvent evt = new FruitBowlEvent(this, fruit);
for (FruitBowlListener listener : listeners) {
listener.fruitAdded(evt);
}
}
}
protected void fireFruitRemoved(String fruit) {
FruitBowlListener[] listeners = getEventListenerList().getListeners(FruitBowlListener.class);
if (listeners.length > 0) {
FruitBowlEvent evt = new FruitBowlEvent(this, fruit);
for (FruitBowlListener listener : listeners) {
listener.fruitRemoved(evt);
}
}
}
}
public class DefaultFruitBowl extends AbstractFruitBowl {
private List<String> fruits;
public DefaultFruitBowl() {
fruits = new ArrayList<>(25);
}
#Override
public void addFruit(String fruit) {
fruits.add(fruit);
fireFruitAdded(fruit);
}
#Override
public void removeFruit(String fruit) {
fruits.remove(fruit);
fireFruitRemoved(fruit);
}
#Override
public List<String> getFruit() {
return Collections.unmodifiableList(fruits);
}
}
Next we need to define the observer pattern contract through the use of listeners...
public class FruitBowlEvent extends EventObject {
private String fruit;
public FruitBowlEvent(FruitBowl fruitBowl, String fruit) {
super(fruitBowl);
this.fruit = fruit;
}
public FruitBowl getFruitBowl() {
return (FruitBowl)getSource();
}
public String getFruit() {
return fruit;
}
}
public interface FruitBowlListener extends EventListener {
public void fruitAdded(FruitBowlEvent evt);
public void fruitRemoved(FruitBowlEvent evt);
}
Next, we define the UI...
public class TestModel {
public static void main(String[] args) {
new TestModel();
}
public TestModel() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
FruitBowl fb = new DefaultFruitBowl();
JDesktopPane dp = new JDesktopPane() {
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 200);
}
};
JInternalFrame manager = new JInternalFrame("Fruit Bowl Manager", true, true, true, true);
manager.add(new FruitBowelManagerPane(fb));
manager.setVisible(true);
manager.setBounds(0, 0, 200, 200);
JInternalFrame monitor = new JInternalFrame("Fruit Bowl Monitor", true, true, true, true);
monitor.add(new FruitBowelMonitorPane(fb));
monitor.setVisible(true);
monitor.setBounds(200, 0, 200, 200);
dp.add(manager);
dp.add(monitor);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(dp);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public abstract class AbstractFruitPane extends JPanel {
private FruitBowl fruitBowl;
public AbstractFruitPane(FruitBowl fruitBowl) {
this.fruitBowl = fruitBowl;
}
public FruitBowl getFruitBowl() {
return fruitBowl;
}
}
public class FruitBowelManagerPane extends AbstractFruitPane {
private String[] fruits = {"Banana", "Strewberry", "Pear", "Peach", "Orange"};
private JButton giver;
private JButton taker;
public FruitBowelManagerPane(FruitBowl fruitBowl) {
super(fruitBowl);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = 1;
giver = new JButton("Add fruit");
taker = new JButton("Remove fruit");
taker.setEnabled(false);
giver.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String fruit = fruits[(int)(fruits.length * Math.random())];
getFruitBowl().addFruit(fruit);
taker.setEnabled(true);
}
});
taker.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
List<String> fruits = getFruitBowl().getFruit();
String eat = fruits.get((int)(fruits.size() * Math.random()));
getFruitBowl().removeFruit(eat);
if (getFruitBowl().getFruit().isEmpty()) {
taker.setEnabled(false);
}
}
});
add(giver, gbc);
add(taker, gbc);
}
}
public class FruitBowelMonitorPane extends AbstractFruitPane {
private JLabel label;
public FruitBowelMonitorPane(FruitBowl fruitBowl) {
super(fruitBowl);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
label = new JLabel("I'm watching you...");
add(label);
fruitBowl.addFruitBowlListener(new FruitBowlListener() {
#Override
public void fruitAdded(FruitBowlEvent evt) {
label.setText("You added " + evt.getFruit());
}
#Override
public void fruitRemoved(FruitBowlEvent evt) {
if (getFruitBowl().getFruit().isEmpty()) {
label.setText("You ate all the fruit!");
} else {
label.setText("You ate my " + evt.getFruit());
}
}
});
}
}
}
Updated with combined example
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EventListener;
import java.util.EventObject;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.EventListenerList;
public class TestModel {
public static void main(String[] args) {
new TestModel();
}
public TestModel() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
FruitBowl fb = new DefaultFruitBowl();
JDesktopPane dp = new JDesktopPane() {
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 200);
}
};
JInternalFrame manager = new JInternalFrame("Fruit Bowl Manager", true, true, true, true);
manager.add(new FruitBowelManagerPane(fb));
manager.setVisible(true);
manager.setBounds(0, 0, 200, 200);
JInternalFrame monitor = new JInternalFrame("Fruit Bowl Monitor", true, true, true, true);
monitor.add(new FruitBowelMonitorPane(fb));
monitor.setVisible(true);
monitor.setBounds(200, 0, 200, 200);
dp.add(manager);
dp.add(monitor);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(dp);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public abstract class AbstractFruitPane extends JPanel {
private FruitBowl fruitBowl;
public AbstractFruitPane(FruitBowl fruitBowl) {
this.fruitBowl = fruitBowl;
}
public FruitBowl getFruitBowl() {
return fruitBowl;
}
}
public class FruitBowelManagerPane extends AbstractFruitPane {
private String[] fruits = {"Banana", "Strewberry", "Pear", "Peach", "Orange"};
private JButton giver;
private JButton taker;
public FruitBowelManagerPane(FruitBowl fruitBowl) {
super(fruitBowl);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = 1;
giver = new JButton("Add fruit");
taker = new JButton("Remove fruit");
taker.setEnabled(false);
giver.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String fruit = fruits[(int) (fruits.length * Math.random())];
getFruitBowl().addFruit(fruit);
taker.setEnabled(true);
}
});
taker.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
List<String> fruits = getFruitBowl().getFruit();
String eat = fruits.get((int) (fruits.size() * Math.random()));
getFruitBowl().removeFruit(eat);
if (getFruitBowl().getFruit().isEmpty()) {
taker.setEnabled(false);
}
}
});
add(giver, gbc);
add(taker, gbc);
}
}
public class FruitBowelMonitorPane extends AbstractFruitPane {
private JLabel label;
public FruitBowelMonitorPane(FruitBowl fruitBowl) {
super(fruitBowl);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
label = new JLabel("I'm watching you...");
add(label);
fruitBowl.addFruitBowlListener(new FruitBowlListener() {
#Override
public void fruitAdded(FruitBowlEvent evt) {
label.setText("You added " + evt.getFruit());
}
#Override
public void fruitRemoved(FruitBowlEvent evt) {
if (getFruitBowl().getFruit().isEmpty()) {
label.setText("You ate all the fruit!");
} else {
label.setText("You ate my " + evt.getFruit());
}
}
});
}
}
public class FruitBowlEvent extends EventObject {
private String fruit;
public FruitBowlEvent(FruitBowl fruitBowl, String fruit) {
super(fruitBowl);
this.fruit = fruit;
}
public FruitBowl getFruitBowl() {
return (FruitBowl) getSource();
}
public String getFruit() {
return fruit;
}
}
public interface FruitBowlListener extends EventListener {
public void fruitAdded(FruitBowlEvent evt);
public void fruitRemoved(FruitBowlEvent evt);
}
public interface FruitBowl {
public void addFruit(String fruit);
public void removeFruit(String fruit);
public List<String> getFruit();
public void addFruitBowlListener(FruitBowlListener listener);
public void removeFruitBowlListener(FruitBowlListener listener);
}
public abstract class AbstractFruitBowl implements FruitBowl {
private EventListenerList listenerList;
public AbstractFruitBowl() {
}
protected EventListenerList getEventListenerList() {
if (listenerList == null) {
listenerList = new EventListenerList();
}
return listenerList;
}
#Override
public void addFruitBowlListener(FruitBowlListener listener) {
getEventListenerList().add(FruitBowlListener.class, listener);
}
#Override
public void removeFruitBowlListener(FruitBowlListener listener) {
getEventListenerList().remove(FruitBowlListener.class, listener);
}
protected void fireFruitAdded(String fruit) {
FruitBowlListener[] listeners = getEventListenerList().getListeners(FruitBowlListener.class);
if (listeners.length > 0) {
FruitBowlEvent evt = new FruitBowlEvent(this, fruit);
for (FruitBowlListener listener : listeners) {
listener.fruitAdded(evt);
}
}
}
protected void fireFruitRemoved(String fruit) {
FruitBowlListener[] listeners = getEventListenerList().getListeners(FruitBowlListener.class);
if (listeners.length > 0) {
FruitBowlEvent evt = new FruitBowlEvent(this, fruit);
for (FruitBowlListener listener : listeners) {
listener.fruitRemoved(evt);
}
}
}
}
public class DefaultFruitBowl extends AbstractFruitBowl {
private List<String> fruits;
public DefaultFruitBowl() {
fruits = new ArrayList<>(25);
}
#Override
public void addFruit(String fruit) {
fruits.add(fruit);
fireFruitAdded(fruit);
}
#Override
public void removeFruit(String fruit) {
fruits.remove(fruit);
fireFruitRemoved(fruit);
}
#Override
public List<String> getFruit() {
return Collections.unmodifiableList(fruits);
}
}
}
Related
In this program I'm trying to input a functionality to start game, where if I click start game (MainMenu) a new jpanel opens up (MainGame), creating another jpanel that creates jbuttons in a grid. If i go back, and click start game again, a new grid should generate instead of the previous one, effectively starting a "new game". the problem is that if i go back and click on new game again, the program creates 2 grids.
I've tried removing the instance of the grid panel with = null but it doesn't work
Main function:
import javax.swing.*;
import java.awt.*;
import java.awt.CardLayout;
public class Game extends JFrame {
MainMenu mainMenu;
Settings settings;
MainGame mainGame;
CardLayout cl;
JPanel container;
public Game(){
setSize(900,900); //have all as seperate classes
setDefaultCloseOperation(3); //cl call container
container = new JPanel(); //container call menu1 and menu2
cl = new CardLayout();
mainMenu = new MainMenu();
settings = new Settings();
mainGame = new MainGame();
mainMenu.setSettings(settings);
settings.setMainMenu(mainMenu);
settings.setMainGame(mainGame);
mainMenu.setMainGame(mainGame);
mainGame.setMainMenu(mainMenu);
mainGame.setSettings(settings);
container.setLayout(cl); //this stays here i think
//add setter for main game here
container.add(mainMenu,"1");
container.add(settings,"2");
container.add(mainGame,"3");
mainMenu.setContainer(container);
mainMenu.setCl(cl);
settings.setContainer(container);
settings.setCl(cl);
mainGame.setContainer(container);
mainGame.setCl(cl);
cl.show(container, "1");
add(container,BorderLayout.CENTER);
}
public static void main(String[] args) {
Game game = new Game();
game.setVisible(true);
}
}
main game class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MainGame extends JPanel {
MainMenu mainMenu;
Settings settings;
CardLayout cl;
JPanel container;
String rows;
String columns;
public void setMainMenu(MainMenu mainMenu) {
this.mainMenu = mainMenu;
}
public void setSettings(Settings settings) {
this.settings = settings;
}
public void setCl(CardLayout cl) {
this.cl = cl;
}
public void setContainer(JPanel container) {
this.container = container;
}
public void setRows(String rows) {
this.rows = rows;
}
public void setColumns(String columns) {
this.columns = columns;
}
public MainGame(){
JPanel north = new JPanel();
north.setLayout(new FlowLayout());
ReturnAction returnAl = new ReturnAction();
JButton Return2 = new JButton("Return");
Return2.addActionListener(returnAl);
north.add(Return2);
add(north);
}
class ReturnAction implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
cl.show(container,"1");
}
}
}
Main menu class (this one contains the game generation part):
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
public class MainMenu extends JPanel {
JPanel grid = new JPanel();
MainGame mainGame;
Settings settings;
CardLayout cl;
JPanel container;
String rows;
String columns;
boolean checkexists = false;
int rownumber;
int columnnumber;
public void setMainGame(MainGame mainGame) {
this.mainGame = mainGame;
}
public void setCl(CardLayout cl) {
this.cl = cl;
}
public void setContainer(JPanel container) {
this.container = container;
}
public void setSettings(Settings settings) {
this.settings = settings;
}
public void setRows(String rows) {
this.rows = rows;
}
public void setColumns(String columns) {
this.columns = columns;
}
public MainMenu() {
setLayout(new GridLayout(3, 1));
JButton Newgame = new JButton("New Game");
JButton Cont = new JButton("Continue");
JButton Sett = new JButton("Settings");
add(Newgame);
add(Cont);
SwitchMenu1 switchMenu1 = new SwitchMenu1();
SwitchMenu2 switchMenu2 = new SwitchMenu2();
GenerateGame generateGame = new GenerateGame();
Newgame.addActionListener(switchMenu2);
Newgame.addActionListener(generateGame);
Sett.addActionListener(switchMenu1);
add(Sett);
}
class SwitchMenu1 implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
cl.show(container, "2");
}
}
class SwitchMenu2 implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
cl.show(container, "3");
}
}
class GenerateGame implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (checkexists == true){
grid = null;
grid = new JPanel();
}
try {
rownumber = Integer.parseInt(rows);
} catch (NumberFormatException be) {
rownumber = 10;
}
try {
columnnumber = Integer.parseInt(columns);
} catch (NumberFormatException be) {
columnnumber = 10;
}
Random rand = new Random();
int randomnumber;
String Letters = "AAIIOOUUEEABCDEFGHIJKLMNOPQRSTUVWXYZ";
grid.setLayout(new GridLayout(rownumber, columnnumber));
JButton[][] gridbutton = new JButton[rownumber][columnnumber];
MainbuttonAL mainbuttonAL = new MainbuttonAL();
for (int i = 0; i < rownumber; i++) {
for (int j = 0; j < columnnumber; j++) {
if (checkexists == true){
gridbutton[i][j] = null;
}
randomnumber = rand.nextInt(Letters.length());
gridbutton[i][j] = new JButton("" + Letters.charAt(randomnumber));
gridbutton[i][j].addActionListener(mainbuttonAL);
grid.add(gridbutton[i][j]);
}
}
mainGame.add(grid);
checkexists = true;
}
}
class MainbuttonAL implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
}
}
}
settings class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
public class MainMenu extends JPanel {
JPanel grid = new JPanel();
MainGame mainGame;
Settings settings;
CardLayout cl;
JPanel container;
String rows;
String columns;
boolean checkexists = false;
int rownumber;
int columnnumber;
public void setMainGame(MainGame mainGame) {
this.mainGame = mainGame;
}
public void setCl(CardLayout cl) {
this.cl = cl;
}
public void setContainer(JPanel container) {
this.container = container;
}
public void setSettings(Settings settings) {
this.settings = settings;
}
public void setRows(String rows) {
this.rows = rows;
}
public void setColumns(String columns) {
this.columns = columns;
}
public MainMenu() {
setLayout(new GridLayout(3, 1));
JButton Newgame = new JButton("New Game");
JButton Cont = new JButton("Continue");
JButton Sett = new JButton("Settings");
add(Newgame);
add(Cont);
SwitchMenu1 switchMenu1 = new SwitchMenu1();
SwitchMenu2 switchMenu2 = new SwitchMenu2();
GenerateGame generateGame = new GenerateGame();
Newgame.addActionListener(switchMenu2);
Newgame.addActionListener(generateGame);
Sett.addActionListener(switchMenu1);
add(Sett);
}
class SwitchMenu1 implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
cl.show(container, "2");
}
}
class SwitchMenu2 implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
cl.show(container, "3");
}
}
class GenerateGame implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (checkexists == true){
grid = null;
grid = new JPanel();
}
try {
rownumber = Integer.parseInt(rows);
} catch (NumberFormatException be) {
rownumber = 10;
}
try {
columnnumber = Integer.parseInt(columns);
} catch (NumberFormatException be) {
columnnumber = 10;
}
Random rand = new Random();
int randomnumber;
String Letters = "AAIIOOUUEEABCDEFGHIJKLMNOPQRSTUVWXYZ";
grid.setLayout(new GridLayout(rownumber, columnnumber));
JButton[][] gridbutton = new JButton[rownumber][columnnumber];
MainbuttonAL mainbuttonAL = new MainbuttonAL();
for (int i = 0; i < rownumber; i++) {
for (int j = 0; j < columnnumber; j++) {
if (checkexists == true){
gridbutton[i][j] = null;
}
randomnumber = rand.nextInt(Letters.length());
gridbutton[i][j] = new JButton("" + Letters.charAt(randomnumber));
gridbutton[i][j].addActionListener(mainbuttonAL);
grid.add(gridbutton[i][j]);
}
}
mainGame.add(grid);
checkexists = true;
}
}
class MainbuttonAL implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
}
}
}
what method can i employ to regenerate a grid?
In general, you should be working on the concept of decoupling your views and your data, this means that you could have a "game model" which could be applied to a view and the view would then modify itself based on model properties, this is commonly known as "model - view - controller".
The problem is, however, you never remove grid from it's parent container when you create a new game
if (checkexists == true){
grid = null;
grid = new JPanel();
}
Instead, before you re-intialise the grid, you should remove from it's parent container
if (grid != null) {
mainGame.remove(grid);
grid = null;
grid = new JPanel();
}
or you could just remove the components from the grid panel itself
grid.removeAll();
A different approach...
At all stages you should be trying to decouple you objects and workflows from each other, so that it's easier to change any one part without having adverse effects on the other parts of the system or workflow.
Looking at you code, for example, the navigation decisions are tightly coupled to each panel/view, but in reality, they shouldn't know or care about how the navigation works (or the fact that there are other views), they should just do there job.
You can decouple this workflow through the use of delegation (backed by an observer). This basically means that the individual view doesn't care "how" the navigation works, only that when it makes a request for some action to be taken, it happens.
You should take the time to read through...
Model-View-Controller
Observer Pattern
Dependency Injection in Java
But how does this help you? Well, it will help you all the time!
Lets start with the "game" itself. The first thing we need is some kind of container to hold the data base logic for the game, so based on your current code, it might look something like...
public interface GameModel {
public int getRows();
public int getColumns();
}
I know, amazing isn't it, but this interface would grow to hold the logic required to run your game.
Now, we can apply this to the GamePanel
public class GamePane extends JPanel {
public interface Obsever {
public void back(GamePane source);
}
private GameModel model;
private Obsever obsever;
private JPanel contentPane;
private ActionListener buttonActionListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
didTap(e.getActionCommand());
}
};
public GamePane(Obsever obsever) {
this.obsever = obsever;
setLayout(new BorderLayout());
contentPane = new JPanel();
add(new JScrollPane(contentPane));
JButton backButton = new JButton("<< Back");
backButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
obsever.back(GamePane.this);
}
});
JPanel bannerPane = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1;
gbc.anchor = GridBagConstraints.LINE_END;
bannerPane.add(backButton, gbc);
add(bannerPane, BorderLayout.NORTH);
}
#Override
public Dimension getPreferredSize() {
// Bunch of things we could do here, but this basically
// acts as a stand in for CardLayout, otherwise the primary
// view will be to small
return new Dimension(800, 800);
}
public void setModel(GameModel model) {
if (this.model == model) {
// Do nothing, nothings changed
return;
}
this.model = model;
buildUI();
}
protected void buildUI() {
contentPane.removeAll();
if (model == null) {
return;
}
String Letters = "AAIIOOUUEEABCDEFGHIJKLMNOPQRSTUVWXYZ";
Random rnd = new Random();
JButton[][] gridbutton = new JButton[model.getRows()][model.getColumns()];
contentPane.setLayout(new GridLayout(model.getRows(), model.getColumns()));
//Game.MainMenu.MainbuttonAL mainbuttonAL = new Game.MainMenu.MainbuttonAL();
for (int i = 0; i < model.getRows(); i++) {
for (int j = 0; j < model.getColumns(); j++) {
int randomnumber = rnd.nextInt(Letters.length());
gridbutton[i][j] = new JButton("" + Letters.charAt(randomnumber));
//gridbutton[i][j].addActionListener(mainbuttonAL);
contentPane.add(gridbutton[i][j]);
}
}
}
protected void didTap(String action) {
}
}
Now, the nice "juicy" part is in the buildUI which is called by setModel when the model changes. This just re-builds the UI based on the GameModel properties.
As for the navigation concept, you can see part of it in the GamePane via its Observer interface. I started by creating a seperate class to handle the navigation workflows.
This means that the "how" or "implementation detail" is decoupled or hidden from the other parts of the system. Instead, it makes use of simple observer/delegation workflow.
Each view provides an Observer (for the what of a better name) which describes the navigation actions it needs performed. For example, both the SettingsPane and GamePane simply have back. They don't care what came before them, that's up to the navigation controller to decide.
public class NavigationPane extends JPanel {
enum View {
MAIN_MENU, GAME, SETTINGS
}
private CardLayout cardLayout;
private GameModel model;
private GamePane gamePane;
// Just for testing...
private Random rnd = new Random();
public NavigationPane() {
cardLayout = new CardLayout();
setLayout(cardLayout);
add(new MainMenu(new MainMenu.Observer() {
#Override
public void newGame(MainMenu source) {
gamePane.setModel(createModel());
navigateTo(View.GAME);
}
#Override
public void continueGame(MainMenu source) {
// Because it's possible to push continue
// without starting a game
// It might be possible have a "menu" model
// which can be used to change the enabled state of
// the continue button based on the state of the
// game
gamePane.setModel(getOrCreateGameModel());
navigateTo(View.GAME);
}
#Override
public void settingsGame(MainMenu source) {
navigateTo(View.SETTINGS);
}
}), View.MAIN_MENU);
gamePane = new GamePane(new GamePane.Obsever() {
#Override
public void back(GamePane source) {
navigateTo(View.MAIN_MENU);
}
});
add(gamePane, View.GAME);
add(new SettingsPane(new SettingsPane.Obsever() {
#Override
public void back(SettingsPane source) {
navigateTo(View.MAIN_MENU);
}
}), View.SETTINGS);
navigateTo(View.MAIN_MENU);
}
protected GameModel createModel() {
model = new DefaultGameModel(rnd.nextInt(9) + 2, rnd.nextInt(9) + 2);
return model;
}
protected GameModel getOrCreateGameModel() {
if (model == null) {
model = createModel();
}
return model;
}
protected void add(Component component, View view) {
add(component, view.name());
}
protected void navigateTo(View view) {
cardLayout.show(this, view.name());
}
}
Runnable example...
So, that's a lot of out-of-context code. The below is basically an example of one possible approach you could take to further reduce some of the clutter and coupling which is growing in your code base at this time.
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new NavigationPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class NavigationPane extends JPanel {
enum View {
MAIN_MENU, GAME, SETTINGS
}
private CardLayout cardLayout;
private GameModel model;
private GamePane gamePane;
// Just for testing...
private Random rnd = new Random();
public NavigationPane() {
cardLayout = new CardLayout();
setLayout(cardLayout);
add(new MainMenu(new MainMenu.Observer() {
#Override
public void newGame(MainMenu source) {
gamePane.setModel(createModel());
navigateTo(View.GAME);
}
#Override
public void continueGame(MainMenu source) {
// Because it's possible to push continue
// without starting a game
// It might be possible have a "menu" model
// which can be used to change the enabled state of
// the continue button based on the state of the
// game
gamePane.setModel(getOrCreateGameModel());
navigateTo(View.GAME);
}
#Override
public void settingsGame(MainMenu source) {
navigateTo(View.SETTINGS);
}
}), View.MAIN_MENU);
gamePane = new GamePane(new GamePane.Obsever() {
#Override
public void back(GamePane source) {
navigateTo(View.MAIN_MENU);
}
});
add(gamePane, View.GAME);
add(new SettingsPane(new SettingsPane.Obsever() {
#Override
public void back(SettingsPane source) {
navigateTo(View.MAIN_MENU);
}
}), View.SETTINGS);
navigateTo(View.MAIN_MENU);
}
protected GameModel createModel() {
model = new DefaultGameModel(rnd.nextInt(9) + 2, rnd.nextInt(9) + 2);
return model;
}
protected GameModel getOrCreateGameModel() {
if (model == null) {
model = createModel();
}
return model;
}
protected void add(Component component, View view) {
add(component, view.name());
}
protected void navigateTo(View view) {
cardLayout.show(this, view.name());
}
}
public class MainMenu extends JPanel {
public interface Observer {
public void newGame(MainMenu source);
public void continueGame(MainMenu source);
public void settingsGame(MainMenu source);
}
private Observer observer;
public MainMenu(Observer observer) {
this.observer = observer;
setLayout(new GridBagLayout());
JButton newGameButton = new JButton("New Game");
JButton continueButton = new JButton("Continue");
JButton settingsButton = new JButton("Settings");
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(newGameButton, gbc);
add(continueButton, gbc);
add(settingsButton, gbc);
newGameButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
observer.newGame(MainMenu.this);
}
});
continueButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
observer.continueGame(MainMenu.this);
}
});
settingsButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
observer.settingsGame(MainMenu.this);
}
});
}
}
public class SettingsPane extends JPanel {
public interface Obsever {
public void back(SettingsPane source);
}
public SettingsPane(Obsever obsever) {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(new JLabel("All your setting belong to us"), gbc);
JButton backButton = new JButton("<< Back");
backButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
obsever.back(SettingsPane.this);
}
});
add(backButton, gbc);
}
}
public interface GameModel {
public int getRows();
public int getColumns();
}
public class DefaultGameModel implements GameModel {
private int rows;
private int columns;
public DefaultGameModel(int rows, int columns) {
this.rows = rows;
this.columns = columns;
}
#Override
public int getRows() {
return rows;
}
#Override
public int getColumns() {
return columns;
}
}
public class GamePane extends JPanel {
public interface Obsever {
public void back(GamePane source);
}
private GameModel model;
private Obsever obsever;
private JPanel contentPane;
private ActionListener buttonActionListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
didTap(e.getActionCommand());
}
};
public GamePane(Obsever obsever) {
this.obsever = obsever;
setLayout(new BorderLayout());
contentPane = new JPanel();
add(new JScrollPane(contentPane));
JButton backButton = new JButton("<< Back");
backButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
obsever.back(GamePane.this);
}
});
JPanel bannerPane = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1;
gbc.anchor = GridBagConstraints.LINE_END;
bannerPane.add(backButton, gbc);
add(bannerPane, BorderLayout.NORTH);
}
#Override
public Dimension getPreferredSize() {
// Bunch of things we could do here, but this basically
// acts as a stand in for CardLayout, otherwise the primary
// view will be to small
return new Dimension(800, 800);
}
public void setModel(GameModel model) {
if (this.model == model) {
// Do nothing, nothings changed
return;
}
this.model = model;
buildUI();
}
protected void buildUI() {
contentPane.removeAll();
if (model == null) {
return;
}
String Letters = "AAIIOOUUEEABCDEFGHIJKLMNOPQRSTUVWXYZ";
Random rnd = new Random();
JButton[][] gridbutton = new JButton[model.getRows()][model.getColumns()];
contentPane.setLayout(new GridLayout(model.getRows(), model.getColumns()));
//Game.MainMenu.MainbuttonAL mainbuttonAL = new Game.MainMenu.MainbuttonAL();
for (int i = 0; i < model.getRows(); i++) {
for (int j = 0; j < model.getColumns(); j++) {
int randomnumber = rnd.nextInt(Letters.length());
gridbutton[i][j] = new JButton("" + Letters.charAt(randomnumber));
//gridbutton[i][j].addActionListener(mainbuttonAL);
contentPane.add(gridbutton[i][j]);
}
}
}
protected void didTap(String action) {
}
}
}
I am new to java swing. I am creating application for patient registration using Swing. There is a button called Clear, that button should clear the input data from the text fields.When button is InputPanel.clear() set the values correctly.But it is not updating.
My classes are below.
MainWindow class create and show the GUI.
public class MainWindow extends JFrame implements ActionListener {
private static final long serialVersionUID = 1905122041950251207L;
transient TableRowSorter<PatientTableModel> sorter;
private PatientListView patientListViewPanel = new PatientListView();
private InputPanel inputPanel = new InputPanel();
private SearchCriteriaPanel searhCriteriaPanel = new SearchCriteriaPanel(this);
public void createAndShowGUI() {
ButtonPanel btnPanel = new ButtonPanel(new MainWindow());
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(600, 600);
sorter = new TableRowSorter<>(patientListViewPanel.getTableModel());
GridBagLayout gbl = new GridBagLayout();
this.setLayout(gbl);
GridBagConstraints gcon = new GridBagConstraints();
gcon.weightx = 1;
gcon.weighty = 5;
gcon.fill = GridBagConstraints.BOTH;
gcon.gridx = 0;
gcon.gridy = 0;
gcon.gridwidth = 11;
gcon.gridheight = 10;
gbl.setConstraints(inputPanel, gcon);
this.add(inputPanel);
gcon.gridx = 4;
gcon.gridy = 10;
gcon.gridwidth = 11;
gcon.gridheight = 5;
gbl.setConstraints(btnPanel, gcon);
this.add(btnPanel);
gcon.gridx = 0;
gcon.gridy = 22;
gcon.gridwidth = 11;
gcon.gridheight = 10;
gbl.setConstraints(searhCriteriaPanel, gcon);
this.add(searhCriteriaPanel);
gcon.gridx = 0;
gcon.gridy = 33;
gcon.gridwidth = 11;
gcon.gridheight = 10;
gbl.setConstraints(patientListViewPanel, gcon);
this.add(patientListViewPanel);
this.setVisible(true);
inputPanel.getNameText().addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
super.keyReleased(e);
if (inputPanel.getNameText().getText().length() > 0)
btnPanel.getSaveBtn().setEnabled(true);
}
});
patientListViewPanel.getTable().addMouseListener(new java.awt.event.MouseAdapter() {
#Override
public void mouseClicked(java.awt.event.MouseEvent evt) {
getSelectedData();
}
});
}
public MainWindow() {
super("Patient Registration");
}
#Override
public void actionPerformed(ActionEvent e) {
JButton button = (JButton) e.getSource();
switch (button.getText()) {
case "Save":
patientListViewPanel.getTableModel()
.addData(inputPanel.getData(patientListViewPanel.getTable().getRowCount()));
button.setEnabled(false);
break;
case "Clear":
inputPanel.clear();
break;
case "Search":
SearchCriteria s = new SearchCriteria(searhCriteriaPanel.getSearchNameText().getText(),
searhCriteriaPanel.getBirthYearText().getText(), searhCriteriaPanel.getMaleChkBx().isSelected(),
searhCriteriaPanel.getFemaleChkBx().isSelected());
patientListViewPanel.filter(s);
break;
default:
}
}
}
InputPanel is handle the fields and methods related to input data
public class InputPanel extends JPanel implements PropertyChangeListener {
/**
* clear fields in input panel
*/
public void clear() {
nameText.setText(" ");
phnText.setText("0");
datePickerObj.jDatePicker.getJFormattedTextField().setText("");
maleBtn.setSelected(true);
femaleBtn.setSelected(false);
adrsTxt.setText("");
statusList.setSelectedIndex(4);
}
public InputPanel() {
// fiels will be set to panel
addDataChangedListner();
isDataValid(phnText);
}
public void addDataChangedListner() {
PatientData model = new PatientData();
model.addPropertyChangeListener(this);
nameText.getDocument().addDocumentListener(new DataChangedListener(model, "name"));
phnText.getDocument().addDocumentListener(new DataChangedListener(model, "phnNumber"));
adrsTxt.getDocument().addDocumentListener(new DataChangedListener(model, "address"));
}
#Override
public void propertyChange(PropertyChangeEvent evt) {
String property = evt.getPropertyName();
String newValue = (String) evt.getNewValue();
switch (property) {
case "name":
updatedName = newValue;
break;
case "phnNumber":
updatedPhoneNumber = newValue;
break;
case "address":
updatedAddress = newValue;
break;
default:
}
}
}
Can someone help me to resolve this?
The basic functionality that you are having difficulty with is demonstrated in the following mre: (1)
import java.awt.BorderLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class MainWindow extends JFrame{
private InputPanel inputPanel;
private JButton saveBtn;
public void createAndShowGUI() {
inputPanel = new InputPanel();
saveBtn = new JButton("Save");
saveBtn.setEnabled(false);
add(saveBtn, BorderLayout.SOUTH);
JButton clearButton = new JButton("Clear");
clearButton.addActionListener(e->clearInput());
add(clearButton, BorderLayout.CENTER);
add(inputPanel, BorderLayout.NORTH);
inputPanel.getNameText().addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
super.keyReleased(e);
if (inputPanel.getNameText().getText().length() > 0) {
saveBtn.setEnabled(true);
}
}
});
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setVisible(true);
}
private void clearInput(){
inputPanel.clear();
saveBtn.setEnabled(false);
}
public MainWindow() {
createAndShowGUI();
}
public static void main(String[] args) {
new MainWindow();
}
}
class InputPanel extends JPanel {
JTextField nameText;
/**
* clear fields in input panel
*/
public void clear() {
nameText.setText(""); //use "" and not " " so text length = 0
}
public InputPanel() {
nameText = new JTextField(5);
add(nameText);
}
public JTextField getNameText() {
return nameText;
}
}
However, a better approach is to use the model to implement the change of data :
public class MainWindow extends JFrame implements PropertyChangeListener{
private InputPanel inputPanel;
private JButton saveBtn;
private final PatientData model;
public void createAndShowGUI() {
inputPanel = new InputPanel(model);
saveBtn = new JButton("Save");
saveBtn.setEnabled(false);
add(saveBtn, BorderLayout.SOUTH);
JButton clearButton = new JButton("Clear");
clearButton.addActionListener(e->clearInput());
add(clearButton, BorderLayout.CENTER);
add(inputPanel, BorderLayout.NORTH);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setVisible(true);
}
private void clearInput(){
inputPanel.clear();
}
public MainWindow() {
model = new PatientData();
model.setPropertyChangeListener(this);
createAndShowGUI();
}
#Override
public void propertyChange(PropertyChangeEvent evt) {
updateGui();
}
private void updateGui() {
if(model.getName().trim().isEmpty()){
saveBtn.setEnabled(false);
}else{
saveBtn.setEnabled(true);
}
}
public static void main(String[] args) {
new MainWindow();
}
}
class InputPanel extends JPanel implements DocumentListener{
private final JTextField nameText;
private final PatientData model;
/**
* clear fields in input panel
*/
public void clear() {
nameText.setText(""); //use "" and not " " so text length = 0
updateModel();
}
public InputPanel(PatientData model) {
this.model = model;
nameText = new JTextField("",5);
nameText.getDocument().addDocumentListener(this);
add(nameText);
}
#Override
public void changedUpdate(DocumentEvent e) {
updateModel();
}
#Override
public void removeUpdate(DocumentEvent e) {
updateModel();
}
#Override
public void insertUpdate(DocumentEvent e) {
updateModel();
}
private void updateModel() {
model.setName(nameText.getText());
}
}
class PatientData{
private String name ="";
private PropertyChangeListener listener;
public String getName() {
return name;
}
public void setPropertyChangeListener(PropertyChangeListener listener) {
this.listener = listener;
}
public void setName(String name) {
String oldName = this.name;
this.name = name;
if(listener != null) {
listener.propertyChange(new PropertyChangeEvent(this,"name", oldName, name));
}
}
}
(Test is online here)
(1) Always consider an mre when posting a question or answer.
I have a instance of a custom JLabel and i want to changes its text in all frames, but the text is changing only on the last opened frame. There's a way i can achieve this?
Here's what happens:
And my code:
App.java
package test;
import javax.swing.JFrame;
public class App extends JFrame {
protected static App app;
private String loggedUser;
private MyCustomLabel myCustomLabel;
public App() {
loggedUser = "User One";
myCustomLabel = new MyCustomLabel(loggedUser);
}
public static App getApp() {
return app;
}
public MyCustomLabel getMyCustomLabel() {
return myCustomLabel;
}
public String getLoggedUser() {
return loggedUser;
}
public void setLoggedUser(String loggedUser) {
this.loggedUser = loggedUser;
}
}
FrmApp.java
package test;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
/**
*
* #author Marco
*/
public class FrmApp extends App {
public FrmApp() {
app = new App();
initComponents();
}
private void initComponents() {
setLayout(new FlowLayout());
setSize(300, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
btnFrmOne = new JButton("Open frmOne");
btnFrmOne.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
FrmOne frmOne = new FrmOne();
frmOne.setVisible(true);
}
});
add(btnFrmOne);
btnFrmTwo = new JButton("Open frmTwo");
btnFrmTwo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
FrmTwo frmTwo = new FrmTwo();
frmTwo.setVisible(true);
}
});
add(btnFrmTwo);
btnChangeUser = new JButton("Change user");
btnChangeUser.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (App.getApp().getLoggedUser().equals("User One")) {
App.getApp().setLoggedUser("User Two");
} else {
App.getApp().setLoggedUser("User One");
}
App.getApp().getMyCustomLabel().refresh();
}
});
add(btnChangeUser);
}
private JButton btnFrmOne;
private JButton btnFrmTwo;
private JButton btnChangeUser;
public static void main(String args[]) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
Logger.getLogger(FrmApp.class.getName()).log(Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
Logger.getLogger(FrmApp.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(FrmApp.class.getName()).log(Level.SEVERE, null, ex);
} catch (UnsupportedLookAndFeelException ex) {
Logger.getLogger(FrmApp.class.getName()).log(Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new FrmApp().setVisible(true);
}
});
}
}
FrmOne.java
package test;
import java.awt.FlowLayout;
import javax.swing.JFrame;
public class FrmOne extends JFrame {
public FrmOne() {
initComponents();
}
private void initComponents() {
setLayout(new FlowLayout());
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(150, 100);
add(App.getApp().getMyCustomLabel());
}
}
FrmTwo.java
package test;
import java.awt.FlowLayout;
import javax.swing.JFrame;
public class FrmTwo extends JFrame {
public FrmTwo() {
initComponents();
}
private void initComponents() {
setLayout(new FlowLayout());
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(150, 100);
add(App.getApp().getMyCustomLabel());
}
}
MyCustomLabel.java
package test;
import javax.swing.JLabel;
public class MyCustomLabel extends JLabel {
public MyCustomLabel(String loggedUser) {
initComponents(loggedUser);
}
private void initComponents(String loggedUser) {
setText(loggedUser);
}
public void refresh() {
setText(App.getApp().getLoggedUser());
}
}
Update
This is what im doing now to do what i wanted.
App.java
public class App extends JFrame {
public App() {
User user = new User(1, "User One");
LoggedUser.getInstance().setUser(user);
initComponents();
}
public static void main(String[] args) {
new App().setVisible(true);
}
private void initComponents() {
setSize(200, 200);
setLocation(400, 200);
setLayout(new FlowLayout());
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JButton btn1 = new JButton("dlgOne");
btn1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
DlgOne dlgOne = new DlgOne(App.this, false);
dlgOne.setVisible(true);
}
});
JButton btn2 = new JButton("dlgTwo");
btn2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
DlgTwo dlgTwo = new DlgTwo(App.this, false);
dlgTwo.setVisible(true);
}
});
JButton btn3 = new JButton("change user");
btn3.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (LoggedUser.getInstance().getUser().getId() == 1) {
User user = new User(2, "User Two");
LoggedUser.getInstance().setUser(user);
} else {
User user = new User(1, "User One");
LoggedUser.getInstance().setUser(user);
}
}
});
add(btn1);
add(btn2);
add(btn3);
}
}
MyCustomPanel.java
public class MyCustomPanel extends JPanel implements Observer {
private JLabel label;
public MyCustomPanel() {
initComponents();
}
#Override
public void update(Observable o, Object arg) {
//LoggedUser u = (LoggedUser) o;
//System.out.println(u.getUser().getId());
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
label.setText(LoggedUser.getInstance().getUser().getName());
}
});
}
private void initComponents() {
LoggedUser.getInstance().addObserver(this);
label = new JLabel(LoggedUser.getInstance().getUser().getName());
add(label);
}
}
User.java
public class User {
private int id;
private String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
DlgOne.java
public class DlgOne extends JDialog {
public DlgOne(Frame owner, boolean modal) {
super(owner, modal);
initComponents();
}
private void initComponents() {
setTitle("dlgOne");
setSize(200, 200);
setLocation(600, 200);
setLayout(new FlowLayout());
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
add(new MyCustomPanel());
}
}
DlgTwo.java
public class DlgTwo extends JDialog {
public DlgTwo(Frame owner, boolean modal) {
super(owner, modal);
initComponents();
}
private void initComponents() {
setTitle("dlgTwo");
setSize(200, 200);
setLocation(800, 200);
setLayout(new FlowLayout());
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
add(new MyCustomPanel());
}
}
LoggedUser.java
public class LoggedUser extends Observable {
private static LoggedUser instance;
public static LoggedUser getInstance() {
if (instance == null) {
instance = new LoggedUser();
}
return instance;
}
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
setChanged();
notifyObservers();
}
}
I have a instance of a custom JLabel and i want to changes its text in all frames,
A Swing component can only have a single parent. So you actually have two instances of your custom label. So updating the text in one label does not affect the other.
What you can do is create a PlainDocument to contain the text to be shared by multiple JTextFields. Then when the text is the Document is changed all the text fields will be updated.
So in the App class you would have:
private PlainDocument sharedDocument = new PlainDocument();
and you would create a method to access the Document. Maybe something like getSharedDocument().
Then in the form classes you would do something like:
//add(App.getApp().getMyCustomLabel());
JTextField textField = new JTextField( App.getApp().getSharedDocument() );
// customize text field to look like a label
textField.setBorder( null );
textField.setEditable( false );
add( textField );
So I have a GUI, a Tile class and a method class. I created four tiles in my Game class which consists of Tiles that has contains a letter and a color in each of them. I now want to create a method where when I click a key on my keyboard to that specific letter on the tile, it will remove the Tile . How would I go about that? Do I create that method in my model class and call it in my Game(GUI) class?
Your game is the "controller", it's responsible for managing the functionality and communication between the model and view.
Your view should be a representation of your model
Your model (and possibly your view) should be providing event notification support, to which you controller will need to monitor, in order to manage the requirements and logic.
To start with, you code is in mess. You are making to much use of static and it's not going to help you.
For example, I re-worked your Tile class to look more like this.
public class Tile extends JLabel {
public static Font font = new Font("Serif", Font.BOLD, 39);
private char _c;
public Tile(char c, Color background) {
setBackground(background);
setOpaque(true);
_c = c;
setText(convert());
}
public static char randomLetter() {
Random r = new Random();
char randomChar = (char) (97 + r.nextInt(25));
return randomChar;
}
public char getChar() {
return _c;
}
public String convert() {
return String.valueOf(getChar());
}
}
Rather then calling randomLetter each time you called getChar or convert, you should only be using it when you actually need a new character, otherwise you'll never know what the Tile's character actually is/was to begin with
Next, we need some kind of observer contract for the mode, so it can tell us when things have changed, for example.
public interface ModelListener {
public void tileWasRemoved(Tile tile);
}
It's nothing special, but this provides a means for the Model to provide notification when a Tile is removed and which Tile was actually removed.
Next, I updated the Model so that it actual "models" something. The Model now maintains a list of Tiles and provides functionality for adding and removing them. It also provides support for the ModelListener and event triggering
public class Model {
private ArrayList<Tile> list = new ArrayList<Tile>();
private List<ModelListener> listeners = new ArrayList<>(25);
public Model() {
}
public void addModelListener(ModelListener listener) {
listeners.add(listener);
}
public void removeModelListener(ModelListener listener) {
listeners.remove(listener);
}
protected void fireTileRemoved(Tile tile) {
for (ModelListener listener : listeners) {
listener.tileWasRemoved(tile);
}
}
public void removeByChar(char value) {
Iterator<Tile> iterator = list.iterator();
while (iterator.hasNext()) {
Tile tile = iterator.next();
if (value == tile.getChar()) {
fireTileRemoved(tile);
iterator.remove();
}
}
}
private void add(Tile tile) {
list.add(tile);
}
private Iterable<Tile> getTiles() {
return Collections.unmodifiableList(list);
}
}
Next, I went to the Game and updated it so it adds Tiles to the Model and uses the Model data to setup the UI. It then registers the KeyListener and ModelListener
public Game() {
model = new Model();
model.add(new Tile(Tile.randomLetter(), Color.WHITE));
model.add(new Tile(Tile.randomLetter(), Color.RED));
model.add(new Tile(Tile.randomLetter(), Color.GREEN));
model.add(new Tile(Tile.randomLetter(), Color.YELLOW));
JFrame frame = new JFrame();
frame.getContentPane().setLayout(new GridLayout(4, 1));
frame.setSize(500, 800);
frame.setVisible(true);
for (Tile tile : model.getTiles()) {
frame.add(tile);
}
model.addModelListener(new ModelListener() {
#Override
public void tileWasRemoved(Tile tile) {
frame.remove(tile);
frame.revalidate();
frame.repaint();
}
});
frame.getContentPane().addKeyListener(this);
frame.getContentPane().setFocusable(true);
frame.getContentPane().requestFocusInWindow();
}
And finally, the keyTyped event now asks the Model to remove a Tile of the given key...
#Override
public void keyTyped(KeyEvent e) {
model.removeByChar(e.getKeyChar());
}
As a proof of concept...
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Game implements KeyListener {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
new Game();
}
});
}
private Model model;
public Game() {
model = new Model();
model.add(new Tile(Tile.randomLetter(), Color.WHITE));
model.add(new Tile(Tile.randomLetter(), Color.RED));
model.add(new Tile(Tile.randomLetter(), Color.GREEN));
model.add(new Tile(Tile.randomLetter(), Color.YELLOW));
JFrame frame = new JFrame();
frame.getContentPane().setLayout(new GridLayout(4, 1));
frame.setSize(500, 800);
frame.setVisible(true);
for (Tile tile : model.getTiles()) {
frame.add(tile);
}
model.addModelListener(new ModelListener() {
#Override
public void tileWasRemoved(Tile tile) {
frame.remove(tile);
frame.revalidate();
frame.repaint();
}
});
frame.getContentPane().addKeyListener(this);
frame.getContentPane().setFocusable(true);
frame.getContentPane().requestFocusInWindow();
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
model.removeByChar(e.getKeyChar());
}
public interface ModelListener {
public void tileWasRemoved(Tile tile);
}
public class Model {
private ArrayList<Tile> list = new ArrayList<Tile>();
private List<ModelListener> listeners = new ArrayList<>(25);
public Model() {
}
public void addModelListener(ModelListener listener) {
listeners.add(listener);
}
public void removeModelListener(ModelListener listener) {
listeners.remove(listener);
}
protected void fireTileRemoved(Tile tile) {
for (ModelListener listener : listeners) {
listener.tileWasRemoved(tile);
}
}
public void removeByChar(char value) {
Iterator<Tile> iterator = list.iterator();
while (iterator.hasNext()) {
Tile tile = iterator.next();
if (value == tile.getChar()) {
fireTileRemoved(tile);
iterator.remove();
}
}
}
private void add(Tile tile) {
list.add(tile);
}
private Iterable<Tile> getTiles() {
return Collections.unmodifiableList(list);
}
}
public static class Tile extends JLabel {
public static Font font = new Font("Serif", Font.BOLD, 39);
private char _c;
public Tile(char c, Color background) {
setBackground(background);
setOpaque(true);
_c = c;
setText(convert());
}
public static char randomLetter() {
Random r = new Random();
char randomChar = (char) (97 + r.nextInt(25));
return randomChar;
}
public char getChar() {
return _c;
}
public String convert() {
return String.valueOf(getChar());
}
}
}
How ever...
As a general rule of thumb, KeyListener is a pain to work with and you should be making use of the key bindings API instead, for example
import java.awt.AWTKeyStroke;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Game {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
new Game();
}
});
}
private Model model;
public Game() {
model = new Model();
model.add(new Tile(Tile.randomLetter(), Color.WHITE));
model.add(new Tile(Tile.randomLetter(), Color.RED));
model.add(new Tile(Tile.randomLetter(), Color.GREEN));
model.add(new Tile(Tile.randomLetter(), Color.YELLOW));
JFrame frame = new JFrame();
frame.getContentPane().setLayout(new GridLayout(4, 1));
frame.setSize(500, 800);
frame.setVisible(true);
for (Tile tile : model.getTiles()) {
frame.add(tile);
KeyStroke ks = KeyStroke.getKeyStroke(tile.getChar());
String name = "typed." + tile.getChar();
Action action = new TileAction(model, tile.getChar());
registerKeyBinding((JComponent)frame.getContentPane(), name, ks, action);
}
model.addModelListener(new ModelListener() {
#Override
public void tileWasRemoved(Tile tile) {
frame.remove(tile);
frame.revalidate();
frame.repaint();
}
});
}
public void registerKeyBinding(JComponent parent, String name, KeyStroke ks, Action action) {
InputMap im = parent.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap am = parent.getActionMap();
im.put(ks, name);
am.put(name, action);
}
public class TileAction extends AbstractAction {
private Model model;
private char value;
public TileAction(Model model, char value) {
this.model = model;
this.value = value;
}
#Override
public void actionPerformed(ActionEvent e) {
model.removeByChar(value);
}
}
public interface ModelListener {
public void tileWasRemoved(Tile tile);
}
public class Model {
private ArrayList<Tile> list = new ArrayList<Tile>();
private List<ModelListener> listeners = new ArrayList<>(25);
public Model() {
}
public void addModelListener(ModelListener listener) {
listeners.add(listener);
}
public void removeModelListener(ModelListener listener) {
listeners.remove(listener);
}
protected void fireTileRemoved(Tile tile) {
for (ModelListener listener : listeners) {
listener.tileWasRemoved(tile);
}
}
public void removeByChar(char value) {
Iterator<Tile> iterator = list.iterator();
while (iterator.hasNext()) {
Tile tile = iterator.next();
if (value == tile.getChar()) {
fireTileRemoved(tile);
iterator.remove();
}
}
}
private void add(Tile tile) {
list.add(tile);
}
private Iterable<Tile> getTiles() {
return Collections.unmodifiableList(list);
}
}
public static class Tile extends JLabel {
public static Font font = new Font("Serif", Font.BOLD, 39);
private char _c;
public Tile(char c, Color background) {
setBackground(background);
setOpaque(true);
_c = c;
setText(convert());
}
public static char randomLetter() {
Random r = new Random();
char randomChar = (char) (97 + r.nextInt(25));
return randomChar;
}
public char getChar() {
return _c;
}
public String convert() {
return String.valueOf(getChar());
}
}
}
See How to Use Key Bindings for more details.
EDIT--CORRECTED CODE BASED ON ACCEPTED ANSWER IS SHOWN AT BOTTOM OF THIS POST.
I found a way (written by Andremoniy) to catch double- and triple-clicks without firing single- and double-clicks. It works very well for my purposes.
I modified it so that it could have the click interval tweaked by the implementation. That also works well.
My modifications include making it an abstract class, defining the 5 abstract methods that the implementation would have to define (methods for single, double, triple, and "many" clicks as well as the click interval tweaker).
Here is the modified version (the println statements are instructive):
public abstract class Click123 extends JPanel
{
public abstract void singleClick();
public abstract void doubleClick();
public abstract void tripleClick();
public abstract void manyClick();
public abstract int getFreq();
public Click123()
{
addMouseListener
(
new MouseAdapter()
{
Thread cp = null;
public void mouseClicked(MouseEvent e)
{
if (cp != null && cp.isAlive())
cp.interrupt();
if (e.getClickCount() == 1)
{
cp = new Thread(new ClickProcessor(new Callable<Void>() {
#Override public Void call() throws Exception {
singleClick();
return null;
}
}));
cp.start();
}
else if (e.getClickCount() == 2)
{
cp = new Thread(new ClickProcessor(new Callable<Void>() {
#Override public Void call() throws Exception {
doubleClick();
return null;
}
}));
cp.start();
}
else if (e.getClickCount() == 3)
{
cp = new Thread(new ClickProcessor(new Callable<Void>()
{
#Override public Void call() throws Exception {
tripleClick();
return null;
}
})
);
cp.start();
}
else manyClick();
} // mouseClicked
} // new MouseAdapter
); // add mouseListener
} // Click123
class ClickProcessor implements Runnable
{
Callable<Void> eventProcessor;
ClickProcessor(Callable<Void> eventProcessor)
{
this.eventProcessor = eventProcessor;
}
#Override public void run()
{
try
{
Thread.sleep(getFreq());
eventProcessor.call();
} catch (InterruptedException e) { System.out.println(e);}
catch (Exception e) { System.out.println(e);}
} // run
} // class ClickProcessor
} // class Click123
Here's the implementing program:
public class NewMain1 {
static int INITIAL_CLICK_FREQUENCY = ((Integer)Toolkit.getDefaultToolkit()
.getDesktopProperty("awt.multiClickInterval"));
public static int CLICK_FREQUENCY;
static JSpinner spinner = new JSpinner();
static final JLabel ch = new JLabel("Click here to test");
public static void main(String[] args) {
CLICK_FREQUENCY = INITIAL_CLICK_FREQUENCY;
spinner = new JSpinner();
spinner.setModel(new SpinnerNumberModel(CLICK_FREQUENCY, 200, 900, 50));
spinner.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
CLICK_FREQUENCY = (int) spinner.getValue();
}
});
Click123 frame = new Click123(){
public void singleClick(){
JOptionPane.showMessageDialog(null,"Single click at " + CLICK_FREQUENCY);
}
public void doubleClick(){
JOptionPane.showMessageDialog(null,"Double click at " + CLICK_FREQUENCY);
}
public void tripleClick(){
JOptionPane.showMessageDialog(null,"Triple click at " + CLICK_FREQUENCY);
}
public void manyClick(){
JOptionPane.showMessageDialog(null,"Many clicks at " + CLICK_FREQUENCY);
}
public int getFreq(){
return CLICK_FREQUENCY;
}
};
frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.setSize(500, 300);
ch.setBorder(new EtchedBorder());
frame.add(ch);
frame.add(spinner);
frame.setVisible(true);
} // main
}
As originally written, Click123 extends JFrame. I modified it (by changing the top line to extends JTextField) to work with a grid of type JTextField. Then I added a button to change the click interval on the fly. So now I have THREE identical (except for the extension type) huge hunks of code.
My question is this: How do I modify Click123 so that, without alteration, it can be used to make ANY component aware of single-, double-, and triple-clicks?
EDIT--SUMMARY OF NECESSARY CHANGES (For my own app, the abstract methods need MouseEvent to be passed in order to determine which component fired the clicks):
Class definition:
public abstract class Click123<T extends Component>
{
public abstract void singleClick(MouseEvent e); // same for 3 others
...
public Click123(T target)
{
target.addMouseListener
(
new MouseAdapter() ...
} ...
}
final added as modifier in order to pass MouseEvent:
public void mouseClicked(final MouseEvent e)
Pass MouseEvent:
singleClick(e); // same for doubleClick and tripleClick and manyClick
Receive MouseEvent in order to determine which component fired the clicks:
public void doubleClick(MouseEvent e)
Implementation:
frame = new JPanel();
new Click123(frame) {
Generics aren't necessary. All you need is to add the MouseListener to a Component.
public abstract class Click123 // doesn't extend anything
{
public Click123(Component comp)
{
comp.addMouseListener(new MouseAdapter() {
// ...
}));
}
}
Now you can just pass the JFrame, or whatever Component you want:
Click123 handler = new Click123(myJFrame){
public void singleClick(){
JOptionPane.showMessageDialog(null,"Single click at " + CLICK_FREQUENCY);
}
// Other implementing methods here
}
Generics are part of the solution. Just do the following:
Make your class Click123<T extends Component>
Make your constructor public Click123(T targetedComponent) {
Call targetedComponent.addMouseListener rather than addMouseListener
Create a JFrame or JPanel or whatever and then pass it to your new Click123 as a constructor argument. Then use your JFrame where you were using your Click123.
Upon request, I am posting code that works. Edits in original post are too scattered to be useful. Original code modifications are flagged with //////////.
package clickForm;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.concurrent.Callable;
public abstract class Click123<T extends Component> ////////////////
{
public abstract void singleClick(MouseEvent e); ////////////////
public abstract void doubleClick(MouseEvent e); ////////////////
public abstract void tripleClick(MouseEvent e); ////////////////
public abstract void manyClick(MouseEvent e); ////////////////
public abstract int getFreq();
public Click123(T target) ////////////////
{
target.addMouseListener ////////////////
(
new MouseAdapter() ////////////////
{
Thread cp = null;
public void mouseClicked(final MouseEvent e)
{
if (cp != null && cp.isAlive())
cp.interrupt();
if (e.getClickCount() == 1)
{
cp = new Thread(new ClickProcessor(new Callable<Void>() {
#Override public Void call() throws Exception {
singleClick(e); //////////////////////////////////////////
return null;
}
}));
cp.start();
}
else if (e.getClickCount() == 2)
{
cp = new Thread(new ClickProcessor(new Callable<Void>() {
#Override public Void call() throws Exception {
doubleClick(e); //////////////////////////////////////////
return null;
}
}));
cp.start();
}
else if (e.getClickCount() == 3)
{
cp = new Thread(new ClickProcessor(new Callable<Void>()
{
#Override public Void call() throws Exception {
tripleClick(e); //////////////////////////////////////////
return null;
}
})
);
cp.start();
}
else manyClick(e); //////////////////////////////////////////
} // mouseClicked
} // new MouseAdapter
); // add mouseListener
} // Click123
class ClickProcessor implements Runnable
{
Callable<Void> eventProcessor;
ClickProcessor(Callable<Void> eventProcessor)
{
this.eventProcessor = eventProcessor;
}
#Override public void run()
{
try
{
Thread.sleep(getFreq());
eventProcessor.call();
} catch (InterruptedException e) { System.out.println(e);}
catch (Exception e) { System.out.println(e);}
} // run
} // class ClickProcessor
} // class Click123
Implementation:
package clickForm;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;
import javax.swing.border.EtchedBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Main {
static int CLICK_FREQUENCY = (int) Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval");
static JSpinner spinner = new JSpinner();
static final JLabel ch = new JLabel("Click here to test");
static JFrame frame = new JFrame();
public static void main(String[] args) {
spinner = new JSpinner();
spinner.setModel(new SpinnerNumberModel(CLICK_FREQUENCY, 200, 900, 50));
spinner.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
CLICK_FREQUENCY = (int) spinner.getValue();
}
});
new Click123(ch){ /////////////////////////////////////////////
#Override
public void singleClick(MouseEvent e) { //////////////////////////////
JOptionPane.showMessageDialog(null,"Single at " + CLICK_FREQUENCY);
}
#Override
public void doubleClick(MouseEvent e) { //////////////////////////////
JOptionPane.showMessageDialog(null,"Double at " + CLICK_FREQUENCY);
}
#Override
public void tripleClick(MouseEvent e) { //////////////////////////////
JOptionPane.showMessageDialog(null,"Triple at " + CLICK_FREQUENCY);
}
#Override
public void manyClick(MouseEvent e) { //////////////////////////////
JOptionPane.showMessageDialog(null,"Many at " + CLICK_FREQUENCY);
}
#Override
public int getFreq() {
return CLICK_FREQUENCY;
}
};
frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.setSize(500, 300);
ch.setBorder(new EtchedBorder());
frame.add(ch);
frame.add(spinner);
frame.setVisible(true);
} // main
}