How can I make dual-lines in a JTabbedPane - java

I'm not sure how much of sense my title does but since you are suppose to have somewhat of a good title this was the best I came up with, so what I actually mean is...
Let's say in theory I've got 10 tabs, and instead of having them all compressed together in 1 line I'd like to split them in 2, so I'd have 5 tabs on the upper side and 5 on the lower.
Example pic:

not clear your question, but there are basic methods for Tabs in the JTabbedPane
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
public class TabComponentsDemo extends JFrame {
private static final long serialVersionUID = 1L;
private final int tabNumber = 15;
private final JTabbedPane pane = new JTabbedPane();
private JMenuItem tabComponentsItem;
private JMenuItem scrollLayoutItem;
public TabComponentsDemo(String title) {
super(title);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initMenu();
add(pane);
}
public void runTest() {
pane.removeAll();
for (int i = 0; i < tabNumber; i++) {
String title = "Tab " + i;
pane.add(title, new JLabel(title));
//initTabComponent(i);
}
tabComponentsItem.setSelected(true);
pane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT);
scrollLayoutItem.setSelected(false);
setSize(new Dimension(400, 200));
setLocationRelativeTo(null);
setVisible(true);
}
/*private void initTabComponent(int i) {
pane.setTabComponentAt(i, new ButtonTabComponent(pane));
}*/
private void initMenu() {//Setting menu
JMenuBar menuBar = new JMenuBar();//create Options menu
tabComponentsItem = new JCheckBoxMenuItem("Use TabComponents", true);
tabComponentsItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.ALT_MASK));
tabComponentsItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < pane.getTabCount(); i++) {
if (tabComponentsItem.isSelected()) {
//initTabComponent(i);
} else {
pane.setTabComponentAt(i, null);
}
}
}
});
scrollLayoutItem = new JCheckBoxMenuItem("Set ScrollLayout");
scrollLayoutItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.ALT_MASK));
scrollLayoutItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (pane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT) {
pane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
} else {
pane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT);
}
}
});
JMenuItem resetItem = new JMenuItem("Reset JTabbedPane");
resetItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.ALT_MASK));
resetItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
runTest();
}
});
JMenu optionsMenu = new JMenu("Options");
optionsMenu.add(tabComponentsItem);
optionsMenu.add(scrollLayoutItem);
optionsMenu.add(resetItem);
menuBar.add(optionsMenu);
setJMenuBar(menuBar);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
UIManager.put("swing.boldMetal", Boolean.FALSE);
new TabComponentsDemo("TabComponentsDemo").runTest();
}
});
}
}

If you want them all displayed in a single row (which I think is what the latter part of your description indicates...), you'll want to set the tab layout policy to JTabbedPane.SCROLL_TAB_LAYOUT.
Here's an example with an image.

Related

How to have the program regenerate a "new game" where previous grid letters get swapped with new grid letters

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) {
}
}
}

One MouseListener for many JLabel components

