Convert String into Component name in Java - java

I searched StackOverflow and found this question but I couldn't get it.
How do I invoke a Java method when given the method name as a string?
I have some JLabels and JPanels and each Label is working as a custom graphical button to change background color of a particular JPanel and as there are alot of these labels so I have created a custom MouseListener which is to change the background color of particular JPanel with the name each JLabel has.
Now as these JLabels are giving name of calling JPanels in String value, I want something like this
#Override
public void mouseClicked(MouseEvent e)
{
e.getComponent().getName().setBackground(new COLOR.RED);
}
But I cannot do so.
I just want to convert my string into JPanel's name.

You can use "client properties" from JComponent. Each Jcomponent contains a Map to put properties inside. You can use a constant String like "associatedPanel" for the key, and the JPanel for the value.
The code could be something like this:
JPanel panel1 = new JPanel();
JLabel label1 = new JLabel();
label1.putClientProperty("associatedPanel", panel1);
Now in the mouse listener use getClientProperty("associatedPanel") to obtain the associated panel to set the background.

You can do it like this:
create a map:
Map<String, JPanel> map = new HashMap<String, JPanel>();
then put all your jPanels in it using their names as keys:
map.put("jPanel1", jPanel1);
Then in the event listener:
JPanel jPanel1 = map.get(e.getComponent().getName());

I would say that the simplest solution to associate 2 elements of the UI is to combine them into a class. Then referencing the corresponding element from the other becomes obvious.
Something like:
class LabelPanel {
JLabel label;
JPanel pane;
...
}
Basic working 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 java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestLabelPanelComposition {
public static class LabelPanel {
private final JLabel label;
private final JPanel panel;
private Color colorToSet;
public LabelPanel(String labelText, final Color colorToSet) {
super();
this.colorToSet = colorToSet;
this.label = new JLabel(labelText);
this.panel = new JPanel();
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
Color old= panel.getBackground();
panel.setBackground(LabelPanel.this.colorToSet);
LabelPanel.this.colorToSet = old;
}
});
}
public JLabel getLabel() {
return label;
}
public JPanel getPanel() {
return panel;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TestLabelPanelComposition().initUI();
}
});
}
protected void initUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Random r= new Random();
List<LabelPanel> labelPanels =new ArrayList<TestLabelPanelComposition.LabelPanel>();
for(int i=0;i<10;i++) {
LabelPanel labelPanel = new LabelPanel("My Label to click "+(i+1), new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256)));
labelPanel.getPanel().add(new JLabel("Some dummy text inside panel "+(i+1)));
labelPanels.add(labelPanel);
}
frame.setLayout(new GridLayout(0, 5));
for (LabelPanel labelPanel : labelPanels) {
frame.add(labelPanel.getLabel());
}
for (LabelPanel labelPanel : labelPanels) {
frame.add(labelPanel.getPanel());
}
frame.pack();
frame.setVisible(true);
}
}
This should not be too hard to adapt to your actual situation .

Related

Search JPanel by name

I was following the How to use CardLayout Java Swing tutorial and I got to the point where the panel is added to the layout:
JPanel cards;
final static String BUTTONPANEL = "Card with JButtons";
//Create the "cards".
JPanel card1 = new JPanel();
//Create the panel that contains the "cards".
cards = new JPanel(new CardLayout());
cards.add(card1, BUTTONPANEL);
Also they say:
To add a component to a container that a CardLayout object manages,
specify a string that identifies the component being added. For
example, in this demo, the first panel has the string "Card with
JButtons"
So if that string is used to identify the component being added I was wondering if there was a way to get a specific panel in the layout from an AssertJ Swing FrameFixture or directly from the JFrame object, passing the string.
I see that the add method is inherited from java.awt.Container. I was expecting to find a method that would allow me to do something like frame.getComponent(BUTTONPANEL) but that method expects an index as parameter. Did I overlook something?
Also I'm aware of the fact that I could just do card1.setName(BUTTONPANEL) and then in my tests retrieve it with:
window = new FrameFixture(view);
window.panel(BUTTONPANEL);
But what's the point of setting that string in the add method if there is no use for it.
Thanks.
Edit:
I had missed the fact that of course the string BUTTONPANEL it it is used to change the panel from the card layout, like this:
cardLayout.show(getContentPane(), BUTTONPANEL);
And so obviously that string has a use.
However I was looking for a way to be able to get the JPanel object by calling a method on the JFrame or FrameFixture object, passing the string. Something like this:
JPanel buttonPanelPanel = frame.getPanelFromName(BUTTONPANEL);
This is because within the tests I don't have a direct access to the panels, but only to the frame. In order to make assertions on a particular panel I wanted to be able to perform a get of the panel with the string used in add. But maybe this is not possible.
I added a method to the MainPanel class to return a JPanel when you pass a String. I don't use the method, but it's there.
I made all the additional classes inner classes so I could post the code as one block.
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CardPanelExample implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new CardPanelExample());
}
private final MainPanel mainPanel;
public CardPanelExample() {
this.mainPanel = new MainPanel(this);
}
#Override
public void run() {
JFrame frame = new JFrame("CardPanel Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel.getPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public void setNextPanel() {
mainPanel.setNextPanel();
}
public JPanel getPanelFromName(String name) {
return mainPanel.getPanelFromName(name);
}
public class MainPanel {
private final CardLayout cardLayout;
private final JPanel panel;
private JPanel yellowPanel, orangePanel, whitePanel;
private final String[] panelStrings;
private String currentPanelString;
public MainPanel(CardPanelExample view) {
this.cardLayout = new CardLayout();
this.panelStrings = new String[] { "alpha", "beta", "gamma" };
this.currentPanelString = panelStrings[0];
this.panel = createMainPanel(view, cardLayout, panelStrings);
}
private JPanel createMainPanel(CardPanelExample view,
CardLayout cardLayout, String[] panelStrings) {
this.yellowPanel = new ColorPanel(view, Color.YELLOW).getPanel();
this.orangePanel = new ColorPanel(view, Color.ORANGE).getPanel();
this.whitePanel = new ColorPanel(view, Color.WHITE).getPanel();
JPanel panel = new JPanel(cardLayout);
panel.add(yellowPanel, panelStrings[0]);
panel.add(orangePanel, panelStrings[1]);
panel.add(whitePanel, panelStrings[2]);
return panel;
}
public JPanel getPanelFromName(String name) {
if (name.equals(panelStrings[0])) {
return yellowPanel;
} else if (name.equals(panelStrings[1])) {
return orangePanel;
} else if (name.equals(panelStrings[2])) {
return whitePanel;
} else {
return null;
}
}
public void setNextPanel() {
for (int index = 0; index < panelStrings.length; index++) {
if (currentPanelString.equals(panelStrings[index])) {
index = ++index % panelStrings.length;
currentPanelString = panelStrings[index];
cardLayout.show(panel, currentPanelString);
return;
}
}
}
public JPanel getPanel() {
return panel;
}
}
public class ColorPanel {
private final JPanel panel;
public ColorPanel(CardPanelExample view, Color backgroundColor) {
this.panel = createMainPanel(view, backgroundColor);
}
private JPanel createMainPanel(CardPanelExample view, Color backgroundColor) {
JPanel panel = new JPanel(new FlowLayout());
panel.setBackground(backgroundColor);
panel.setBorder(BorderFactory.createEmptyBorder(25, 150, 25, 150));
JButton button = new JButton("Next Panel");
button.addActionListener(new ButtonListener(view));
panel.add(button);
return panel;
}
public JPanel getPanel() {
return panel;
}
}
public class ButtonListener implements ActionListener {
private final CardPanelExample view;
public ButtonListener(CardPanelExample view) {
this.view = view;
}
#Override
public void actionPerformed(ActionEvent event) {
view.setNextPanel();
}
}
}

When button clicked, replace entire window content with an image

