How to completely get rid of a JPanel and everything in it while running?
package textgame;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class EscapeFromPrison extends JFrame implements ActionListener{
JButton startGameButton;
JButton creditsButton;
JButton choice1;
Button choice2;
JLabel mainTitleLabel;
JLabel question;
JLabel space;
JLabel credits;
JPanel titleScreen;
public EscapeFromPrison(){
super("Escape From Prison");
setLookAndFeel();
setSize(500,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainTitleLabel = new JLabel("<html>Escape From Prison</html>");
startGameButton = new JButton("<html>START<html>");
startGameButton.setActionCommand("StartGameButton");
creditsButton = new JButton("<html>CREDITS</html>");
creditsButton.addActionListener(this);
creditsButton.setActionCommand("CreditsButton");
question = new JLabel("");
space = new JLabel("");
credits = new JLabel("");
choice1 = new JButton("");
choice2 = new JButton("");
JPanel titleScreen = new JPanel();
BoxLayout titleScreenLayout = new BoxLayout(titleScreen, BoxLayout.Y_AXIS);
titleScreen.setLayout(titleScreenLayout);
titleScreen.add(mainTitleLabel);
titleScreen.add(startGameButton);
titleScreen.add(creditsButton);
add(titleScreen);
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent buttonClick){
String event = buttonClick.getActionCommand();
In this if statement I want to get rid of mainTitleLabel, startGameButton, and creditsButton. So question can be in the top left position, cause right now they are currently invisible and the question is in the top right position. I am using grid layout.
if(event.equals("StartGameButton")){
GridLayout grid = new GridLayout(2,2);
setLayout(grid);
question.setText("<html>text</html>");
choice1.setActionCommand("");
choice1.setText("");
choice2.setActionCommand("");
choice2.setText("");
mainTitleLabel.setVisible(false);
startGameButton.setVisible(false);
creditsButton.setVisible(false);
add(question);
add(choice1);
add(choice2);
setVisible(true);
}
if(event.equals("CreditsButton")){
FlowLayout flo = new FlowLayout();
setLayout(flo);
credits.setText("<html></html>");
mainTitleLabel.setVisible(false);
startGameButton.setVisible(false);
creditsButton.setVisible(false);
add(credits);
setVisible(true);
}
}
private void setLookAndFeel(){
try{
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
}catch(Exception exc){
//ignore error
}
}
public static void main(String[] arguments){
EscapeFromPrison frame = new EscapeFromPrison();
}
}
The basic problem to your current code is startGameButton is never registered to an ActionListener, so it will never do anything.
The large issue is your code is going to become massively complicated to manage as you add more content. A better solution would be to separate each view in it's own class, which you can then manage independently and switch in and out as you need.
This is a beginning of the concept of Model-View-Controller, where you separate your functionality into self contained domains which can communicate via something like a observer pattern (as one idea).
With this you can use a CardLayout to make it easier to switch between views more simply.
Basic example...
This is just one of many possible ways to achieve this
First, we need to define some kind of "controller" which can be used to control what is been made visible. We uses interfaces as the primary contract as they limit the exposure of the implementation and define the exact contract that we expect to be maintained between class, this is commonly known as "program to interfaces", see Smarter Java development and Code to Interface for more details
public interface CardGameController {
public void showMainMenu();
public void showQuestion();
public void showCredits();
}
Now, because I want to use a CardLayout as the underlying mechanism for controlling the views, I need a implementation of the CardGameController which can do this...
public class DefaultCardGameController implements CardGameController {
public static final String MAIN_MENU_PANE = "mainMenuPane";
public static final String CREDITS_PANE = "creditsPane";
public static final String QUESTION_PANE = "questionPane";
private Container parent;
private CardLayout cardLayout;
public DefaultCardGameController(Container parent, CardLayout cardLayout) {
this.parent = parent;
this.cardLayout = cardLayout;
}
public Container getParent() {
return parent;
}
public CardLayout getCardLayout() {
return cardLayout;
}
protected void show(String name) {
getCardLayout().show(getParent(), name);
}
#Override
public void showMainMenu() {
show(MAIN_MENU_PANE);
}
#Override
public void showCredits() {
show(CREDITS_PANE);
}
#Override
public void showQuestion() {
show(QUESTION_PANE);
}
}
Have a look at How to Use CardLayout for more details
Now, we need the view we want to manage...
public class MenuPane extends JPanel {
private JButton startGameButton;
private JButton creditsButton;
private JLabel mainTitleLabel;
private CardGameController controller;
public MenuPane(CardGameController controller) {
this.controller = controller;
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
mainTitleLabel = new JLabel("<html>Escape From Prison</html>");
startGameButton = new JButton("<html>START<html>");
startGameButton.setActionCommand("StartGameButton");
startGameButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
controller.showQuestion();
}
});
creditsButton = new JButton("<html>CREDITS</html>");
creditsButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
controller.showCredits();
}
});
creditsButton.setActionCommand("CreditsButton");
add(mainTitleLabel, gbc);
add(startGameButton, gbc);
add(creditsButton, gbc);
}
}
public class QuestionPane extends JPanel {
private JButton choice1;
private JButton choice2;
private JLabel question;
private CardGameController controller;
public QuestionPane(CardGameController controller) {
this.controller = controller;
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
question = new JLabel("The meaning of life, the universe and everything!?");
choice1 = new JButton("42");
choice2 = new JButton("46");
add(question, gbc);
JPanel panel = new JPanel();
panel.add(choice1);
panel.add(choice2);
gbc.gridy++;
add(panel, gbc);
// Have some mechanism to control the questions
}
}
public class CreditsPane extends JPanel {
private JLabel credits;
private CardGameController controller;
public CreditsPane(CardGameController controller) {
this.controller = controller;
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
credits = new JLabel("Happy Bunnies");
add(credits);
}
}
And finally, the "master" view which brings it all together...
public class EscapeFromPrison extends JPanel {
private MenuPane menuPane;
private QuestionPane questionPane;
private CreditsPane creditsPane;
public EscapeFromPrison() {
CardLayout cardLayout = new CardLayout();
setLayout(cardLayout);
DefaultCardGameController controller = new DefaultCardGameController(this, cardLayout);
menuPane = new MenuPane(controller);
questionPane = new QuestionPane(controller);
creditsPane = new CreditsPane(controller);
add(menuPane, DefaultCardGameController.MAIN_MENU_PANE);
add(questionPane, DefaultCardGameController.QUESTION_PANE);
add(creditsPane, DefaultCardGameController.CREDITS_PANE);
controller.showMainMenu();
}
private static void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
} catch (Exception exc) {
//ignore error
}
}
public static void main(String[] arguments) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
setLookAndFeel();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new EscapeFromPrison());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Now, this is a very limited example, which takes what you have already done and demonstrates some basic principles.
Because you'll be asking more then one question, you will need some way to manage the questions (and answers) more efficiently, this would be best done by some kind of model which contained all the questions, possible answers and the users answer. This way, you would get away with just a single question view, but which could use the information in the question model to reconfigure itself to display each new question
For example
Related
I know that this kind of issue has been discussed here many times, but I'm confused. I'm totally beginner in Java and I honestly don't know what to do and I admit that I don't have that much time to read whole documentation provided by Oracle. Here's my problem:
I'm trying to program a GUI for my program that will be show interference of acoustic waves. Mathematical functionality doesn't matter in here. I've got two classes called Window and Sliders. Window is intended to be a 'main GUI class' and Sliders is supposed to inherit (?) from it.
This comes from another issue that I need to implement ActionListener in class Window and ChangeListener in Sliders class. I heard that one class can't implement several classes that's why I made two.
Now, I wrote a little bit chaotic those two classes, but I don't know how to combine them. It's really silly, but after C++ I'm pretty confused how to tell the program that it is supposed to show in one frame either buttons defined in Window class and sliders defined in Sliders class. Currently it shows only buttons I want to make it showing sliders too.
I'm very sorry for chaotic pseudo code, please help. Please, try to explain as simply as you can/possible. Please feel free to ignore overrided methods, they're not finished yet.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
public class Window extends JFrame implements ActionListener
{
private JButton showChord, playSound, getSample, getPlot;
private JLabel chordInfo;
private JPanel basicFunctions;
public Window()
{
init();
}
private void init()
{
setVisible(true);
setSize(new Dimension(1000,500));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
basicFunctions = new JPanel();
FlowLayout basicLayout = new FlowLayout();
basicFunctions.setLayout(basicLayout);
showChord = new JButton("Akord");
playSound = new JButton("Odtwórz");
getSample = new JButton("Pobierz dźwięk");
getPlot = new JButton("Pobierz wykres");
showChord.addActionListener(this);
playSound.addActionListener(this);
getSample.addActionListener(this);
getPlot.addActionListener(this);
basicFunctions.add(showChord);
basicFunctions.add(playSound);
basicFunctions.add(getSample);
basicFunctions.add(getPlot);
add(basicFunctions);
Sliders param = new Sliders();
}
public static void main(String[] args)
{
Window frame = new Window();
}
//Action Listener
#Override
public void actionPerformed(ActionEvent a)
{
Object event = a.getSource();
if(event == showChord)
{
}
else if(event == playSound)
{
}
else if(event == getSample)
{
}
else if(event == getPlot)
{
}
}
}
import java.awt.*;
import javax.swing.event.ChangeEvent;
import javax.swing.*;
import javax.swing.event.ChangeListener;
public class Sliders extends Window implements ChangeListener
{
private JPanel sliders, sliderSub;
private JTextField accAmplitude, accFrequency, accPhase;
private JSlider amplitude, frequency, phase;
private double amplitudeValue, frequencyValue, phaseValue;
public Sliders()
{
sliders = new JPanel();
sliders.setLayout(new FlowLayout());
amplitude = new JSlider(0,100,0);
amplitude.setMajorTickSpacing(10);
amplitude.setMinorTickSpacing(5);
amplitude.setPaintTicks(true);
amplitude.setPaintLabels(true);
frequency = new JSlider(0,10,0);
frequency.setMajorTickSpacing(1);
frequency.setMinorTickSpacing(1/10);
frequency.setPaintTicks(true);
frequency.setPaintLabels(true);
phase = new JSlider(0,1,0);
phase.setMinorTickSpacing(2/10);
phase.setPaintTicks(true);
phase.setPaintLabels(true);
accAmplitude = new JTextField();
accFrequency = new JTextField();
accPhase = new JTextField();
sliders.add(amplitude, BorderLayout.NORTH);
sliders.add(frequency, BorderLayout.CENTER);
sliders.add(phase, BorderLayout.SOUTH);
add(sliders);
}
#Override
public void stateChanged(ChangeEvent arg0)
{
}
}
I've done this so far, but those text fields just stopped showing sliders values and I don't know why. They are defined in the Parameters class and Window class. Can someone help? Additionally in the future I'd like to make those text fields editable so that you can set slider value by typing it in the text field.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.event.*;
public class Window extends JPanel
{
private JMenuBar mainMenu = new JMenuBar();
private Plot plot = new Plot();
private Parameters param = new Parameters();
private JComboBox chooseChord = new JComboBox();
private JButton playSound = new JButton("Odtwórz");
private JButton getSample = new JButton("Pobierz dźwięk");
private JButton getPlot = new JButton("Pobierz wykres");
private JPanel mainPanel = new JPanel();
private JPanel subPanel = new JPanel();
private JPanel buttonsPanel = new JPanel();
private JPanel slidersPanel = new JPanel();
private JLabel chord = new JLabel("Akord:");
private JTextField aValue = new JTextField();
private JTextField fValue = new JTextField();
private JTextField pValue = new JTextField();
public Window()
{
mainPanel.setLayout(new FlowLayout());
buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.Y_AXIS));
slidersPanel.setLayout(new BorderLayout());
subPanel.setLayout(new BorderLayout());
chooseChord.addItem("A");
chooseChord.addItem("A#");
chooseChord.addItem("Ab");
chooseChord.addItem("B");
chooseChord.addItem("Bb");
chooseChord.addItem("C");
chooseChord.addItem("C#");
chooseChord.addItem("Cb");
chooseChord.addItem("D");
chooseChord.addItem("D#");
chooseChord.addItem("E");
chooseChord.addItem("F");
chooseChord.addItem("F#");
buttonsPanel.add(chord);
buttonsPanel.add(chooseChord);
buttonsPanel.add(Box.createRigidArea(new Dimension(0,10)));
buttonsPanel.add(playSound);
buttonsPanel.add(Box.createRigidArea(new Dimension(0,10)));
buttonsPanel.add(getSample);
buttonsPanel.add(Box.createRigidArea(new Dimension(0,10)));
buttonsPanel.add(getPlot);
buttonsPanel.setBorder(BorderFactory.createTitledBorder("Menu"));
slidersPanel.add(param);
JMenu langMenu = new JMenu("Język");
mainMenu.add(langMenu);
subPanel.add(buttonsPanel, BorderLayout.NORTH);
subPanel.add(slidersPanel, BorderLayout.SOUTH);
mainPanel.add(subPanel);
mainPanel.add(plot);
add(mainPanel);
param.addAmplitudeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent a)
{
double ampValue = param.getAmplitudeValue();
aValue.setText(String.valueOf(ampValue));
}
}
);
param.addFrequencyListener(new ChangeListener()
{
public void stateChanged(ChangeEvent f)
{
double frValue = param.getFrequencyValue();
fValue.setText(String.valueOf(frValue));
}
}
);
param.addPhaseListener(new ChangeListener()
{
public void stateChanged(ChangeEvent p)
{
double phValue = param.getPhaseValue();
pValue.setText(String.valueOf(phValue));
}
}
);
}
public JMenuBar getmainMenu()
{
return mainMenu;
}
private static void GUI()
{
Window mainPanel = new Window();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setJMenuBar(mainPanel.getmainMenu());
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
GUI();
}
}
);
}
}
class Parameters extends JPanel
{
private JPanel pane = new JPanel();
private JPanel ampPanel = new JPanel();
private JPanel frPanel = new JPanel();
private JPanel phPanel = new JPanel();
private JSlider amplitude = new JSlider(0,100,0);
private JSlider frequency = new JSlider(0,10000,0);
private JSlider phase = new JSlider(0,180,0);
private JLabel pLabel = new JLabel("Faza");
private JLabel aLabel = new JLabel("Amplituda (dB)");
private JLabel fLabel = new JLabel("Częstotliwość (Hz)");
private JTextField preciseAmplitude = new JTextField(3);
private JTextField preciseFrequency = new JTextField(4);
private JTextField precisePhase = new JTextField(3);
public Parameters()
{
preciseAmplitude.setEditable(true);
preciseFrequency.setEditable(true);
precisePhase.setEditable(true);
pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS));
ampPanel.setLayout(new FlowLayout());
frPanel.setLayout(new FlowLayout());
phPanel.setLayout(new FlowLayout());
amplitude.setMajorTickSpacing(10);
amplitude.setMinorTickSpacing(5);
amplitude.setPaintTicks(true);
amplitude.setPaintLabels(true);
frequency.setMajorTickSpacing(2000);
frequency.setMinorTickSpacing(100);
frequency.setPaintTicks(true);
frequency.setPaintLabels(true);
phase.setMajorTickSpacing(2/10);
phase.setPaintTicks(true);
phase.setPaintLabels(true);
setBorder(BorderFactory.createTitledBorder("Parametry fali"));
ampPanel.add(aLabel);
ampPanel.add(preciseAmplitude);
pane.add(ampPanel);
pane.add(Box.createRigidArea(new Dimension(0,5)));
pane.add(amplitude);
pane.add(Box.createRigidArea(new Dimension(0,10)));
frPanel.add(fLabel);
frPanel.add(preciseFrequency);
pane.add(frPanel);
pane.add(Box.createRigidArea(new Dimension(0,5)));
pane.add(frequency);
pane.add(Box.createRigidArea(new Dimension(0,10)));
phPanel.add(pLabel);
phPanel.add(precisePhase);
pane.add(phPanel);
pane.add(Box.createRigidArea(new Dimension(0,5)));
pane.add(phase);
pane.add(Box.createRigidArea(new Dimension(0,10)));
add(pane);
}
public int getAmplitudeValue()
{
return amplitude.getValue();
}
public int getFrequencyValue()
{
return frequency.getValue();
}
public int getPhaseValue()
{
return phase.getValue();
}
public void addAmplitudeListener(ChangeListener ampListener)
{
amplitude.addChangeListener(ampListener);
}
public void addFrequencyListener(ChangeListener frListener)
{
frequency.addChangeListener(frListener);
}
public void addPhaseListener(ChangeListener phListener)
{
phase.addChangeListener(phListener);
}
}
class Plot extends JPanel
{
private JPanel componentWave = new JPanel();
private JPanel netWave = new JPanel();
private JLabel componentLabel = new JLabel("Fale składowe");
private JLabel netLabel = new JLabel("Fala wypadkowa");
private JLabel wave = new JLabel("Wybierz falę składową");
private JPanel labels = new JPanel();
private JComboBox chooseWave = new JComboBox();
public Plot()
{
labels.setLayout(new BoxLayout(labels, BoxLayout.PAGE_AXIS));
componentWave.setBackground(new Color(255,255,255));
netWave.setBackground(new Color(255,255,255));
componentWave.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
netWave.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
componentWave.setPreferredSize(new Dimension(400,200));
netWave.setPreferredSize(new Dimension(400,200));
labels.add(wave);
labels.add(Box.createRigidArea(new Dimension(0,10)));
labels.add(chooseWave);
labels.add(componentLabel);
labels.add(componentWave);
labels.add(Box.createRigidArea(new Dimension(0,20)));
labels.add(netLabel);
labels.add(netWave);
add(labels);
}
}
Window is intended to be a 'main GUI class' and Sliders is supposed to inherit (?) from it.
Nope: this is a misuse of inheritance and will only lead to problems since the Windows instance that Sliders inherently is, is completely distinct from the displayed Windows instance. What you need to do is to pass references.
For example, the following code uses outside classes for the JButton and JMenuItem Actions (Actions are like ActionListeners on steroids), and uses a class that holds a JSlider that allows itside classes to attach listeners to the slider.
import java.awt.Component;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Foo extends JPanel {
private static final long serialVersionUID = 1L;
private Action helloAction = new HelloAction("Hello", KeyEvent.VK_H);
private Action exitAction = new ExitAction("Exit", KeyEvent.VK_X);
private JMenuBar menuBar = new JMenuBar();
private JTextField sliderValueField = new JTextField(10);
private Bar bar = new Bar();
public Foo() {
sliderValueField.setEditable(false);
sliderValueField.setFocusable(false);
add(new JButton(helloAction));
add(new JButton(exitAction));
add(new JLabel("Slider Value: "));
add(sliderValueField);
add(bar);
JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic(KeyEvent.VK_F);
fileMenu.add(new JMenuItem(exitAction));
fileMenu.add(new JMenuItem(helloAction));
menuBar.add(fileMenu);
bar.addSliderListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
int sliderValue = bar.getSliderValue();
sliderValueField.setText(String.valueOf(sliderValue));
}
});
}
public JMenuBar getJMenuBar() {
return menuBar;
}
private static void createAndShowGui() {
Foo mainPanel = new Foo();
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setJMenuBar(mainPanel.getJMenuBar());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class HelloAction extends AbstractAction {
public HelloAction(String name, int mnemonic) {
super(name); // sets name property and gives button its title
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null, "Hello!");
}
}
class ExitAction extends AbstractAction {
private static final long serialVersionUID = 1L;
public ExitAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
Component component = (Component) e.getSource();
Window win = SwingUtilities.getWindowAncestor(component);
if (win == null) {
// if no window, then a JMenuItem held in a JPopupMenu
JPopupMenu popup = (JPopupMenu) component.getParent();
component = popup.getInvoker();
win = SwingUtilities.getWindowAncestor(component);
}
win.dispose();
}
}
class Bar extends JPanel {
private JSlider slider = new JSlider(0, 100, 50);
public Bar() {
slider.setPaintLabels(true);
slider.setPaintTicks(true);
slider.setMajorTickSpacing(20);
slider.setMinorTickSpacing(5);
slider.setSnapToTicks(true);
setBorder(BorderFactory.createTitledBorder("Slider Panel"));
add(slider);
}
public int getSliderValue() {
return slider.getValue();
}
// one way to let outside classes listen for changes
public void addSliderListener(ChangeListener listener) {
slider.addChangeListener(listener);
}
}
You ask about decimal labels, and yes this can be done but requires use of a label table. For example,
JSlider slider = new JSlider(0, 100, 50);
slider.setPaintLabels(true);
slider.setPaintTicks(true);
slider.setMajorTickSpacing(20);
slider.setMinorTickSpacing(2);
Dictionary<Integer, JLabel> labels = new Hashtable<>();
for (int i = 0; i <= 100; i += 20) {
labels.put(i, new JLabel(String.format("%.1f", i / 200.0)));
}
slider.setLabelTable(labels);
Which displays as:
You would also have to translate the value back from int to its corresponding floating point number.
I'm building a Java Virtual Pet game, currently the menu panel is working fine, buttons are loading and operating, but when I click my new game button which is supposed to launch into the GamePanel Panel I get a nullpointerException.
This is the main class which builds the original frame and Jpanel to switch from.
public class MainFrame extends JPanel {
public JPanel mainPanel;
public CardLayout cl;
private final GamePanel gamePanel;
private final MenuPanel menuPanel;
/**
* Constructs the main panel to be used to switch between panels.
*
*/
public MainFrame() {
// creates a new panel to add panels to.
cl = new CardLayout();
// panel to be used as a main switch.
mainPanel = new JPanel();
Dimension size = getPreferredSize();
size.width = 600;
size.height = 600;
setPreferredSize(size);
setBackground(Color.BLACK);
add(mainPanel);
gamePanel = new GamePanel();
menuPanel = new MenuPanel();
// sets layout
mainPanel.setLayout(cl);
mainPanel.add(menuPanel, "menuPanel");
mainPanel.add(gamePanel, "gamePanel");
}
public void changePanel(String name) {
cl.show(mainPanel, name);
}
/**
* Main frame used by the game.
*
* #param args
*/
public static void main(String[] args) {
MainFrame game = new MainFrame();
JFrame frame = new JFrame("Main Window");
frame.add(game);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
}
}
This is the code from my MenuPanel class which should be accessing the changePanel() method.
public class MenuPanel extends JPanel {
MainFrame mf;
public MenuPanel() {
this.mf = mf;
Dimension size = getPreferredSize();
size.width = 600;
size.height = 600;
setPreferredSize(size);
ImageIcon menuIcon = new ImageIcon("C:\\Programming\\NetBeansProjects\\PDCMain\\src\\Data\\the_menu_title2.png");
JLabel menuLbl = new JLabel();
menuLbl.setIcon(menuIcon);
JButton newGameBtn = new JButton("New Game");
JButton loadGameBtn = new JButton("Load Game");
JButton helpBtn = new JButton("Instructions");
JButton exitBtn = new JButton("Exit");
newGameBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("New Game");
mf.changePanel("gamePanel");
}
});
loadGameBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
}
});
helpBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
showHelp();
}
});
exitBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
setLayout(new GridBagLayout());
GridBagConstraints gc = new GridBagConstraints();
gc.weightx = 0;
gc.weighty = 0.1;
gc.gridx = 0;
gc.gridy = 1;
add(menuLbl, gc);
gc.gridx = 0;
gc.gridy = 2;
add(newGameBtn, gc);
gc.gridx = 0;
gc.gridy = 3;
add(loadGameBtn, gc);
gc.gridx = 0;
gc.gridy = 4;
add(helpBtn, gc);
gc.gridx = 0;
gc.gridy = 5;
add(exitBtn, gc);
}
public void showHelp(){
String[] help = new String[100];
try {
BufferedReader br = new BufferedReader(new FileReader("instruct.txt"));
String line = "";
int i = 0;
while((line = br.readLine()) != null) {
help[i] = line;
i++;
}
JOptionPane.showMessageDialog(null, help);
} catch(IOException ex) {
System.err.println("IOException Error: " + ex.getMessage());
}
}
and here is the game panel
public class GamePanel extends JPanel{
private ButtonsPanel buttonsPanel;
private GraphicsPanel graphicsPanel;
private final JPanel gamePanel;
public GamePanel(){
super();
this._initGUI();
gamePanel = new JPanel();
Dimension size = getPreferredSize();
size.width = 600;
size.height = 600;
setPreferredSize(size);
setBackground(Color.RED);
}
private void _initGUI(){
this.buttonsPanel = new ButtonsPanel();
this.graphicsPanel = new GraphicsPanel();
this.setLayout(new BorderLayout());
this.add(buttonsPanel, BorderLayout.SOUTH);
this.add(graphicsPanel, BorderLayout.CENTER);
}
public void run(){
graphicsPanel.run();
}
}
This is my first attempt at building a GUI from scratch and using cardlayout. I can't see where it would be assigning a null value as the panel is declared in the main panel used for the switching, any ideas?
Take a second to look at this piece of code...
public static class MenuPanel extends JPanel {
MainFrame mf;
public MenuPanel() {
this.mf = mf;
Basically, you are assigning (this) mf to this.mf, but since mf is already null, this.mf will remain null...
You should be passing a reference of MainFrame to your MenuPanel
Now, because I hate passing around references of UI components to other parts of the program, which should have no idea about the rest of the UI and don't direct control over them, I would advice against passing MainFrame blinding like this.
Instead, create a interface which provides the functionality you expect that MenuPanel should be allowed to perform (newGame, loadGame, showInstructions, exit) for example and allow the implementation of this interface (probably the MainFrame) to deal with it
You would then pass the instance of this interface to MenuPanel...This limits the exposure of classes to other classes which don't need those classes functionality and decouples your code so you can pass any old instance of the interface to the class without having to rewrite whole sections of your code...
Updated with a basic concept
Start with some kind game controller interface, for example...
public interface GameController {
public void newGame();
public void loadGame();
public void showInstructions();
public void exit();
}
This describes the actions that can take against the implementation of this interface.
Use MainFrame and implement the GameController...
public class MainFrame extends JPanel implements GameController {
//...
public void newGame() {
}
public void loadGame() {
}
public void showInstructions() {
}
public void exit() {
}
Change MenuPane to require an instance of GameController when it's constructed...
public class MenuPanel extends JPanel {
private GameController controller;
public MenuPanel(GameController gameController) {
this.controller = gameController;
//...
Now, when you handle the user interaction, you would pass the request to the controller....
newGameBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("New Game");
controller.newGame();
}
});
In this way, the MenuPanel doesn't know how a new game is created, it just knows that it will be taken care of...
Now, you will need to update the newGame method in MainFrame to do something, for example...
public void newGame() {
// Setup the new game...
cl.show(mainPanel, "gamePanel");
}
This places all the responsibility squarely with the implementation of the GameController to make decisions about how certain actions should take place, decouples the process, so if you change the implementation of the GameController to some other class, you don't need to worry about updating the MenuPanel, cause it's only interested in taking to the GameController...nice ;)
For architecture and design purposes I would like to design my GUI with a class for each card in a Java Swing CardLayout. and then have a mainapp that builds the GUI. I am having trouble doing this right now.
I would like to example have a class for the main menu with all the button locations etc. and then just instantiate that card and add it to the layout in another class. Does anyone know how to achieve this?
Perhaps you want to give your class that uses the CardLayout a public loadCard method, something like
public void loadCard(JComponent component, String key) {
cardHolderPanel.add(component, key);
}
where cardHolderPanel is the container that holds the cards.
Since your creating classes to act as cards, consider having them all extend from a base abstract class or an interface that has a method that allows this class to hold its own key String. Either that or simply use the JComponent name property to have a component hold its own key String, one that can easily be obtained via getName().
For a more detailed answer, you may need to give us more details on your current application and its structure.
very simple example that held Swing Objects generated from different Java Classes
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class OnTheFlyImageTest extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel cardPanel;
private CardLayout cardLayout;
public OnTheFlyImageTest() {
JPanel cp = new JPanel(new BorderLayout());
cp.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
cardLayout = new CardLayout(5, 5);
cardPanel = new JPanel(cardLayout);
cp.add(cardPanel);
for (int i = 0; i < 100; i++) {// Create random panels for testing.
String name = "ImagePanel" + (i + 1);
String image = (i & 1) == 0 ? "foo.gif" : "bar.gif";
ImagePanel imgPanel = new ImagePanel(name, image);
cardPanel.add(imgPanel, name);
cardLayout.addLayoutComponent(imgPanel, name);
}
JPanel buttonPanel = new JPanel(new GridLayout(1, 2, 5, 5));
JButton prevButton = new JButton("< Previous");
prevButton.setActionCommand("Previous");
prevButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.previous(cardPanel);
}
});
buttonPanel.add(prevButton);
JButton nextButton = new JButton("Next >");
nextButton.setActionCommand("Next");
nextButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.next(cardPanel);
}
});
buttonPanel.add(nextButton);
JPanel temp = new JPanel(new BorderLayout());
temp.add(buttonPanel, BorderLayout.LINE_END);
cp.add(temp, BorderLayout.SOUTH);
setContentPane(cp);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("Test");
pack();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new OnTheFlyImageTest().setVisible(true);
}
});
}
}
class ImagePanel extends JPanel {
private static final long serialVersionUID = 1L;
private String imgString;
private JLabel imgLabel;
public ImagePanel(String name, String imgString) {
setName(name);
this.imgString = imgString;
setLayout(new BorderLayout());
// Ensure size is correct even before any image is loaded.
setPreferredSize(new Dimension(640, 480));
}
#Override
public void setVisible(boolean visible) {
if (visible) {
System.err.println(getName() + ": Loading and adding image");
ImageIcon icon = new ImageIcon(imgString);
imgLabel = new JLabel(icon);
add(imgLabel);
}
super.setVisible(visible);
if (!visible) { // Do after super.setVisible() so image doesn't "disappear".
System.err.println(getName() + ": Removing image");
if (imgLabel != null) { // Before display, this will be null
remove(imgLabel);
imgLabel = null; // Hint to GC that component/image can be collected.
}
}
}
}
I have a JFrame which contains 3 JPanels. I want to pass the JTextField value of one panel to other. Each panel is shown using JTabbedPane. I am getting null when i access the value of other text field. How can i access?
You don't show any code, and so it's impossible to know why you're getting "null" values. Two possible solutions if you want all three JPanels to hold JTextFields with the same content:
Put the shared JTextField outside of the JPanels held by the JTabbedPane and instead in a JPanel that holds the JTabbedPane, so that the field is always visible no matter what tab is displayed, or
Use several JTextFields but have them share the same Document or "model".
e.g.,
import java.awt.Dimension;
import javax.swing.*;
import javax.swing.text.PlainDocument;
public class SharedField extends JTabbedPane {
private static final int TAB_COUNT = 5;
private static final int MY_WIDTH = 600;
private static final int MY_HEIGHT = 300;
PlainDocument doc = new PlainDocument();
public SharedField() {
for (int i = 0; i < TAB_COUNT; i++) {
JTextField tField = new JTextField(10);
tField.setDocument(doc);
JPanel panel = new JPanel();
panel.add(tField);
add("Panel " + i, panel);
// to demonstrate some of the JTextFields acting like
// a label
if (i % 2 == 1) { // if i is odd
tField.setEditable(false);
tField.setBorder(null);
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(MY_WIDTH, MY_HEIGHT);
}
private static void createAndShowUI() {
JFrame frame = new JFrame("SharedField");
frame.getContentPane().add(new SharedField());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
Edit 1
I see that you've cross-posted this on java-forums.org/ where you show some of your code:
pacage Demotool;
Class:MainFrame
This is the actionPerformed code of first panel
both str and scrTxt is (public static)
public void actionPerformed(ActionEvent e)
{
String act=e.getActionCommand();
if(act.equals("ADD"))
{
str=scrnTxt.getText();
System.out.println("Hi :"+str);
Demotool.DemoTool.jtp.setSelectedIndex(1);
}
}
using the belove code i tried to access the data but I am getting null String:
System.out.println("Hello:"+Demotool.MainFrame.str);
Problems:
Don't use static variables or methods unless you have a good reason to do so. Here you don't.
You're may be trying to access the MainFrame.str variable before anything has been put into it, making it null, or you are creating a new MainFrame object in your second class, one that isn't displayed, and thus one whose str variable is empty or null -- hard to say.
Either way, this design is not good. You're better off showing us a small demo program that shows your problem with code that compiles and runs, an sscce, so we can play with and modify your code and better be able to show you a decent solution.
One such decent solution is to add a DocumentListener to the JTextField so that changes to the text held by the JTextField are "pushed" into the observers that are listening for changes (your other classes).
For example, using DocumentListeners:
import java.awt.Dimension;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
public class SharedField2 extends JTabbedPane {
private static final int LABEL_PANEL_COUNT = 4;
private static final int MY_WIDTH = 600;
private static final int MY_HEIGHT = 300;
public SharedField2() {
TextFieldPanel tfPanel = new TextFieldPanel();
LabelPanel[] labelPanels = new LabelPanel[LABEL_PANEL_COUNT];
add("TextFieldPanel", tfPanel);
for (int i = 0; i < labelPanels.length; i++) {
labelPanels[i] = new LabelPanel();
// add each label panel's listener to the text field
tfPanel.addDocumentListenerToField(labelPanels[i].getDocumentListener());
add("Label Panel " + i, labelPanels[i]);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(MY_WIDTH, MY_HEIGHT);
}
private static void createAndShowUI() {
JFrame frame = new JFrame("SharedField2");
frame.getContentPane().add(new SharedField2());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class TextFieldPanel extends JPanel {
private JTextField tField = new JTextField(10);
public TextFieldPanel() {
add(tField);
}
public void addDocumentListenerToField(DocumentListener listener) {
tField.getDocument().addDocumentListener(listener);
}
}
class LabelPanel extends JPanel {
private DocumentListener myListener;
private JLabel label = new JLabel();
public LabelPanel() {
add(label);
myListener = new DocumentListener() {
#Override
public void changedUpdate(DocumentEvent e) {
updateLabel(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
updateLabel(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
updateLabel(e);
}
private void updateLabel(DocumentEvent e) {
try {
label.setText(e.getDocument().getText(0,
e.getDocument().getLength()));
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
};
}
public DocumentListener getDocumentListener() {
return myListener;
}
}
One simple solution will be making JTextField global so all panel can access it.
Make sure all your panel can access JTextField that is textField is globally accessible.
Following code demonstrate this:
JTextField textField = new JTextField(25);
JLabel labelForPanel2 = new JLabel(),labelForPanel3 = new JLabel();
private void panelDemo() {
JFrame frame = new JFrame();
frame.setSize(400, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
JPanel panel3 = new JPanel();
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.addTab("Tab 1", panel1);
tabbedPane.addTab("Tab 2", panel2);
tabbedPane.addTab("Tab 3", panel3);
panel1.add(textField);
panel2.add(labelForPanel2);
panel3.add(labelForPanel3);
textField.addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
labelForPanel2.setText(textField.getText());
labelForPanel3.setText(textField.getText());
}
});
frame.add(tabbedPane);
frame.setVisible(true);
}
I don't know what exactly are you going to achieve, but maybe try data binding?
Take a look at BetterBeansBinding library.
I'm working on a downloader which looks like this at the moment:
The JFrame uses a BorderLayout.
In the NORTH, I have a JPanel(FlowLayout). In the SOUTH there is also a JPanel(FlowLayout), in the WEST I just have a JTextArea (in a JScrollPane). This is all shown correctly. However, in the EAST I currently have a JPanel(GridLayout(10, 1)).
I want to show up to 10 JProgressBars in the EAST section which are added and removed from the panel dynamically. The problem is, I can not get them to look like I want to them to look: I want the JProgressBars' width to fill up the entire EAST section because 1) This gives the app a more symmetrical look and 2) The ProgressBars may contain long strings that don't fit at the moment. I've tried putting the JPanel that contains the GridLayout(10, 1) in a flowlayout and then put that flowlayout in the EAST section, but that didn't work either.
My code (SSCCE) is currently as follows:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
new DownloadFrame();
}
private static class DownloadFrame extends JFrame {
private JButton downloadButton;
private JTextField threadIdTextField;
private JTextArea downloadStatusTextArea;
private JScrollPane scrollPane;
private JTextField downloadLocationTextField;
private JButton downloadLocationButton;
private JPanel North;
private JPanel South;
private JPanel ProgressBarPanel;
private Map<String, JProgressBar> progressBarMap;
public DownloadFrame() {
InitComponents();
InitLayout();
AddComponents();
AddActionListeners();
setVisible(true);
setSize(700, 300);
}
private void InitComponents() {
downloadButton = new JButton("Dowload");
threadIdTextField = new JTextField(6);
downloadStatusTextArea = new JTextArea(10, 30);
scrollPane = new JScrollPane(downloadStatusTextArea, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
downloadLocationTextField = new JTextField(40);
downloadLocationButton = new JButton("...");
North = new JPanel();
South = new JPanel();
ProgressBarPanel = new JPanel();
progressBarMap = new HashMap<String, JProgressBar>();
}
private void InitLayout() {
North.setLayout(new FlowLayout());
South.setLayout(new FlowLayout());
ProgressBarPanel.setLayout(new GridLayout(10, 1));
}
private void AddComponents() {
North.add(threadIdTextField);
North.add(downloadButton);
add(North, BorderLayout.NORTH);
add(ProgressBarPanel, BorderLayout.EAST);
South.add(downloadLocationTextField);
South.add(downloadLocationButton);
add(South, BorderLayout.SOUTH);
add(scrollPane, BorderLayout.WEST);
}
private void AddActionListeners() {
downloadButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addNewProgessBar(threadIdTextField.getText());
}
});
}
public void addNewProgessBar(String threadId) {
JProgressBar progressBar = new JProgressBar();
progressBar.setStringPainted(true);
progressBarMap.put(threadId, progressBar);
drawProgessBars();
}
void drawProgessBars() {
ProgressBarPanel.removeAll();
for (JProgressBar progressBar : progressBarMap.values()) {
ProgressBarPanel.add(progressBar);
}
validate();
repaint();
}
}
}
Thanks in advance.
EDIT
Easiest solution: change
add(ProgressBarPanel, BorderLayout.EAST);
to
add(ProgressBarPanel, BorderLayout.CENTER);
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
new DownloadFrame();
}
private static class DownloadFrame extends JFrame {
private JButton downloadButton;
private JTextField threadIdTextField;
private JTextArea downloadStatusTextArea;
private JScrollPane scrollPane;
private JTextField downloadLocationTextField;
private JButton downloadLocationButton;
private JPanel North;
private JPanel South;
private JPanel ProgressBarPanel;
private Map<String, JProgressBar> progressBarMap;
public DownloadFrame() {
InitComponents();
AddComponents();
AddActionListeners();
pack();
setVisible(true);
//setSize(700, 300);
}
private void InitComponents() {
setLayout(new BorderLayout());
downloadButton = new JButton("Dowload");
threadIdTextField = new JTextField(6);
downloadStatusTextArea = new JTextArea(10, 30);
scrollPane = new JScrollPane(downloadStatusTextArea, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
downloadLocationTextField = new JTextField(40);
downloadLocationButton = new JButton("...");
North = new JPanel(new FlowLayout());
South = new JPanel(new FlowLayout());
ProgressBarPanel = new JPanel(new GridLayout(0, 1));
ProgressBarPanel.setBorder(new LineBorder(Color.black));
ProgressBarPanel.setPreferredSize(new Dimension(300,20));
progressBarMap = new HashMap<String, JProgressBar>();
}
private void AddComponents() {
North.add(threadIdTextField);
North.add(downloadButton);
add(North, BorderLayout.NORTH);
add(ProgressBarPanel, BorderLayout.EAST);
South.add(downloadLocationTextField);
South.add(downloadLocationButton);
add(South, BorderLayout.SOUTH);
add(scrollPane, BorderLayout.WEST);
}
private void AddActionListeners() {
downloadButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addNewProgessBar(threadIdTextField.getText());
}
});
}
public void addNewProgessBar(String threadId) {
JProgressBar progressBar = new JProgressBar();
progressBar.setStringPainted(true);
progressBarMap.put(threadId, progressBar);
drawProgessBars();
}
void drawProgessBars() {
ProgressBarPanel.removeAll();
for (JProgressBar progressBar : progressBarMap.values()) {
ProgressBarPanel.add(progressBar);
}
validate();
repaint();
}
}
}
well. that possible, but in your example CENTER area occupated some Rectangle, its hard to reduce/remove CENTER area to the zero Size
to the North JPanel (BorderLayout) place another JPanel and put it to the EAST (with LayoutManager would be GridLayout(1,2,10,10)) and put here two JComponents JTextField - threadIdTextField and JButton - downloadButton, there you are needed setPreferredSize 1) for JComponents (correct way) or 2) for whole JPanel (possible way too)
JScrollPane with JTextArea must be placed to the CENTER area
JPanel with JProgressBars place to EAST, but again set same PreferredSize as for JPanel with JTextField and JButton from the NORTH
SOUTH JPanel remains without changes
Please post a compilable runnable small program for the quickest best help, an SSCCE.
Suggestions include using GridLayout(0, 1) (variable number of rows, one column), or display the JProgressBars in a JList that uses a custom renderer that extends JProgressBar.
Edit 1:
I know that Andrew has already posted the accepted answer (and 1+ for an excellent answer), but I just wanted to demonstrate that this can be done readily with a JList, something like so:
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.util.Random;
import javax.swing.*;
public class EastProgressList extends JPanel {
private DefaultListModel myListModel = new DefaultListModel();
private JList myList = new JList(myListModel);
private JTextField downloadUrlField = new JTextField(10);
public EastProgressList() {
JButton downLoadBtn = new JButton("Download");
downLoadBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
downloadAction();
}
});
JPanel northPanel = new JPanel();
northPanel.add(new JLabel("File to Download:"));
northPanel.add(downloadUrlField);
northPanel.add(Box.createHorizontalStrut(15));
northPanel.add(downLoadBtn);
myList.setCellRenderer(new ProgressBarCellRenderer());
JScrollPane eastSPane = new JScrollPane(myList);
eastSPane.setPreferredSize(new Dimension(200, 100));
setLayout(new BorderLayout());
add(new JScrollPane(new JTextArea(20, 30)), BorderLayout.CENTER);
add(northPanel, BorderLayout.NORTH);
add(eastSPane, BorderLayout.EAST);
}
private void downloadAction() {
String downloadUrl = downloadUrlField.getText();
final MyData myData = new MyData(downloadUrl);
myListModel.addElement(myData);
myData.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(MyData.VALUE)) {
myList.repaint();
if (myData.getValue() >= 100) {
myListModel.removeElement(myData);
}
}
}
});
}
private class ProgressBarCellRenderer extends JProgressBar implements ListCellRenderer {
protected ProgressBarCellRenderer() {
setBorder(BorderFactory.createLineBorder(Color.blue));
}
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
//setText(value.toString());
MyData myData = (MyData)value;
setValue(myData.getValue());
setString(myData.getText());
setStringPainted(true);
return this;
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("EastProgressList");
frame.getContentPane().add(new EastProgressList());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class MyData {
public static final int TIMER_DELAY = 300;
public static final String VALUE = "value";
protected static final int MAX_DELTA_VALUE = 5;
private String text;
private int value = 0;
private Random random = new Random();
private PropertyChangeSupport pcSupport = new PropertyChangeSupport(this);
public MyData(String text) {
this.text = text;
new Timer(TIMER_DELAY, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int deltaValue = random.nextInt(MAX_DELTA_VALUE);
int newValue = value + deltaValue;
if (newValue >= 100) {
newValue = 100;
((Timer)e.getSource()).stop();
}
setValue(newValue);
}
}).start();
}
public String getText() {
return text;
}
public int getValue() {
return value;
}
public void setValue(int value) {
int oldValue = this.value;
this.value = value;
PropertyChangeEvent pcEvent = new PropertyChangeEvent(this, VALUE, oldValue, value);
pcSupport.firePropertyChange(pcEvent);
}
public void addPropertyChangeListener(PropertyChangeListener pcListener) {
pcSupport.addPropertyChangeListener(pcListener);
}
}
This results in a GUI looking like so: