I am trying to have a dialog showing a progress bar with a label. I have set my label to be center aligned with JLabel.Center and the use of a box.
Initially, the label is shown as centered, which is what I am looking for. However, when changing the label's text (by using the code "creatingQueriesLabel.setText(text)", the label is now displayed as left aligned.
Any help will be greatly appreciated! Here is my code.
JFrame frame = new JFrame("Creating queries ...");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Box box = Box.createVerticalBox();
JPanel panel = new JPanel();
panel.setLayout(null);
creatingQueriesLabel = new JLabel("Initializing ... ");
creatingQueriesLabel.setSize(480, 160);
creatingQueriesLabel.setLocation(10, 10);
creatingQueriesLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
box.setLocation(0, 10);
box.setSize(480, 160);
box.add(creatingQueriesLabel);
progressBar = new JProgressBar();
progressBar.setSize(480, 50);
progressBar.setValue(0);
progressBar.setStringPainted(true);
progressBar.setLocation(creatingQueriesLabel.getX(),
creatingQueriesLabel.getY() + creatingQueriesLabel.getHeight());
panel.add(progressBar);
frame.add(box);
frame.add(panel);
// Display the window.
frame.pack();
frame.setSize(520, 280);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
/**
* Invoked when task's progress property changes.
*/
public void propertyChange(PropertyChangeEvent evt)
{
if ("progress" == evt.getPropertyName())
{
int progress = (Integer) evt.getNewValue();
progressBar.setValue(progress);
}
if ("currentQueryText" == evt.getPropertyName())
{
String text = (String) evt.getNewValue();
creatingQueriesLabel.setText(text);
}
}
Problems:
You're setting sizes and positions using absolute positioning -- don't as that's not how Swing works and this will lead to GUI's that are very hard to maintain and enhance, as you're finding out.
Use the SwingConstants.CENTER int when constructing the JLabel so that its text is centered
Add it to a container that uses BorderLayout, probably in the BorderLayout.PAGE_START position.
Unrelated problem -- don't do this: if ("currentQueryText" == evt.getPropertyName()) {. This tests for reference equality which is not what you want to test for. Use the equals method instead.
This GUI looks like it should be a dialog window, a temporary window that is displaying information not shown in the main parent window (the JFrame window), and so it should be displayed in a JDialog, not a JFrame.
For example:
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
#SuppressWarnings("serial")
public class CreatingSpeciesPanel extends JPanel {
public static final String INITIALIZING = "Initializing...";
public static final String DONE = "DONE!";
private static final int PREF_W = 480;
private static final int PREF_H = 150;
private static final int GAP = 20;
private static final float TITLE_SIZE = 24f;
private JLabel title = new JLabel(INITIALIZING, SwingConstants.CENTER);
private JProgressBar progressBar = new JProgressBar();
public CreatingSpeciesPanel() {
title.setFont(title.getFont().deriveFont(Font.BOLD, TITLE_SIZE));
progressBar.setValue(0);
progressBar.setStringPainted(true);
JPanel centerPanel = new JPanel(new BorderLayout());
centerPanel.add(progressBar, BorderLayout.PAGE_END);
setLayout(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
add(title, BorderLayout.PAGE_START);
add(centerPanel, BorderLayout.CENTER);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
public void setValue(int value) {
progressBar.setValue(value);
}
public void setTitleLabelText(String text) {
title.setText(text);
}
private static void createAndShowGui() {
final CreatingSpeciesPanel creatingSpeciesPanel = new CreatingSpeciesPanel();
final JFrame mainFrame = new JFrame("Main Frame");
JButton createSpeciesBtn = new JButton(new AbstractAction("Create Species") {
#Override
public void actionPerformed(ActionEvent e) {
creatingSpeciesPanel.setTitleLabelText(CreatingSpeciesPanel.INITIALIZING);
final JDialog dialog = new JDialog(mainFrame, "Creating Species", ModalityType.APPLICATION_MODAL);
dialog.add(creatingSpeciesPanel);
dialog.pack();
dialog.setLocationRelativeTo(mainFrame);
new Timer(200, new ActionListener() {
private int doneCount = 0;
private int value = 0;
private static final int MAX_DONE_COUNT = 10;
#Override
public void actionPerformed(ActionEvent e) {
if (value < 100) {
value += (int) Math.random() * 5 + 5;
value = Math.min(100, value);
creatingSpeciesPanel.setValue(value);
if (value == 100) {
creatingSpeciesPanel.setTitleLabelText(CreatingSpeciesPanel.DONE);
}
} else {
// let's display the dialog for 2 more seconds
doneCount++;
if (doneCount >= MAX_DONE_COUNT) {
((Timer) e.getSource()).stop();
dialog.setVisible(false);
}
}
}
}).start();
dialog.setVisible(true);
}
});
JPanel panel = new JPanel();
panel.add(createSpeciesBtn);
panel.setPreferredSize(new Dimension(500, 400));
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.getContentPane().add(panel);
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Related
I am trying to create a GUI and in that GUI I have different JLabels with a value. I want to be able to click on a JLabel to edit it in my JTextfield (only have 1) and after I press enter it should leave Editing the JLabel. At the moment if I try to edit a JLabel it will change but when I click on the next one the old one will also still change.
This is my code:
public class GUI {
JFrame frame;
int n1=1;
int n2=1;
int n3=1;
GUI(){
frame=new JFrame();//creating instance of JFrame
JLabel l1=new JLabel(Integer.toString(n1));
JLabel l2=new JLabel(Integer.toString(n2));
JLabel l3=new JLabel(Integer.toString(n3));
JTextField t=new JTextField();
l1.setBounds(40,50,100, 40);
l2.setBounds(40,100,100, 40);
l3.setBounds(40,150,100, 40);
t.setBounds(20,200,100, 40);
frame.add(l1);
frame.add(l2);
frame.add(l3);
frame.add(t);
l1.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
l1.setText(t.getText());
n1=parseInt(t.getText());
}
});
}
});
l2.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
l2.setText(t.getText());
n2=parseInt(t.getText());
}
});
}
});
frame.setSize(400,500);//400 width and 500 height
frame.setLayout(null);//using no layout managers
frame.setVisible(true);//making the frame visible
}
public static void main(String[] args) {
new GUI();
}
}
Thanks in advance.
Don't add action listeners for each click. Clicking on a label should record the state of your UI -- that that label is now being edited, and set up the value in the JTextField. Then enter should transfer the value to the JLabel which was recorded as selected.
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class GUI {
JLabel currentEditLabel = null;
JFrame frame;
int n1 = 1;
int n2 = 1;
int n3 = 1;
GUI() {
frame = new JFrame();//creating instance of JFrame
JLabel l1 = new JLabel(Integer.toString(n1));
JLabel l2 = new JLabel(Integer.toString(n2));
JLabel l3 = new JLabel(Integer.toString(n3));
JTextField t = new JTextField();
l1.setBounds(40, 50, 100, 40);
l2.setBounds(40, 100, 100, 40);
l3.setBounds(40, 150, 100, 40);
t.setBounds(20, 200, 100, 40);
frame.add(l1);
frame.add(l2);
frame.add(l3);
frame.add(t);
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (currentEditLabel != null) {
currentEditLabel.setText(t.getText());
currentEditLabel = null;
}
}
});
addMouseListener(l1, t);
addMouseListener(l2, t);
addMouseListener(l3, t);
frame.setSize(400, 500);//400 width and 500 height
frame.setLayout(null);//using no layout managers
frame.setVisible(true);//making the frame visible
}
private void addMouseListener(JLabel label, JTextField t) {
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
currentEditLabel = (JLabel) e.getComponent();
t.setText(currentEditLabel.getText());
}
});
}
public static void main(String[] args) {
new GUI();
}
}
Figuring out how to set n1, n2, ... is left as an exercise, as is how to indicate in the UI that no label is selected (hint: should you allow input in the JTextField when no label has been selected?)
As #kleopatra says, using no layout manager is not good practice, as if your panel is resized (perhaps your program will be run on a mobile device, for instance) your components may become hidden, See this discussion.
Here's your code using GridLayout, a simple layout manager.
Points to note:
I've removed the absolute positioning and sizing of the components and the frame.
The frame is now resizable, so you can see what the layout manager does as the size changes.
The JFrame is packed before displaying it.
To get a layout which does exactly what you want you can look at GridBagLayout, and also think about nesting containers with simple layout managers.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class GUI {
JLabel currentEditLabel = null;
JFrame frame;
int n1 = 1;
int n2 = 1;
int n3 = 1;
GUI() {
frame = new JFrame();
JLabel l1 = new JLabel(Integer.toString(n1));
JLabel l2 = new JLabel(Integer.toString(n2));
JLabel l3 = new JLabel(Integer.toString(n3));
JTextField t = new JTextField();
GridLayout layout = new GridLayout(4, 1, 10, 10);
frame.setLayout(layout);
frame.add(l1);
frame.add(l2);
frame.add(l3);
frame.add(t);
frame.setResizable(true);
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (currentEditLabel != null) {
currentEditLabel.setText(t.getText());
currentEditLabel = null;
}
}
});
addMouseListener(l1, t);
addMouseListener(l2, t);
addMouseListener(l3, t);
frame.pack();
frame.setVisible(true);//making the frame visible
}
private void addMouseListener(JLabel label, JTextField t) {
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
currentEditLabel = (JLabel) e.getComponent();
t.setText(currentEditLabel.getText());
}
});
}
public static void main(String[] args) {
new GUI();
}
}
I am a noob in java and am trying to make a kind of text adventure game. I want to be able to have the program have some kind of fade ability as it transitions from one layout of the UI to another.
I really have no idea what the best approach to this problem would be or if its really even feasible, but I have so far been trying to have a Jpanel that covers the entire window and uses a timer to fade in to cover everything else in black, or fades out from black to transparency thereby revealing everything underneath.
I have been testing this idea by trying to fade in/out the program at the start just to get the logic for the fade system working before trying to have it as a transition effect. The fade-out kind of works, but I have the program output the alpha level and the screen is turning black at around alpha 50 out of 255 which is confusing me. The fade-in does not work at all.
Here is the code for the fade method:
static int opacityCounter = 0;
public void fadeOut(JPanel frame){
System.out.println(opacityCounter);
opacityCounter = 0;
fadeTimer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
frame.setBackground(new Color(0,0,0,opacityCounter));
opacityCounter++;
gui.window.add(frame);
if(opacityCounter >= 255){
opacityCounter = 255;
fadeTimer.stop();
}
System.out.println(opacityCounter);
}
});
fadeTimer.start();
}
This is the code where the "fadePanel" that covers the window is created and deployed in the method.
fadeScreen = new JPanel();
fadeScreen.setBounds(0,0,800,600);
fadeScreen.setBackground(Color.black);
window.add(fadeScreen);
game.visibilityManager.fadeOut(this.fadeScreen);
To clarify I want something that goes from a UI layout like this:
fades to black, before fading back to a UI that looks like this
This is a minimal reproducible example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Test {
JFrame window;
JPanel fadeScreen, screen1, screen2;
JLabel text1, text2;
Timer fadeTimer;
public Test(){
//Frame Window
window = new JFrame();
window.setSize(800,600);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.getContentPane().setBackground(Color.blue);
//Screen 1
screen1 = new JPanel();
screen1.setBounds(100, 100, 600, 125);
screen1.setBackground(Color.white);
text1 = new JLabel("Text1");
screen1.add(text1);
window.add(screen1);
//Screen 2
screen2 = new JPanel();
screen2.setBounds(100, 400, 600, 125);
screen2.setBackground(Color.white);
text2 = new JLabel("Text2");
screen2.add(text2);
window.add(screen2);
//Cover Panel
fadeScreen = new JPanel();
fadeScreen.setBounds(0,0,800,600);
fadeScreen.setBackground(Color.black);
window.add(fadeScreen);
window.setVisible(true);
//Comment out which method you don't want to use
fadeOut(this.fadeScreen);
//fadeIn(this.fadeScreen);
}
//Fade methods
int opacityCounter = 0;
public void fadeOut(JPanel frame){
System.out.println(opacityCounter);
opacityCounter = 0;
fadeTimer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
frame.setBackground(new Color(0,0,0,opacityCounter));
opacityCounter++;
window.add(frame);
if(opacityCounter >= 255){
opacityCounter = 255;
fadeTimer.stop();
}
System.out.println(opacityCounter);
}
});
fadeTimer.start();
}
public void fadeIn(JPanel frame){
System.out.println(opacityCounter);
opacityCounter = 255;
fadeTimer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
frame.setBackground(new Color(0,0,0,opacityCounter));
opacityCounter--;
window.add(frame);
if(opacityCounter <= 0){
opacityCounter = 0;
fadeTimer.stop();
}
System.out.println(opacityCounter);
}
});
fadeTimer.start();
}
public static void main(String[] args){
new Test();
}
}
Thanks in advance!
I would try these things:
Use the GlassPane of the top-level window and make a section of it darker where you want to cover things up, using a Swing Timer.
Use a CardLayout to swap the underlying components, and make the swap when the covering JPanel is darkest.
Then undarken the covering panel after the swap.
For example (to write more code explanation later):
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Test2 extends JPanel {
public static final String PANEL_1 = "panel 1";
public static final String PANEL_2 = "panel 2";
private CardLayout cardLayout = new CardLayout();
private JPanel cardPanel = new JPanel(cardLayout);
private JPanel panel1 = new JPanel();
private JPanel panel2 = new JPanel();
private Action fadeAction = new FadeAction(cardPanel);
public Test2() {
JLabel label = new JLabel("Panel 1");
label.setFont(label.getFont().deriveFont(Font.BOLD, 100f));
panel1.setLayout(new GridBagLayout());
int gap = 40;
panel1.setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
panel1.add(label);
panel1.setBackground(Color.PINK);
label = new JLabel("Panel 2");
label.setFont(label.getFont().deriveFont(Font.BOLD, 100f));
panel2.setLayout(new GridBagLayout());
panel2.setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
panel2.add(label);
panel2.setBackground(new Color(131, 238, 255));
cardPanel.add(panel1, PANEL_1);
cardPanel.add(panel2, PANEL_2);
JButton startFadeBtn = new JButton(fadeAction);
JPanel buttonPanel = new JPanel();
buttonPanel.add(startFadeBtn);
setLayout(new BorderLayout(5, 5));
add(cardPanel, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.PAGE_END);
}
private static class FadeAction extends AbstractAction {
private static final int FADE_DELAY = 20;
private static final int UNFADE_VALUE = 255;
private JPanel cardPanel;
private JComponent glassPane;
private JPanel coverPanel = new JPanel();
private Timer fadeTimer;
private int counter = 0;
private boolean fade = true;
public FadeAction(JPanel cardPanel) {
super("Start Fade");
putValue(MNEMONIC_KEY, KeyEvent.VK_S);
this.cardPanel = cardPanel;
}
#Override
public void actionPerformed(ActionEvent e) {
counter = 0;
fade = true;
setEnabled(false);
CardLayout cl = (CardLayout) cardPanel.getLayout();
cl.show(cardPanel, PANEL_1);
Window topLevelWindow = SwingUtilities.getWindowAncestor(cardPanel);
glassPane = (JComponent) ((RootPaneContainer) topLevelWindow).getRootPane().getGlassPane();
glassPane.setVisible(true);
glassPane.setLayout(null);
coverPanel.setSize(cardPanel.getSize());
int x = cardPanel.getLocationOnScreen().x - glassPane.getLocationOnScreen().x;
int y = cardPanel.getLocationOnScreen().y - glassPane.getLocationOnScreen().y;
Point coverPanelPoint = new Point(x, y);
coverPanel.setLocation(coverPanelPoint);
glassPane.add(coverPanel);
fadeTimer = new Timer(FADE_DELAY, e2 -> fadeTimerActionPerformed(e2));
fadeTimer.start();
}
private void fadeTimerActionPerformed(ActionEvent e) {
coverPanel.setBackground(new Color(0, 0, 0, counter));
glassPane.repaint();
if (fade) {
counter++;
} else if (counter > 0) {
counter--;
} else {
glassPane.remove(coverPanel);
glassPane.setVisible(false);
setEnabled(true);
((Timer) e.getSource()).stop();
}
if (counter >= UNFADE_VALUE) {
fade = false;
CardLayout cl = (CardLayout) cardPanel.getLayout();
cl.show(cardPanel, PANEL_2);
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Test2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Pay close attention to the Concurrency in Swing and the Laying Out Components Within a Container sections.
This is Hovercraft Full Of Eels' answer. All I did was clean up the GUI creation and demonstrate how this would work with more than two JPanels.
I created five JPanels and displayed them in order with the fade-out/fade-in effect.
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class FadeEffectsTesting {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Fade Effects Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new FadeEffectsTesting().getMainPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
});
}
public static final String[] PANEL_SEQUENCE = { "Panel 1", "Panel 2", "Panel 3", "Panel 4",
"Panel 5" };
private int sequence = 0;
private CardLayout cardLayout;
private FadeAction action;
private JPanel cardPanel, mainPanel;
public FadeEffectsTesting() {
this.mainPanel = new JPanel(new BorderLayout(5, 5));
this.cardPanel = createCardPanel();
this.action = new FadeAction(cardPanel);
mainPanel.add(cardPanel, BorderLayout.CENTER);
mainPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
}
private JPanel createCardPanel() {
cardLayout = new CardLayout();
JPanel panel = new JPanel(cardLayout);
panel.add(createTextPanel(Color.PINK, PANEL_SEQUENCE[0]),
PANEL_SEQUENCE[0]);
panel.add(createTextPanel(new Color(131, 238, 255),
PANEL_SEQUENCE[1]), PANEL_SEQUENCE[1]);
panel.add(createTextPanel(Color.PINK, PANEL_SEQUENCE[2]),
PANEL_SEQUENCE[2]);
panel.add(createTextPanel(new Color(131, 238, 255),
PANEL_SEQUENCE[3]), PANEL_SEQUENCE[3]);
panel.add(createTextPanel(Color.PINK, PANEL_SEQUENCE[4]),
PANEL_SEQUENCE[4]);
return panel;
}
private JPanel createTextPanel(Color color, String text) {
JPanel panel = new JPanel(new FlowLayout());
panel.setBackground(color);
int gap = 40;
panel.setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
JLabel label = new JLabel(text);
label.setFont(label.getFont().deriveFont(Font.BOLD, 72f));
panel.add(label);
return panel;
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
setFadeAction();
JButton startFadeBtn = new JButton(action);
panel.add(startFadeBtn);
return panel;
}
public void setFadeAction() {
action.setFromPanel(PANEL_SEQUENCE[sequence]);
action.setToPanel(PANEL_SEQUENCE[sequence + 1]);
}
public JPanel getMainPanel() {
return mainPanel;
}
public class FadeAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private static final int FADE_DELAY = 20;
private static final int UNFADE_VALUE = 255;
private JPanel cardPanel;
private JComponent glassPane;
private JPanel coverPanel;
private Timer fadeTimer;
private int alphaValue;
private boolean fadeOut;
private String fromPanel, toPanel;
public FadeAction(JPanel cardPanel) {
super("Start Fade");
this.putValue(MNEMONIC_KEY, KeyEvent.VK_S);
this.cardPanel = cardPanel;
this.alphaValue = 0;
this.fadeOut = true;
}
public void setFromPanel(String fromPanel) {
this.fromPanel = fromPanel;
}
public void setToPanel(String toPanel) {
this.toPanel = toPanel;
}
#Override
public void actionPerformed(ActionEvent event) {
alphaValue = 0;
fadeOut = true;
setEnabled(false);
CardLayout cl = (CardLayout) cardPanel.getLayout();
cl.show(cardPanel, fromPanel);
Window topLevelWindow = SwingUtilities.getWindowAncestor(cardPanel);
glassPane = (JComponent) ((RootPaneContainer) topLevelWindow).getRootPane()
.getGlassPane();
glassPane.setLayout(null);
coverPanel = new JPanel();
coverPanel.setSize(cardPanel.getSize());
glassPane.add(coverPanel);
glassPane.setVisible(true);
fadeTimer = new Timer(FADE_DELAY, e2 -> fadeTimerActionPerformed(e2));
fadeTimer.start();
}
private void fadeTimerActionPerformed(ActionEvent event) {
coverPanel.setBackground(new Color(0, 0, 0, alphaValue));
glassPane.repaint();
if (fadeOut) {
alphaValue += 3;
} else if (alphaValue > 0) {
alphaValue -= 3;
} else {
glassPane.remove(coverPanel);
glassPane.setVisible(false);
((Timer) event.getSource()).stop();
if (++sequence < (PANEL_SEQUENCE.length - 1)) {
setFadeAction();
setEnabled(true);
}
}
if (alphaValue >= UNFADE_VALUE) {
fadeOut = false;
CardLayout cl = (CardLayout) cardPanel.getLayout();
cl.show(cardPanel, toPanel);
}
}
}
}
I'm having trouble with the functionality of dispose for my checkerboard (called Checkers) . For each checkerboard that I have, i want to be able to remove it by using dispose before calling another instance of my interface. Here is my progress so far:
Checkers class:
import java.awt.*;
import javax.swing.*;
import java.awt.Color.*;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.util.Random;
public class Checkers extends JFrame
{
Random random = new Random();
private final int ROWS = 2;
private final int COLS = 5;
private final int GAP = 2;
private final int NUM = ROWS * COLS;
private int i;
public int score;
private JPanel pane = new JPanel(new GridLayout(ROWS,COLS, GAP,GAP));
private JPanel pane2 = new JPanel();
private JPanel pane3 = new JPanel();
private JButton btn1 = new JButton("Play A Game");
private JButton btn2 = new JButton("Exit");
private JButton btn3 = new JButton("Easy");
private JButton btn4 = new JButton("Intermediate");
private JButton btn5 = new JButton("Difficult");
private JLabel lbl1 = new JLabel ("score: " + score);
private JLabel gameLost = new JLabel("You lose! You got: " + score + " points");
private MyPanel [] panel = new MyPanel[NUM];
private Color col1 = Color.RED;
private Color col2 = Color.WHITE;
private Color col3 = Color.GREEN;
private Color tempColor;
public Checkers()
{
super("Checkers");
setSize(600,600);
setVisible(true);
setBackground(Color.BLACK);
setBoard();
}
public void setBoard()
// roates colors on the checkbaord
{
for (int i = 0; i < panel.length; i++) {
panel[i] = new MyPanel(this);
pane.add(panel[i]);
if (i % COLS == 0) {
tempColor = col1;
col1 = col2;
col2 = tempColor;}
if (i % 2 == 0) {
panel[i].setBackground(col1);}
else {
panel[i].setBackground(col2);}
}
//pane background colour and the size of this pane.
pane.setBackground(Color.BLACK);
pane.setPreferredSize(new Dimension(300,300));
//pane background colour and size of this pane.
pane2.setBackground(Color.white);
pane2.setPreferredSize(new Dimension(300,300));
//directions on the board where these panes appear.
add(pane, BorderLayout.WEST);
add(pane2, BorderLayout.EAST);
pane2.add(lbl1);
pane2.setLayout(new BoxLayout(pane2, BoxLayout.PAGE_AXIS));
}
public void incrementScore(){
score++;
lbl1.setText("Score: " + Integer.toString(score));
}
//This is the method for resetting via dispose - only works once.
public void restartBoard(){
this.dispose();
new Checkers();
}
}
And also the MyPanel class
public class MyPanel extends JPanel implements MouseListener {
private final Checkers checkers;
public MyPanel(Checkers checkers) {
this.checkers = checkers;
addMouseListener(this);
}
#Override
public void mouseClicked(MouseEvent e) {
setBackground(Color.BLACK);
checkers.incrementScore();
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
EXPECTED RESULT - What i'd like to do is be able to close the current version of interface by using the dispose method, and then opening a new instance of said interface.
ACTUAL RESULT - When opening an interface, then calling dispose method, it will work once. once you try to remove the 2nd interface when creating a 3rd interface, dispose will not function, and I cant see why this is.
Any help is welcome.
For what it's worth, this is an MCVE that shows your likely problem:
import java.awt.Dimension;
import javax.swing.*;
public class CheckersTest {
private static void createAndShowGui() {
Checkers checkers = new Checkers();
JButton restartButton = new JButton("Restart");
restartButton.addActionListener(event -> checkers.restartBoard());
JPanel restartPanel = new JPanel();
restartPanel.setPreferredSize(new Dimension(400, 400));
restartPanel.add(restartButton);
JFrame frame = new JFrame("Checkers Test");
frame.add(restartPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class Checkers extends JFrame {
public Checkers() {
setPreferredSize(new Dimension(200, 200));
pack();
setLocationByPlatform(true);
setVisible(true);
}
public void restartBoard(){
this.dispose();
new Checkers();
}
}
The restart button refers to the original Checkers instance and so will not close any new instances created. The solution would be to get the restart method out of Checkers, create a Checkers field, and make sure the restart method refers to the visible Checkers instance:
import java.awt.Dimension;
import javax.swing.*;
public class CheckersTest {
private static Checkers checkers = new Checkers(); // holds reference
private static void restartBoard() {
if (checkers != null) {
checkers.dispose();
checkers = new Checkers(); // assign to reference field
}
}
private static void createAndShowGui() {
// !! Checkers checkers = new Checkers();
JButton restartButton = new JButton("Restart");
// !! restartButton.addActionListener(event -> checkers.restartBoard());
restartButton.addActionListener(event -> restartBoard());
JPanel restartPanel = new JPanel();
restartPanel.setPreferredSize(new Dimension(400, 400));
restartPanel.add(restartButton);
JFrame frame = new JFrame("Checkers Test");
frame.add(restartPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class Checkers extends JFrame {
public Checkers() {
setPreferredSize(new Dimension(200, 200));
pack();
setLocationByPlatform(true);
setVisible(true);
}
}
Notes:
Again a much better design is not to swap JFrames but rather JPanel views
Note that the MCVE has code that reproduces the problem but avoids code not related to the problem. So it shows the restartBoard method, it compiles, but avoids game code since this is not relevant to the problem.
So I'm working on making a database system built on top of a Java Swing GUI... I have one button that works to add a person/thing to a vector (in this case the database):
// Database
Vector<String> db = new Vector<String>();
Here is the button's actionlistener to add:
new ActionListener() {
public void actionPerformed(ActionEvent e) {
String newStudent = student.getText();
db.addElement(newStudent);
This part all seems to be working fine, however, when I go to print out the vector on a JTextArea using a string buffer, there are odd spacing issues in the text on the JTextArea
Here is the StringBuffer and section where I print the vector onto the JTextArea:
StringBuffer dbb = new StringBuffer();
for (int i = 0; i < db.size(); i++) {
dbb.append(db.get(i) + '\n');
}
// printDB is the JTextArea
printDB.setText(dbb.toString());
add(printDB);
Screenshot of spacing issues:
Screenshot
Any Ideas on what might be causing this? The spacing seems to be linear as well (1space, 2spaces, 3spaces...)
Link to full project if needed (Sorry for bad code in general lol i'm just beginning): Full Code
Sorry if linear isn't the right word btw I couldn't think of another way to describe it
Code:
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.*;
import java.util.Vector.*;
import javax.swing.*;
public class Database extends JFrame implements ActionListener, EventListener {
// Database
Vector<String> db = new Vector<String>();
// Main Menu Buttons:
JButton addStudent = new JButton("Add Student");
JButton deleteStudent = new JButton("Delete Button");
JButton deleteAll = new JButton("Delete All Students");
JButton printAll = new JButton("Print Database");
JTextArea welcome = new JTextArea("Welcome!");
// Add Student Menu:
JTextField student = new JTextField();
JButton submit = new JButton("Add Student");
// Print Students
JTextArea printDB = new JTextArea();
JButton returnMenu = new JButton("Return to Menu");
public Database() {
super("DatabaseGUI");
setSize(800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
setResizable(false);
welcome.setBackground(this.getForeground());
add(welcome);
welcome.setSize(60, 15);
welcome.setLocation(386, 300);
add(addStudent);
addStudent.setSize(150, 50);
addStudent.setLocation(25, 100);
add(deleteStudent);
deleteStudent.setSize(150, 50);
deleteStudent.setLocation(625, 100);
add(deleteAll);
deleteAll.setLocation(225, 100);
deleteAll.setSize(150, 50);
add(printAll);
printAll.setLocation(425, 100);
printAll.setSize(150, 50);
addStudent.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
welcome.setVisible(false);
addStudent.setVisible(false);
deleteStudent.setVisible(false);
deleteAll.setVisible(false);
printAll.setVisible(false);
add(student);
add(submit);
submit.setVisible(true);
submit.setSize(150, 30);
submit.setLocation(425, 250);
student.setVisible(true);
student.setSize(150, 30);
student.setLocation(275, 250);
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String newStudent = student.getText();
db.addElement(newStudent);
student.setText(null);
student.setVisible(false);
submit.setVisible(false);
welcome.setVisible(true);
addStudent.setVisible(true);
deleteStudent.setVisible(true);
deleteAll.setVisible(true);
printAll.setVisible(true);
}
});
}
});
printAll.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
welcome.setVisible(false);
addStudent.setVisible(false);
deleteStudent.setVisible(false);
deleteAll.setVisible(false);
printAll.setVisible(false);
StringBuffer dbb = new StringBuffer();
for (int i = 0; i < db.size(); i++) {
dbb.append(db.get(i) + '\n');
}
printDB.setText(dbb.toString());
add(printDB);
printDB.setSize(300, 400);
printDB.setEditable(false);
printDB.setLocation(100, 100);
printDB.setVisible(true);
add(returnMenu);
returnMenu.setVisible(true);
returnMenu.setSize(200, 30);
returnMenu.setLocation(500, 400);
returnMenu.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
returnMenu.setVisible(false);
printDB.setVisible(false);
welcome.setVisible(true);
addStudent.setVisible(true);
deleteStudent.setVisible(true);
deleteAll.setVisible(true);
printAll.setVisible(true);
}
});
}
});
setVisible(true);
}
public static void main(String[] args) {
Database student = new Database();
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
You're adding an ActionListener to the submit button repeatedly within the addStudent ActionListener, meaning as addStudent is pressed, more and more ActionListeners will be added to submit and this is not what you want.
Suggestions:
Add an ActionListener just once to your JButtons and not within other event listeners which may be called multiple times. Consider adding all ActionListeners within your class constructor.
Side recs:
Don't use absolute positioning and null layouts. While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
Learn how to use and then use CardLayout to allow you to cleanly and easily swap your views.
For example,
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class Database2 extends JPanel {
// constants for the cards
public static final String WELCOME = "welcome";
public static final String ADD_STUDENT = "add student";
public static final String DISPLAY_DATA = "display data";
private JTextArea displayTextArea = new JTextArea(15, 20);
private JTextField addStudentField = new JTextField(10);
private CardLayout cardLayout = new CardLayout();
private List<String> db = new ArrayList<>();
public Database2() {
// prepare JTextArea
displayTextArea.setWrapStyleWord(true);
displayTextArea.setLineWrap(true);
displayTextArea.setFocusable(false);
// set layout as CardLayout and add all JPanels with constants
setLayout(cardLayout);
add(createWelcomePanel(), WELCOME);
add(createAddStudentPanel(), ADD_STUDENT);
add(createDisplayDataPanel(), DISPLAY_DATA);
}
private JPanel createWelcomePanel() {
ShowStudentPanelAction showStudentAction = new ShowStudentPanelAction("Add Student");
DisplayDataAction displayDataAction = new DisplayDataAction("Display Data");
JButton addStudentButton = new JButton(showStudentAction);
JButton displayDataButton = new JButton(displayDataAction);
JPanel topPanel = new JPanel(new GridLayout(1, 0, 5, 0));
topPanel.add(addStudentButton);
topPanel.add(displayDataButton);
topPanel.add(new JButton(new ExitAction("Exit", KeyEvent.VK_X)));
JLabel welcomeLabel = new JLabel("Welcome", SwingConstants.CENTER);
// make JLabel text bigger
welcomeLabel.setFont(welcomeLabel.getFont().deriveFont(Font.BOLD, 42f));
// and give it a border 30 points wide
int ebGap = 30;
welcomeLabel.setBorder(BorderFactory.createEmptyBorder(ebGap, ebGap,
ebGap, ebGap));
JPanel welcomePanel = new JPanel(new BorderLayout());
ebGap = 4;
welcomePanel.setBorder(BorderFactory.createEmptyBorder(ebGap, ebGap, ebGap, ebGap));
welcomePanel.add(topPanel, BorderLayout.PAGE_START);
welcomePanel.add(welcomeLabel, BorderLayout.CENTER);
return welcomePanel;
}
private JPanel createAddStudentPanel() {
AddStudentAction addStudentAction = new AddStudentAction("Add Student");
addStudentField.setAction(addStudentAction);
JPanel addStudentPanel = new JPanel();
addStudentPanel.add(addStudentField);
addStudentPanel.add(new JButton(addStudentAction));
return addStudentPanel;
}
private JPanel createDisplayDataPanel() {
JPanel displayDataPanel = new JPanel();
JScrollPane scrollPane = new JScrollPane(displayTextArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
displayDataPanel.add(scrollPane);
displayDataPanel.add(new JButton(new ReturnToWelcomeAction("Return")));
return displayDataPanel;
}
private class ShowStudentPanelAction extends AbstractAction {
public ShowStudentPanelAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(Database2.this, ADD_STUDENT);
addStudentField.requestFocusInWindow();
addStudentField.selectAll();
}
}
private class DisplayDataAction extends AbstractAction {
public DisplayDataAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
StringBuilder sb = new StringBuilder();
for (String studentName : db) {
sb.append(studentName + "\n");
}
displayTextArea.setText(sb.toString());
cardLayout.show(Database2.this, DISPLAY_DATA);
}
}
private class AddStudentAction extends AbstractAction {
public AddStudentAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
String studentText = addStudentField.getText();
db.add(studentText);
cardLayout.show(Database2.this, WELCOME);
}
}
private class ReturnToWelcomeAction extends AbstractAction {
public ReturnToWelcomeAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(Database2.this, WELCOME);
}
}
private class ExitAction extends AbstractAction {
public ExitAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
Window window = SwingUtilities.getWindowAncestor(Database2.this);
if (window != null) {
window.dispose();
}
}
}
private static void createAndShowGui() {
Database2 mainPanel = new Database2();
JFrame frame = new JFrame("Database2");
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();
}
});
}
}
I have a JFrame which contains 2 JPanel subclass and 2 JLabel in BorderLayout. One of the JPanel contains JButtons and the other is used for displaying graphics. The JLabels are in north and south, the button JPanel in the west and the display JPanel in center.
The display JPanel requires constant refresh, so i invoke its repaint() method via the action event generated by swing timer. I also override its paintComponent() method to do my drawings.
Instead of displaying what i have drawn, the "content of the JFrame" is being drawn onto the display JPanel. I am aware that i can simply "clear" the display JPanel by using g.fillRect() or super.paintComponent() before doing my drawings.
I am just curious why this happens.
i'm using jdk 1.6u27. below is my code:
package test;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class Main {
public static void main(String[] args) {
Simulation sim = new Simulation();
}
}
class Simulation extends JFrame {
public JLabel state;
private JLabel id;
private ButtonPanel control;
private Display display;
public Simulation() {
id = new JLabel("Test");
state = new JLabel("Test");
control = new ButtonPanel();
display = new Display(this);
this.setLayout(new BorderLayout());
this.add(id, BorderLayout.NORTH);
this.add(control, BorderLayout.WEST);
this.add(display, BorderLayout.CENTER);
this.add(state, BorderLayout.SOUTH);
this.setSize(500, 600);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public ButtonPanel getControl() {
return this.control;
}
}
class ButtonPanel extends JPanel implements ActionListener {
public JButton b[] = new JButton[8];
public boolean bp[] = new boolean[8];
public ButtonPanel() {
this.setLayout(new GridLayout(8, 1));
for (int i = 0; i < b.length; i++) {
b[i] = new JButton(""+i);
b[i].addActionListener(this);
bp[i] = false;
this.add(b[i]);
}
}
public void actionPerformed(ActionEvent e) {
//do something
}
}
class Display extends JPanel implements ActionListener {
private Timer tm;
private int yco;
private Simulation sim;
public Display(Simulation sim) {
tm = new Timer(100, this);
tm.start();
yco = 0;
this.sim = sim;
}
#Override
public void paintComponent(Graphics g) {
//draw something
g.drawLine(0, yco, 100, 100);
}
public void actionPerformed(ActionEvent e) {
yco ++;
this.repaint();
}
}
Without super.paintComponent(g), the result depends on your platform's default for the opacity property of the JPanel UI delegate, PanelUI. Mine happens to be true, but you can experiment on your platform, as suggested below.
Addendum: "If you do not honor the opaque property you will likely see visual artifacts."—paintComponent(). The artifact you observe will vary by platform, but it is not atypical. In effect, you are breaking the promise to draw every pixel, and you see whatever is left over in some buffer.
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class Main {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Simulation sim = new Simulation();
}
});
}
}
class Simulation extends JFrame {
public JCheckBox state;
private JLabel id;
private ButtonPanel control;
private Display display;
public Simulation() {
id = new JLabel("Test");
state = new JCheckBox("Opaque");
control = new ButtonPanel();
display = new Display(this);
this.setLayout(new BorderLayout());
this.add(id, BorderLayout.NORTH);
this.add(control, BorderLayout.WEST);
this.add(display, BorderLayout.CENTER);
this.add(state, BorderLayout.SOUTH);
state.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
display.setOpaque(e.getStateChange() == ItemEvent.SELECTED);
}
});
state.setSelected(true);
this.pack();
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public ButtonPanel getControl() {
return this.control;
}
}
class ButtonPanel extends JPanel {
private static final int N = 8;
private List<JToggleButton> list = new ArrayList<JToggleButton>(N);
public ButtonPanel() {
this.setLayout(new GridLayout(0, 1));
for (int i = 0; i < N; i++) {
final JToggleButton b = new JToggleButton(String.valueOf(i));
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//System.out.println(b.isSelected());
}
});
list.add(b);
this.add(b);
}
}
}
class Display extends JPanel {
private Simulation sim;
private Timer tm;
private int yco;
public Display(Simulation sim) {
this.setPreferredSize(new Dimension(320, 320));
this.setOpaque(true);
this.sim = sim;
tm = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
yco++;
repaint();
}
});
tm.start();
}
#Override
public void paintComponent(Graphics g) {
//super.paintComponent(g);
g.drawLine(0, yco, getWidth() / 2, getHeight() / 2);
}
}