I have 17 JLabel components and I want to add same handler for all these labels. Actually I have have to increase the size of the label when mouse hovers over it. Code is here:
private void lblBackupMouseEntered(java.awt.event.MouseEvent evt) {
lblBackup.setSize(lblBackup.getWidth()+5,lblBackup.getHeight()+5);
}
private void lblChangePasswordMouseEntered(java.awt.event.MouseEvent evt) {
lblChangePassword.setSize(lblChangePassword.getWidth()+5,lblChangePassword.getHeight()+5);
}
private void lblAddEmployeeMouseEntered(java.awt.event.MouseEvent evt) {
lblAddEmployee.setSize(lblAddEmployee.getWidth()+5,lblAddEmployee.getHeight()+5);
}
private void lblAddCustomerMouseEntered(java.awt.event.MouseEvent evt) {
lblAddCustomer.setSize(lblAddCustomer.getWidth()+5,lblAddCustomer.getHeight()+5);
}
Now I want to avoid this repetition of same handler.
It's simple -- you can use the same mouse handler class, and can assign it to multiple JLabels, and then get the current involved JLabel via the MouseEvent#getSource() method.
#Override
public void mouseEntered(MouseEvent evt) {
// assuming that you only add this MouseListener to JLabels...
JLabel currentLabel = (JLabel)evt.getSource();
// do what needs to be done with currentLabel
}
For example:
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class ManyLabelExample extends JPanel {
private static final int SIDES = 8;
private static final int GAP = 15;
public static final Color HOVER_COLOR = Color.pink;
private List<JLabel> labels = new ArrayList<>();
public ManyLabelExample() {
setLayout(new GridLayout(SIDES, SIDES));
MyMouseHandler myMouseHandler = new MyMouseHandler();
for (int i = 0; i < SIDES * SIDES; i++) {
String text = String.format("[%d, %d]", i % SIDES + 1, i / SIDES + 1);
JLabel label = new JLabel(text);
label.setOpaque(true);
label.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
label.addMouseListener(myMouseHandler);
labels.add(label);
add(label);
}
}
private class MyMouseHandler extends MouseAdapter {
#Override
public void mouseEntered(MouseEvent evt) {
JLabel source = (JLabel) evt.getSource();
for (JLabel label : labels) {
if (label == source) {
label.setBackground(HOVER_COLOR);
} else {
label.setBackground(null);
}
}
}
}
private static void createAndShowGui() {
ManyLabelExample mainPanel = new ManyLabelExample();
JFrame frame = new JFrame("ManyLabelExample");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

No up state JButton

I'm trying to change to appearance of my JButton so that the button have no up state.
Currently i have something like this:
And i would like something like this:(comming from NetBeans)
In other words, I only want the image of the button to be visible when the button does not have any kind of focus. But when the user click or roll over it, it should act exactly the same as a regular button.
more examples:
no focus
roll over
click
I use a inner class for my button. It look like this:
private class CustumJButton extends JButton
{
public CustumJButton(Icon icon)
{
super(icon);
int size = 30;
setPreferredSize(new Dimension(size, size));
setFocusable(false);
}
}
Thanks ayoye.
You can achieve this using setBorderPainted() and setContentAreaFilled() methods. Here is the short Demo of what you are looking for. I hope it would give you rough figure to how to achieve your task.:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class CustomJButton extends JButton
{
public CustomJButton(String icon)
{
super(icon);
/*int size = 30;
setPreferredSize(new Dimension(size, size));*/
addFocusListener(new ButtonFocusAdapter());
addMouseListener(new ButtonMouseAdapter());
setContentAreaFilled(false);
setBorderPainted(false);
//setFocusable(false);//Don't use this method. This would avoid the focus event on JButton
}
private void decorateButton()
{
setContentAreaFilled(true);
setBorderPainted(true);
}
private void unDecorateButton()
{
setContentAreaFilled(false);
setBorderPainted(false);
}
private class ButtonFocusAdapter extends FocusAdapter
{
#Override
public void focusGained(FocusEvent evt)
{
decorateButton();
}
#Override
public void focusLost(FocusEvent evt)
{
unDecorateButton();
}
}
private class ButtonMouseAdapter extends MouseAdapter
{
#Override
public void mouseEntered(MouseEvent evt)
{
decorateButton();
}
#Override
public void mouseExited(MouseEvent evt)
{
unDecorateButton();
}
}
}
public class ButtonFrame extends JFrame
{
public void createAndShowGUI()
{
Container c = getContentPane();
c.setLayout(new FlowLayout());
for (int i = 0; i < 4 ; i++ )
{
CustomJButton cb = new CustomJButton("Button "+i);
c.add(cb);
}
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String st[])
{
SwingUtilities.invokeLater( new Runnable()
{
#Override
public void run()
{
ButtonFrame bf = new ButtonFrame();
bf.createAndShowGUI();
bf.setLocationRelativeTo(null);
}
});
}
}
I guess you need to use these two things to make it work, setBorderPainted(boolean) and setContentAreaFilled(boolean)
buttonObject.setBorderPainted(false);
buttonObject.setContentAreaFilled(false);
as cited in this example for changing appearance of JButton by #mKorbel
import java.awt.*;
import java.awt.event.*;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class ButtonDemo
{
private JButton demoButton;
private ImageIcon buttonImage;
private void displayGUI()
{
JFrame frame = new JFrame("Button Demo Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
try
{
//buttonImage = new ImageIcon(ImageIO.read(
// getClass().getResource("/image/bulb.gif")));
buttonImage = new ImageIcon(ImageIO.read(
new URL("http://gagandeepbali.uk.to/"
+ "gaganisonline/swing/downloads/"
+ "images/bulb.gif")));
}
catch(Exception e)
{
e.printStackTrace();
}
demoButton = new JButton(buttonImage);
setExceptionalState(demoButton);
demoButton.addMouseListener(new MouseAdapter()
{
#Override
public void mouseEntered(MouseEvent me)
{
setNormalState(demoButton);
}
#Override
public void mouseExited(MouseEvent me)
{
setExceptionalState(demoButton);
}
});
contentPane.add(demoButton);
frame.setContentPane(contentPane);
frame.setSize(300, 100);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private void setExceptionalState(JButton button)
{
button.setBorderPainted(false);
button.setContentAreaFilled(false);
}
private void setNormalState(JButton button)
{
button.setBorderPainted(true);
button.setContentAreaFilled(true);
}
public static void main(String[] args)
{
Runnable runnable = new Runnable()
{
#Override
public void run()
{
new ButtonDemo().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
You would set the default state for the button as:
button.setBorderPainted(false);
Then you would need to use a MouseListener:
on mouseEntered you would use
button.setBorderPainted(true);
and on mouse exited you would use
button.setBorderPainted(false);
You should check out the skinnable "Synth Look and Feel", but also be aware that Swing will be deprecated and replaced by JavaFX in the long run. If you are building a new application, you might want to consider using JavaFX which can be skinned with CSS to achieve the effect you are looking for.

JTextField is not editable in a JPopupMenu

When I add a JtextField in a JPopupMenu, I can't edit the text when the popup is displayed. Anyone know why?
Here's a code example:
public static void main(String[] args) {
JFrame frame = new JFrame();
JPopupMenu popup = new JPopupMenu();
JTextField field = new JTextField("My text");
popup.insert(field, 0);
popup.setVisible(true);
}
Seems to work alright for me:
Check out this example (right click anywhere on the content pane to make the popup visible:
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
public class Main {
protected void initUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPopupMenu popup = new JPopupMenu();
final JTextField field = new JTextField(20);
field.setText("My text");
popup.insert(field, 0);
popup.addPopupMenuListener(new PopupMenuListener() {
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
field.requestFocusInWindow();
field.selectAll();
}
});
}
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
}
#Override
public void popupMenuCanceled(PopupMenuEvent e) {
}
});
((JComponent) frame.getContentPane()).setComponentPopupMenu(popup);
frame.setSize(300, 300);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Main().initUI();
}
});
}
}
to avoiding any speculations
I can't edit the text when the popup is displayed. Anyone know why?
JPopup nested JPopupMenu must has a parent, my code example (reason why is there hardcodes frame.setLocation(150, 100);)
in this form works correctly, JPopup accepting JFrames coordinates
change this code inside Swing Action
from
//popupMenu.setVisible(true);
popupMenu.show(frame, (frame.getHeight() / 4), (frame.getWidth() / 4));
to
popupMenu.setVisible(true);
//popupMenu.show(frame, (frame.getHeight() / 4), (frame.getWidth() / 4));
then PopupMenuListener firing and events, but JMenuItems aren't repainted too
from code
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class PopupSample {
private JPopupMenu popupMenu = new JPopupMenu();
private javax.swing.Timer timer = null;
private JFrame frame = new JFrame("Popup Example");
public PopupSample() {
ActionListener actionListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent actionEvent) {
System.out.println("Selected: "
+ actionEvent.getActionCommand());
}
};
PopupMenuListener popupMenuListener = new PopupMenuListener() {
#Override
public void popupMenuCanceled(PopupMenuEvent popupMenuEvent) {
System.out.println("Canceled");
}
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent popupMenuEvent) {
System.out.println("Becoming Invisible");
}
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent popupMenuEvent) {
System.out.println("Becoming Visible");
}
};
popupMenu.addPopupMenuListener(popupMenuListener);
JSeparator jSeparator = new JSeparator(JSeparator.VERTICAL);
jSeparator.setPreferredSize(new Dimension(2, 100));
jSeparator.setBackground(Color.red);
popupMenu.add(jSeparator);
JMenuItem cutMenuItem = new JMenuItem("Cut");
cutMenuItem.addActionListener(actionListener);
popupMenu.add(cutMenuItem);
cutMenuItem.setBorder(null);
JMenuItem copyMenuItem = new JMenuItem("Copy");
copyMenuItem.addActionListener(actionListener);
popupMenu.add(copyMenuItem);
JMenuItem pasteMenuItem = new JMenuItem("Paste");
pasteMenuItem.addActionListener(actionListener);
pasteMenuItem.setEnabled(false);
popupMenu.add(pasteMenuItem);
popupMenu.addSeparator();
JMenuItem findMenuItem = new JMenuItem("Find");
findMenuItem.addActionListener(actionListener);
popupMenu.add(findMenuItem);
JTextField text = new JTextField("text");
popupMenu.add(text);
MouseListener mouseListener = new JPopupMenuShower(popupMenu);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addMouseListener(mouseListener);
frame.setLocation(150, 100);
frame.setSize(350, 250);
frame.setVisible(true);
start();
}
private void start() {
timer = new javax.swing.Timer(1000, updateCol());
timer.start();
}
public Action updateCol() {
return new AbstractAction("text load action") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
//popupMenu.setVisible(true);
popupMenu.show(frame, (frame.getHeight() / 4), (frame.getWidth() / 4));
}
});
}
};
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
PopupSample popupSample = new PopupSample();
}
});
}
static class JPopupMenuShower extends MouseAdapter {
private JPopupMenu popup;
public JPopupMenuShower(JPopupMenu popup) {
this.popup = popup;
}
private void showIfPopupTrigger(MouseEvent mouseEvent) {
if (popup.isPopupTrigger(mouseEvent)) {
popup.show(mouseEvent.getComponent(), mouseEvent.getX(),
mouseEvent.getY());
}
}
#Override
public void mousePressed(MouseEvent mouseEvent) {
showIfPopupTrigger(mouseEvent);
}
#Override
public void mouseReleased(MouseEvent mouseEvent) {
showIfPopupTrigger(mouseEvent);
}
}
}