SOLVED
So I have an issue where when I click the button, I want an image to replace the entire content of the window. But it's only replacing, what I believe to be, a part of a panel. Should I not use panels in this instance? I found some code online which didn't use panels which worked, but maybe there is a scenario where I can remove the panel and just cover the entire frame with my image when the button is clicked?
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class SatNav extends JFrame {
private JFrame frame;
private JPanel panel;
private JLabel satelliteLabel;
private JLabel aboutLabel;
private JButton satellite;
private JButton about;
public SatNav() {
frame = new JFrame("Work Package 5");
frame.setVisible(true);
frame.setSize(300, 380);
about = new JButton("About");
add(about);
event abo = new event();
about.addActionListener(abo);
panel = new JPanel();
frame.add(panel);
panel.add(about);
setLocationRelativeTo(null); //This is for centering the frame to your screen.
setDefaultCloseOperation(EXIT_ON_CLOSE); //This for closing your application after you closing the window.
}
public class event implements ActionListener {
public void actionPerformed(ActionEvent abo) {
ImagePanel imagePanel = new ImagePanel();
//JFrames methods
panel.add(imagePanel, BorderLayout.CENTER);
revalidate();
repaint();
about.setVisible(false);
//satellite.setVisible(false);
}
}
public class ImagePanel extends JPanel {
private BufferedImage image;
public ImagePanel() {
try {
image = ImageIO.read(new File("about.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
setBorder(BorderFactory.createLineBorder(Color.black, 2));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
}
}
public static void main(String[] args) {
new SatNav();
}
}
Your problem is that you're treating the panel JPanel as if it has a BorderLayout when it doesn't. Rather it has JPanel's default FlowLayout which will size components to their preferred sizes (here [0, 0]) rather than have contained components fill the container. The simple solution: give your panel a BorderLayout:
panel = new JPanel(new BorderLayout());
Now when adding components, the BorderLayout constants will be respected by the container's layout.
Another and possibly better and more durable solution is to use a CardLayout to help you swap components.
For example:
import java.awt.CardLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class SatNav2 extends JPanel {
private static final long serialVersionUID = 1L;
// a publicly available example image for demonstration purposes:
public static final String SAT_PATH = "https://upload.wikimedia.org"
+ "/wikipedia/commons/1/18/AEHF_1.jpg";
private static final String INTRO_PANEL = "intro panel";
private static final String IMAGE_LABEL = "image label";
// our layout
private CardLayout cardLayout = new CardLayout();
// JLabel to display the image
private JLabel imgLabel = new JLabel();
public SatNav2(Image img) {
// put image into JLabel
imgLabel.setIcon(new ImageIcon(img));
// JPanel to hold JButton
JPanel introPanel = new JPanel();
// add button that does the swapping
introPanel.add(new JButton(new ShowImageAction("Show Image")));
// set the CardLayout and add the components. Order of adding
// is important since the first one is displayed
setLayout(cardLayout);
// add components w/ String constants
add(introPanel, INTRO_PANEL);
add(imgLabel, IMAGE_LABEL);
}
private class ShowImageAction extends AbstractAction {
public ShowImageAction(String text) {
super(text);
}
#Override
public void actionPerformed(ActionEvent e) {
// tell card layout to show next component
cardLayout.next(SatNav2.this);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
createAndShowGui();
} catch (IOException e) {
e.printStackTrace();
}
});
}
private static void createAndShowGui() throws IOException {
// get the image
URL imgUrl = new URL(SAT_PATH);
Image img = ImageIO.read(imgUrl);
// pass image into our new JPanel
SatNav2 mainPanel = new SatNav2(img);
JFrame frame = new JFrame("Satellite");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}

repaint() method does not paint new frame

I have looked at a lot of answers but i still cannot find a solution. I have a JFrame and two JPanels. I want to remove the one panel and replace it with the second when a button is pressed, but the repaint() method does not refresh the frame. Please help.
Here is my code for the frame:
import javax.swing.*;
import java.awt.*;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
public class MainFrame
{
static JFrame mainFrame;
int height = 650;
int width = 1042;
public MainFrame()
{
mainFrame = new JFrame();
mainFrame.setBounds(0, 0, width, height);
mainFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);
mainFrame.setResizable(false);
}
public static void main(String[] args)
{
new MainMenu();
mainFrame.setVisible(true);
}
}
This is the code for my MainMenu panel
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import static java.awt.Color.CYAN;
import static java.awt.Color.red;
public class MainMenu extends MainFrame
{
public MainMenu()
{
components();
}
//variable decleration
JPanel menuPanel;
JLabel title;
JButton periodicTable;
private void components()
{
int buttonW = 500;
int buttonH = 50;
//creating panel
menuPanel = new JPanel();
menuPanel.setLayout(null);
menuPanel.setBackground(CYAN);
//creating title label
title = new JLabel("Application Title", SwingConstants.CENTER);
title.setFont(new Font("Calibri Body", 0, 50));
title.setBounds(width / 3 - buttonW / 2, 50, buttonW, buttonH + 10);
//creating periodic table button
periodicTable = new JButton();
periodicTable.setText("Periodic Table");
periodicTable.setBounds(width / 3 - buttonW / 2, 50 + buttonH + 60, buttonW, buttonH);
periodicTable.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
periodicTableActionPerformed(event);
}
});
//adding components to panel
menuPanel.add(title);
menuPanel.add(periodicTable);
//adding panel to MainFrame
mainFrame.add(menuPanel);
}
private void periodicTableActionPerformed(ActionEvent event)
{
mainFrame.remove(menuPanel);
mainFrame.repaint();
new PeriodicTable();
mainFrame.repaint();
}
}
And finally my PeriodicTable panel
import javax.swing.*;
import java.awt.*;
public class PeriodicTable extends MainFrame
{
public PeriodicTable()
{
periodicComponents();
}
JPanel ptPanel;
private void periodicComponents()
{
ptPanel = new JPanel();
ptPanel.setLayout(null);
ptPanel.setBackground(Color.RED);
mainFrame.add(ptPanel);
}
}
I have no idea why you are extending MainFrame. Looks unnecessary to me.
I want to remove the one panel and replace it with the second when a button is pressed
Then use a CardLayout. Read the section from the Swing tutorial on How to Use CardLayout for a working example.
The tutorial will show you how to better structure your code.
Your PeriodicTable extends MainFrame. When creating new PeriodicTable you create with it new MainFrame which has its own instance of JFrame (MainFrame.mainFrame). You need to add that panel to existing mainFrame in MainMenu
I suggest removing changing your PeriodicTable class like this:
import javax.swing.*;
import java.awt.*;
public class PeriodicTable extends JPanel // Not MainFrame, but new custom panel
{
public PeriodicTable()
{
periodicComponents();
}
private void periodicComponents()
{
// You don't need ptPanel anymore, because `this` is JPanel
setLayout(null);
setBackground(Color.RED);
}
}
and change your actionPerformed function to something like this:
private void periodicTableActionPerformed(ActionEvent event)
{
mainFrame.remove(menuPanel); // Remove old panel
mainFrame.add(new PeriodicTable()); // Create and add to existing mainFrame
mainFrame.repaint(); // Just one repaint at the end
// I think it will work even without repaint, because add and remove should schedule repainting as well
}

In a java Jframe can I add/remove a Jlabel from view using a checkbox?

Im making an application that lets me perform hashes, at the top I want to have a group of check boxes basically saying the four different hash types I have. When the check boxes are selected I want the labels to appear showing the hashed entered text.
I've attached an image to hopefully make it easier to understand what I mean. The reason I'm doing this is so that when the final program is made with almost 10 rows of text boxes and labels it can be reduced only to show the ones that the user wishes to see.This hopefully should explain what I mean.
I've been able to get it so the checkboxes make it visible or not visible but that also then just leaves a blank space where one row of labels used to be rather than moving everything up a row
I've now added my coding so people can see how I'm doing it currently and help define where needs to be modified
import java.awt.*;
import java.awt.event.*;
import java.security.*;
import javax.swing.*;
public class Hasher extends JFrame implements ActionListener {
String UserInput;
private JTextField textInputField;
private static JLabel MD5Hashed,MD5Label;
private static JCheckBox MD5Check, SHA1Check, SHA256Check, FileCheck;
private JFrame contentPane;
public Hasher() {
this.setTitle("Hasher");
Container contentPane = this.getContentPane();
contentPane.setLayout(new GridLayout(0,1) );
contentPane.setBackground(new Color(88,148,202));
//CheckBoxes
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
JPanel checkBoxPanel = new JPanel();
MD5Check = new JCheckBox("MD5");
MD5Check.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
boolean Visible = MD5Check.isSelected();
MD5Hashed.setVisible(Visible);
MD5Label.setVisible(Visible);
}
});
checkBoxPanel.add(MD5Check);
SHA1Check = new JCheckBox("SHA-1");
checkBoxPanel.add(SHA1Check);
SHA256Check = new JCheckBox("SHA-256");
checkBoxPanel.add(SHA256Check);
FileCheck = new JCheckBox("File Hashing");
checkBoxPanel.add(FileCheck);
mainPanel.add(checkBoxPanel);
contentPane.add(mainPanel);
//Entered data to perform hash on
contentPane.add(new JLabel (" Enter text to hash"));
textInputField = new JTextField();
//HashingProcess inputListener = new HashingProcess( );
//textInputField.addActionListener(inputListener);
contentPane.add( textInputField);
//MD5 hash is completed
MD5Label = new JLabel( " Using MD5 the hash is: " );
contentPane.add( MD5Label);
MD5Hashed = new JLabel( "??") ;
contentPane.add( MD5Hashed );
MD5Hashed.setVisible(false);
MD5Label.setVisible(false);
}
public static void main(String[] args) {
Hasher theWindow = new Hasher( );
theWindow.setSize(400, 400 );
theWindow.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
theWindow.setVisible(true);
}
}
You have two frames...
public class Hasher extends JFrame implements ActionListener {
//...
private JFrame contentPane;
//..
This immediately raises the question, which one is actually on the screen and which one are you actually interacting with? While this might not be directly related to your problem, it is confusing.
As a general rule of thumb, don't extend from top level containers like JFrame, it locks you into a single use case and can cause no end of confusion. Instead, start with a JPanel and add it to an instance of JFrame or any other container you like.
The "main probable" problem is, Swing is lazy. It won't update the UI until you tell it or the UI is resized.
When adding and removing components, you need to call revalidate and repaint on the container to trigger an update - this is what's actually going wrong in your code, you're referencing contentPane, by that is private JFrame contentPane; and not the contentPane of the JFrame from which Hasher extends ... see, confusion.
Happening dug around your code a bit, it's obvious that you have a lot of repeated operations going on, the only core difference is the algorithm used to hash the text.
So, with that in mind, we can create some basic classes to do most of the work, for example...
public class HashPane extends JPanel {
private JLabel hashedLabel;
private JLabel promptLabel;
private HashAlgorithim algorithim;
public HashPane(String labelText, HashAlgorithim algorithim) {
setOpaque(false);
this.algorithim = algorithim;
setLayout(new FlowLayout(FlowLayout.LEFT));
promptLabel = new JLabel(labelText);
add(promptLabel);
hashedLabel = new JLabel("??");
add(hashedLabel);
}
public void setText(String text) {
hashedLabel.setText(algorithim.generateHash(text));
}
}
This is just two labels, which show a prompt and a result. The result is generated via a plug algorithm which is used to generate the hash for the supplied text
The algorithm itself is just a interface which defines the basic contract...
public interface HashAlgorithm {
public String generateHash(String from);
}
You would then need to create an implementation of each algorithm you wanted to use
Now, making a panel visible/invisible simply becomes a matter of associating a JCheckBox with a HashPane which can be achieved through a simple Map...
public class Hasher extends JPanel {
//...
private Map<JCheckBox, HashPane> mapPanes;
public Hasher() {
//...
HashPane md5Pane = new HashPane("MD5 hash = ", new NotAMD5Alorithim());
//...
HashPane sha1Pane = new HashPane("SHA-1 hash = ", new NotAMSHA1Alorithim());
//..
mapPanes = new HashMap<>(25);
mapPanes.put(MD5Check, md5Pane);
mapPanes.put(SHA1Check, sha1Pane);
//...
You can then use a single ActionListener to manage all the JCheckBoxs
public class Hasher extends JPanel {
//...
private Map<JCheckBox, HashPane> mapPanes;
public Hasher() {
//...
ActionHandler listener = new ActionHandler();
for (Entry<JCheckBox, HashPane> entry : mapPanes.entrySet()) {
entry.getKey().addActionListener(listener);
entry.getValue().setVisible(false);
}
}
protected class ActionHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
JCheckBox cb = (JCheckBox) e.getSource();
HashPane hashPane = mapPanes.get(cb);
hashPane.setVisible(cb.isSelected());
revalidate();
repaint();
}
}
And because I pretty much butchered your code...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Hasher extends JPanel {
String UserInput;
private JTextField textInputField;
private static JCheckBox MD5Check, SHA1Check, SHA256Check, FileCheck;
private Map<JCheckBox, HashPane> mapPanes;
public Hasher() {
setLayout(new BorderLayout());
setBackground(new Color(88, 148, 202));
//CheckBoxes
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
JPanel checkBoxPanel = new JPanel();
MD5Check = new JCheckBox("MD5");
checkBoxPanel.add(MD5Check);
SHA1Check = new JCheckBox("SHA-1");
checkBoxPanel.add(SHA1Check);
SHA256Check = new JCheckBox("SHA-256");
checkBoxPanel.add(SHA256Check);
FileCheck = new JCheckBox("File Hashing");
checkBoxPanel.add(FileCheck);
mainPanel.add(checkBoxPanel);
add(mainPanel, BorderLayout.NORTH);
JPanel centerPane = new JPanel(new BorderLayout());
centerPane.setOpaque(false);
JPanel inputPane = new JPanel(new FlowLayout(FlowLayout.LEFT));
inputPane.setOpaque(false);
//Entered data to perform hash on
inputPane.add(new JLabel("Enter text to hash: "));
textInputField = new JTextField(20);
inputPane.add(textInputField);
centerPane.add(inputPane, BorderLayout.NORTH);
JPanel output = new JPanel(new GridBagLayout());
output.setOpaque(false);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
gbc.gridwidth = GridBagConstraints.REMAINDER;
HashPane md5Pane = new HashPane("MD5 hash = ", new NotAMD5Alorithim());
output.add(md5Pane, gbc);
gbc.gridx = 0;
gbc.gridy++;
HashPane sha1Pane = new HashPane("SHA-1 hash = ", new NotAMSHA1Alorithim());
output.add(sha1Pane, gbc);
// last pane
gbc.gridy++;
gbc.weighty = 1;
output.add(new JLabel(), gbc);
centerPane.add(output);
add(centerPane);
mapPanes = new HashMap<>(25);
mapPanes.put(MD5Check, md5Pane);
mapPanes.put(SHA1Check, sha1Pane);
//...
ActionHandler listener = new ActionHandler();
for (Entry<JCheckBox, HashPane> entry : mapPanes.entrySet()) {
entry.getKey().addActionListener(listener);
entry.getValue().setVisible(false);
}
}
protected class ActionHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
JCheckBox cb = (JCheckBox) e.getSource();
HashPane hashPane = mapPanes.get(cb);
hashPane.setVisible(cb.isSelected());
revalidate();
repaint();
}
}
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();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Hasher());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface HashAlgorithm {
public String generateHash(String from);
}
public class NotAMD5Alorithim implements HashAlgorithm {
#Override
public String generateHash(String from) {
return "bananas";
}
}
public class NotAMSHA1Alorithim implements HashAlgorithm {
#Override
public String generateHash(String from) {
return "bananas";
}
}
public class HashPane extends JPanel {
private JLabel hashedLabel;
private JLabel promptLabel;
private HashAlgorithm algorithim;
public HashPane(String labelText, HashAlgorithm algorithim) {
setOpaque(false);
this.algorithim = algorithim;
setLayout(new FlowLayout(FlowLayout.LEFT));
promptLabel = new JLabel(labelText);
add(promptLabel);
hashedLabel = new JLabel("??");
add(hashedLabel);
}
public void setText(String text) {
hashedLabel.setText(algorithim.generateHash(text));
}
}
}
Having said all that, I might be tempted to have the JCheckBox in the HashPane and has the HashPane always visible and simply disable the output text ... or simply not bother and always have all the algorithms available all the time
you need to handle Events for all check-box while check/uncheck,
public void actionPerformed(ActionEvent actionEvent) {
if(all check-box un-checked){
// someLable.setVisible(false);
}else if(MD5 checked){
// peform operation based upon MD5
// someLable.setVisible(true);
}
// likewise for all others
}
Change
public void actionPerformed(ActionEvent e) {
boolean Visible = MD5Check.isSelected();
MD5Hashed.setVisible(Visible);
MD5Label.setVisible(Visible);
}
to:
public void actionPerformed(ActionEvent e) {
boolean Visible = MD5Check.isSelected();
MD5Hashed.setVisible(Visible);
MD5Label.setVisible(Visible);
contentPane.validate();
contentPane.repaint();
}
If You want to remove MD5Hashed and MD5Label then something like this:
{
if(MD5Check.isSelected()){
MD5Hashed.remove();
MD5Label.remove();
}
else{
contentPane.add( MD5Label);
contentPane.add( MD5Hashed );
}
contentPane.validate();
contentPane.repaint();
}