Toggle read-only in Java

Is there a way to toggle a read-only mode so when you click any object in your window it simply returns what you clicked, ignoring the object's usual event handling? IE, while in this "read-only" mode, if you click on a Button, it simply returns the button, not actually pressing the button. Then I could do something like:
if ("thing pressed" == button) "do this";
else if ("thing pressed" == panel) "do that";
else "do nothing";
Here's my code, its a frame with 3 colored boxes. Clicking the 2nd box, the 3rd box, or the background will display a message. Clicking box 1 does nothing. I like using new mouse adapters so I want to do it this way.
Now what I want is when you click box 1, box 1 is treated as selected (if that helps you get the picture). Then if you click anywhere, including box 1 again, box 1 is deselected and nothing else (meaning that box 2, box 3. or the background's message will display). At that time, only if box 2 or 3 were clicked, they will still not display their normal message but a different message would be displayed.
I'm very sorry if I come off a little short.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Labels {
public static void main(String[] args) {
new Labels();
}
Square l1, l2, l3;
public Labels() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
l1 = new Square();
l2 = new Square();
l3 = new Square();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(120, 150);
frame.setResizable(false);
panel.setVisible(true);
panel.setLayout(null);
l1.setLocation(5, 5);
l2.setLocation(5, 60);
l3.setLocation(60, 5);
l2.setColor("yellow");
l3.setColor("black");
l1.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
//do nothing
}
});
l2.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Pushed label 2");
}
});
l3.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Pushed label 3");
}
});
panel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("pushed background");
}
});
frame.add(panel);
panel.add(l1);
panel.add(l2);
panel.add(l3);
}
class Square extends JLabel{
Color color = Color.blue;
public Square() {
// TODO Auto-generated constructor stub\
setVisible(true);
setSize(50,50);
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(color);
g.fillRect(0, 0, 50, 50);
}
public void setColor(String color){
if (color == "white") this.color = Color.white;
else if (color == "black") this.color = Color.black;
else if (color == "yellow") this.color = Color.yellow;
else {
System.out.println("Invalid color");
return;
}
repaint();
}
}
}
Don't disable anything. Simply change the state of your class, perhaps by using a few boolean flag variables/fields and change these flags depending on what is pressed.
So have boolean fields called label1PressedLast, label2PressedLast, and label3PressedLast or something similar, and when a label is pressed, check the states of all other flags and have your program's behavior change depending on the state of these flags and the label that was just pressed. Then set all flags to false except for the one corresponding to the label that was just pressed.
For example, this little program reacts only if the first and then the third JLabel have been pressed:
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
public class FlagEg extends JPanel {
private static final int LABEL_COUNT = 3;
private JLabel[] labels = new JLabel[LABEL_COUNT];
private boolean[] flags = new boolean[LABEL_COUNT];
public FlagEg() {
setLayout(new GridLayout(1, 0, 20, 0));
setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
// panel mouse listener
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent arg0) {
inactivateAll();
}
});
MouseListener labelsMouseListener = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent mouseEvt) {
myMousePressed(mouseEvt);
}
};
// create JLabels and add MouseListener
for (int i = 0; i < labels.length; i++) {
labels[i] = new JLabel("Label " + (i + 1));
labels[i].addMouseListener(labelsMouseListener);
labels[i].setOpaque(true);
labels[i].setBorder(BorderFactory.createLineBorder(Color.black));
add(labels[i]);
}
}
private void inactivateAll() {
for (int i = 0; i < labels.length; i++) {
labels[i].setBackground(null);
flags[i] = false;
}
}
private void myMousePressed(MouseEvent mouseEvt) {
JLabel label = (JLabel) mouseEvt.getSource();
// which label was pressed?
int index = -1;
for (int i = 0; i < labels.length; i++) {
if (label == labels[i]) {
index = i;
}
}
// check if first label and then third pressed:
if (flags[0] && index == 2) {
System.out.println("first and then third label pressed!");
}
// reset all labels and flags to initial state
inactivateAll();
// set pressed label background color and set flag of label just pressed
labels[index].setBackground(Color.pink);
flags[index] = true;
}
private static void createAndShowGui() {
FlagEg mainPanel = new FlagEg();
JFrame frame = new JFrame("Flag Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Logic iteration two: only label 1 is the "primer" JLabel. This is actually easier to implement, because now you only need one boolean flag, that representing label 1 being pressed:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class FlagEg2 extends JPanel {
private static final int LABEL_COUNT = 3;
private JLabel[] labels = new JLabel[LABEL_COUNT];
private boolean label1Flag = false;
public FlagEg2() {
setLayout(new GridLayout(1, 0, 20, 0));
setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
// panel mouse listener
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent arg0) {
inactivateAll();
}
});
MouseListener labelsMouseListener = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent mouseEvt) {
myMousePressed(mouseEvt);
}
};
// create JLabels and add MouseListener
for (int i = 0; i < labels.length; i++) {
labels[i] = new JLabel("Label " + (i + 1));
labels[i].addMouseListener(labelsMouseListener);
labels[i].setOpaque(true);
labels[i].setBorder(BorderFactory.createLineBorder(Color.black));
add(labels[i]);
}
}
private void inactivateAll() {
for (int i = 0; i < labels.length; i++) {
labels[i].setBackground(null);
label1Flag = false;
}
}
private void myMousePressed(MouseEvent mouseEvt) {
JLabel label = (JLabel) mouseEvt.getSource();
// which label was pressed?
int index = -1;
for (int i = 0; i < labels.length; i++) {
if (label == labels[i]) {
index = i;
}
}
if (label1Flag) {
if (index == 1) {
System.out.println("Label 1 and label 2 pressed");
} else if (index == 2) {
System.out.println("Label 1 and label 3 pressed");
}
}
// reset all labels and flags to initial state
inactivateAll();
// if label1, then activate it
if (index == 0) {
labels[0].setBackground(Color.pink);
label1Flag = true;
}
}
private static void createAndShowGui() {
FlagEg2 mainPanel = new FlagEg2();
JFrame frame = new JFrame("Flag Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
package javaapplication6;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
*
* #author Jan Vorcak <vorcak#mail.muni.cz>
*/
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
MouseListener listener = new MouseAdapter() {
private int count = 0;
#Override
public void mouseClicked(MouseEvent e) {
if(e.getComponent() instanceof JLabel) {
count++;
if (count >= 2) {
System.out.println("clicked 2 times on labels");
count = 0;
}
} else {
count = 0;
}
}
};
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JLabel l1 = new JLabel("Label 1");
JLabel l2 = new JLabel("Label 2");
JLabel l3 = new JLabel("Label 3");
l1.addMouseListener(listener);
l2.addMouseListener(listener);
l3.addMouseListener(listener);
frame.addMouseListener(listener); // or panel.addMouseListener(listener);
panel.add(l1);
panel.add(l2);
panel.add(l3);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
You could want to create a listener that do the job for using the putClientProperty method of JComponent.
public class JComponentClickCountListener extends MouseAdapter {
private final Integer ONE = 1;
#Override
public void mouseClicked(MouseEvent e) {
if (e.getComponent() instanceof JComponent) {
JComponent jComponent = (JComponent) e.getComponent();
Object property = jComponent.getClientProperty(JComponentClickCountListener.class);
if (property instanceof Number) {
property = ONE + ((Number) property).intValue();
}
else {
property = ONE;
}
jComponent.putClientProperty(JComponentClickCountListener.class, property);
}
}
}
Then in your code you can decide to have a single instace of that class for all of your components or create a new one each time.
This could give you the advantage of using the propertyChangeListener for future actions.
PS.
The code example do not represent all logic for OP question but i could by used as solid base. Later on i will try to update it. To cover that.
EDIT2:
I think that you should separate the logic, of selection and action over selected items. Then the task is divided into two tasks. First is the possibility to store the information about it state, clicked active, clicked again inactive. The second tasks it to operate on that status when a jComponent status was changed.
This is an simple example that i wrote, the functionality is to highlight the background of labels when the are selected and remove it when it was clicked again or the panel was clicked remove all selections.
This example is divided to three elements Enum, Iterface and class that manage the logic of selection
Enum - we store the possible statuses and a property key.
public enum JComponentActivationStatus {
NONE,
ACTIVE,
INACTIVE;
public static final String PROPERTY_KEY = JComponentActivationStatus.class.getCanonicalName();
}
Interface - provide a delegate for action to be taken when jcomponenet status change.
public abstract interface JComponenetActivationStatusChangeAction<T extends JComponent> {
public abstract void onActivation(T object);
public abstract void onDeactivation(T object);
}
Class - This class mange the status logic of jcomponents.
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JComponent;
public class JComponenetActivationManager {
public static <T extends JComponent> T addMouseStatusControl(T jComponent) {
jComponent.addMouseListener(new JComponentMouseStatusModyfier());
return jComponent;
}
public static <T extends JComponent> T addActivationStatusChangeAction(T jComponenet, JComponenetActivationStatusChangeAction<T> statusChangeAction) {
jComponenet.addPropertyChangeListener(craeteJCompositeActivationStatusChangeListener(statusChangeAction));
return jComponenet;
}
public static <T extends JComponent> PropertyChangeListener craeteJCompositeActivationStatusChangeListener(JComponenetActivationStatusChangeAction<T> action) {
return new JComponentStatusPropertyChangeListener<T>(action);
}
/**
* Class that set the status for the JComponet after doubClicl
*/
private final static class JComponentMouseStatusModyfier extends MouseAdapter {
#Override
public void mouseClicked(MouseEvent e) {
if(e.getComponent() instanceof JComponent) {
JComponent jComponent = (JComponent) e.getComponent();
Object propertyValue = jComponent.getClientProperty(JComponentActivationStatus.PROPERTY_KEY);
if(JComponentActivationStatus.ACTIVE.equals(propertyValue)) { //We check that the ACTIVE status is already selected, if so we inactive.
propertyValue = JComponentActivationStatus.INACTIVE; //If so we inactive it.
} else {
propertyValue = JComponentActivationStatus.ACTIVE; // Otherwise we set it as active
}
jComponent.putClientProperty(JComponentActivationStatus.PROPERTY_KEY, propertyValue); // We use the property key form status
}
}
}
/**
* Help class that fire the actions after status is changed
*/
private static final class JComponentStatusPropertyChangeListener<T extends JComponent> implements PropertyChangeListener {
private final JComponenetActivationStatusChangeAction<T> statusChangeAction;
/**
*
*/
public JComponentStatusPropertyChangeListener(JComponenetActivationStatusChangeAction<T> statusChangeAction) {
if(statusChangeAction == null) {
throw new IllegalArgumentException("action can not be null at this point");
}
this.statusChangeAction = statusChangeAction;
}
#Override
public void propertyChange(PropertyChangeEvent evt) {
if(JComponentActivationStatus.PROPERTY_KEY.equals(evt.getPropertyName())) {
if(JComponentActivationStatus.ACTIVE.equals(evt.getNewValue())) {
statusChangeAction.onActivation((T) evt.getSource());
}
if(JComponentActivationStatus.INACTIVE.equals(evt.getNewValue())){
statusChangeAction.onDeactivation((T) evt.getSource());
}
}
}
}
}
That class contain two public static method, that allow the developer to add the functionality to mange status to any jComponent object, add subscribe the action handler if any change occur.
At the end we have the main method that test our solution
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JLabel l1 = new JLabel("Label 1");
JLabel l2 = new JLabel("Label 2");
JLabel l3 = new JLabel("Label 3");
panel.setBackground(Color.CYAN);
addMouseStatusControl(panel);
addMouseStatusControl(l1);
addMouseStatusControl(l2);
addMouseStatusControl(l3);
JComponenetActivationStatusChangeAction<JLabel> activeBackground = new JComponenetActivationStatusChangeAction<JLabel>() {
#Override
public void onActivation(JLabel object) {
object.setOpaque(true);
object.setBackground(Color.YELLOW);
}
#Override
public void onDeactivation(JLabel object) {
object.setOpaque(false);
object.setBackground(object.getParent().getBackground());
}
};
JComponenetActivationStatusChangeAction<JPanel> deactivateChildrens = new JComponenetActivationStatusChangeAction<JPanel>() {
#Override
public void onDeactivation(JPanel object) {
}
#Override
public void onActivation(JPanel object) {
for(Component component : object.getComponents()) {
if(component instanceof JComponent) {
((JComponent) component).putClientProperty(JComponentActivationStatus.PROPERTY_KEY,JComponentActivationStatus.INACTIVE);
}
}
}
};
addActivationStatusChangeAction(l1, activeBackground);
addActivationStatusChangeAction(l2, activeBackground);
addActivationStatusChangeAction(l3, activeBackground);
addActivationStatusChangeAction(panel, deactivateChildrens);
panel.add(l1);
panel.add(l2);
panel.add(l3);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
The solution is very flexible and extendable in case you will need to add more labels.
The example is for those that want to learn. Any comment would be appreciate.

Categories