Composition vs inheritence in JButton

I'd like to create a simple table game by Swing. I have a JFrame and a JPanel variable.
I want to add JButtons to this JPanel, but I'd like to create an own class.
I made a class that extends JButton (inheritence):
public class GameField extends JButton {...}
So I could add GameFields to the JPanel.
But I'd like to create GameFields by composition:
public class GameField{
private JButton button;
}
But in this clase how I can add GameField to JPanel?
Can I solve this problem by compisition?
But in this clase how I can add GameField to JPanel? Can I solve this
problem by compisition?
You do this by adding a simple getter like this:
public class GameField{
private JButton button;
public GameField(String text) {
button = new JButton(text);
// do your stuff here
}
public JButton getButton() {
return button;
}
}
Then in your GUI:
public void createAndShowGUI() {
JPanel panel = new JPanel(new GridLayout(5,5));
panel.add(new GameField("Button # 1").getButton());
panel.add(new GameField("Button # 2").getButton());
...
JFrame frame = new JFrame("Game");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
Edit
You've stated in a comment:
Thanks, but in this case if I'd like to access this field (i.e.
panel.getComponent(i)), I can get only a JButton, and not a GameField.
You can keep a list with your GameField objects or you can use putClientProperty() method to keep a reference to the GameField object as shown in the example below:
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Demo {
private void createAndShowGUI() {
ActionListener actionListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JButton button = (JButton)e.getSource();
GameField gameField = (GameField)button.getClientProperty("GameField");
if(gameField != null) {
System.out.println(gameField.getText());
}
}
};
GameField gameField1 = new GameField("Button # 1");
gameField1.getButton().addActionListener(actionListener);
GameField gameField2 = new GameField("Button # 2");
gameField2.getButton().addActionListener(actionListener);
JPanel content = new JPanel(new GridLayout());
content.add(gameField1.getButton());
content.add(gameField2.getButton());
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(content);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
class GameField {
private String text;
private JButton button;
public GameField(String text) {
this.text = text;
button = new JButton(text);
button.putClientProperty("GameField", GameField.this);
}
public JButton getButton() {
return button;
}
public String getText() {
return text;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Demo().createAndShowGUI();
}
});
}
}
If you wish your GameField objects to have JComponents and still be able to add them to other JComponents, have them extend JPanel instead of JButton.
You can then have your GameField objects as JPanels with other JComponents and add them to your JFrame.

Categories