Repaint many elements with one button click in GUI app - java

Hello, I've been working on a GUI application that should resize dynamically and change background color multiple times after clicking a button. My first shot was to make a for loop inside an actionPerformed(ActionEvent e) method but it doesn't work properly. Strangely enough, the app changes properly if the listener is removed and the commented code from main function is used. Why is that? This code is actually a simple example of a problem which I've came across making a slightly more complex app. Could You kindly add a line or two if the solution varies if my window consists of many JPanels and I decide to repeatedly change properties of some other elements with one button click?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
public class TempWindow {
public static void main(String [] args ) {
Frame f = new Frame();
// for (int i = 0; i < 3; i++) {
// if(i == 0) {
// f.getMyPanel().setBackground(Color.red);
// }
// if (i == 1) {
// f.setSize(500, 400);
// f.getMyPanel().setBackground(Color.yellow);
// }
// if( i == 2) {
// f.setSize(100, 200);
// f.getMyPanel().setBackground(Color.green);
// }
//
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// f.repaint();
// }
}
}
class Frame extends JFrame {
MyPanel panel;
JButton but1;
public Frame() {
this.setSize(400, 300);
this.setLocationRelativeTo(null);
this.setLayout(new BorderLayout());
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
but1 = new JButton("Start");
this.getContentPane().add(but1, BorderLayout.NORTH);
panel = new MyPanel();
this.getContentPane().add(panel, BorderLayout.CENTER);
but1.addActionListener(new DanceActionListener(this));
this.setVisible(true);
}
public MyPanel getMyPanel() {
return panel;
}
}
class MyPanel extends JPanel {
JLabel text;
public MyPanel() {
this.setBackground(Color.black);
this.setLayout(new BorderLayout());
text = new JLabel(" xxx ");
text.setFont(new Font(Font.SERIF, Font.BOLD, 40));
this.add(text, BorderLayout.CENTER);
text.setHorizontalAlignment(SwingConstants.CENTER);
text.setVerticalAlignment(SwingConstants.CENTER);
}
}
class DanceActionListener implements ActionListener {
MyPanel panel;
Frame f;
public DanceActionListener(Frame f) {
this.f = f;
this.panel = f.getMyPanel();
}
public void actionPerformed(ActionEvent e ){
for (int i = 0; i < 3; i++) {
if(i == 0) {
panel.setBackground(Color.red);
panel.repaint();
}
if (i == 1) {
panel.setBackground(Color.yellow);
f.setSize(500, 400);
}
if( i == 2) {
f.setSize(100, 200);
panel.setBackground(Color.green);
}
f.repaint();
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}

Related

How don't repaint after setLocation my JLabel

I'm doing an animation for my Menu. I created an animation vidéo : https://youtu.be/wG6AFMj1ZYI
As u can see the animation repaint my frame so hard :'(. I won't repaint after modifying my JLabel !
private synchronized void animationButtonExited(JLabelFirstPosition button) {
if (button.getActual_thread_running().isAlive()) {
button.getActual_thread_running().interrupt();
}
Thread t = new Thread(() -> {
SwingUtilities.invokeLater(() -> {
button.setFont(new Font(null, 0,
(int) (this.racio_width < this.racio_height
? (int) (button.getFirstFontSize() * this.racio_width)
: (button.getFirstFontSize() * this.racio_height))));
button.setSize((int) (button.getFirstSize().getWidth() * this.racio_width),
(int) (button.getFirstSize().getHeight() * this.racio_height));
});
try {
while (button.getLocation().getX() > button.getFirstX() * this.racio_width) {
SwingUtilities.invokeLater(() -> {
button.setLocation((int) ((button.getLocation().getX() - 1)),
(int) (button.getFirstY() * this.racio_height));
});
Thread.sleep(6);
}
} catch (InterruptedException e1) {
}
});
t.start();
if (!button.getActual_thread_running().isAlive()) {
} else {
button.getActual_thread_running().interrupt();
}
button.setActual_thread_running(t);
}
private synchronized void animationButtonEntered(JLabelFirstPosition button) {
if (button.getActual_thread_running().isAlive()) {
button.getActual_thread_running().interrupt();
}
Thread t = new Thread(() -> {
SwingUtilities.invokeLater(() -> {
button.setFont(new Font("", 1,
(int) (this.racio_width < this.racio_height
? (int) (button.getFirstFontSize() * this.racio_width)
: ((button.getFirstFontSize() + 5) * this.racio_height))));
button.setSize((int) ((button.getFirstSize().getWidth() + 20) * this.racio_width),
(int) (button.getFirstSize().getHeight() * this.racio_height));
});
try {
while (button.getLocation().getX() <= (button.getFirstX() + 20) * this.racio_width) {
SwingUtilities.invokeLater(() -> {
button.setLocation((int) ((button.getLocation().getX() + 1)),
(int) (button.getFirstY() * this.racio_height));
});
Thread.sleep(3);
}
} catch (InterruptedException e1) {
}
});
t.start();
if (!button.getActual_thread_running().isAlive()) {
} else {
button.getActual_thread_running().interrupt();
}
button.setActual_thread_running(t);
}
My fps calculator detect how many time method "paintComponent" is call.
Thanks !
Here's one way to create a menu where a mouse-over makes the selection stand out.
The MouseListener class has three methods that we'll use in this example. The mouseEntered method detects when the mouse enters a Swing component, in this case, a JLabel. The mouseExited method detects when the mouse exits a Swing component.
The mousePressed method detects when a mouse button is pressed. This allows us to use a JLabel to select an option.
Setting up the JFrame is a bit tricky. We don't want the JPanels we've created to constantly change size.
So, we go through the following process:
Create the menu JPanel with the larger font
Pack the JFrame
Get the size of the menu JPanel and make that the preferred size of the menu JPanel
Change the font back to the smaller font before we make the JFrame visible.
Here's the code I used.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MouseoverExample implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new MouseoverExample());
}
private Font font;
private JLabel optionLabel;
private JLabel option1Label;
private JLabel option2Label;
private JLabel option3Label;
private JPanel menuPanel;
#Override
public void run() {
JFrame frame = new JFrame("Mouseover Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMenuPanel(), BorderLayout.BEFORE_LINE_BEGINS);
frame.add(createDummyPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
menuPanel.setPreferredSize(menuPanel.getSize());
updateFont();
frame.setVisible(true);
}
private JPanel createMenuPanel() {
JPanel outerPanel = new JPanel();
outerPanel.setLayout(new FlowLayout());
menuPanel = new JPanel();
menuPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
menuPanel.setLayout(new GridLayout(0, 1, 5, 5));
font = menuPanel.getFont().deriveFont(18f);
Font boldFont = font.deriveFont(Font.BOLD).deriveFont(24f);
ExampleListener listener = new ExampleListener(font, boldFont);
option1Label = new JLabel("Option 1");
option1Label.setFont(boldFont);
option1Label.addMouseListener(listener);
menuPanel.add(option1Label);
option2Label = new JLabel("Option 2");
option2Label.setFont(boldFont);
option2Label.addMouseListener(listener);
menuPanel.add(option2Label);
option3Label = new JLabel("Option 3");
option3Label.setFont(boldFont);
option3Label.addMouseListener(listener);
menuPanel.add(option3Label);
outerPanel.add(menuPanel);
return outerPanel;
}
private void updateFont() {
option1Label.setFont(font);
option2Label.setFont(font);
option3Label.setFont(font);
}
private JPanel createDummyPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setPreferredSize(new Dimension(400, 400));
optionLabel = new JLabel(" ");
panel.add(optionLabel);
return panel;
}
public class ExampleListener extends MouseAdapter {
private Font enterFont;
private Font exitFont;
public ExampleListener(Font exitFont, Font enterFont) {
this.exitFont = exitFont;
this.enterFont = enterFont;
}
#Override
public void mouseEntered(MouseEvent event) {
JLabel label = (JLabel) event.getSource();
label.setFont(enterFont);
}
#Override
public void mouseExited(MouseEvent event) {
JLabel label = (JLabel) event.getSource();
label.setFont(exitFont);
}
#Override
public void mousePressed(MouseEvent event) {
JLabel label = (JLabel) event.getSource();
String optionText = label.getText();
optionLabel.setText(optionText + " displayed");
}
}
}

How to delete button after clicking on "delete" button?

My program seems to run fine, except for the delete part. Every time I click on the 'delete' button, it deletes itself. So my question is, how would I delete a selected button after I clicked on the "delete" button?
Here is a snippet of my code:
public class DeleteButton extends JFrame implements ActionListener
{
JButton b18a = new JButton("Delete");
JPanel panel = new JPanel();
panel.add(b18);
class ClickListenerTwo implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
JButton buttonThatWasClicked = (JButton) e.getSource();
Container parent = buttonThatWasClicked.getParent();
parent.remove(buttonThatWasClicked);
parent.revalidate();
parent.repaint();
}
}
}
ActionListener b18aClicked = new ClickListenerTwo();
b18a.addActionListener(b18aClicked);
P.S - This selected button that I'm talking about is made during run time, so I want to delete it during run time too, if that would be possible. Thanks!
So, assuming that you need to click the "other" button first, you could use an instance field to maintain a reference to the "last" clicked button and then use that when the delete button is clicked
For example...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JButton lastButton;
public TestPane() {
JPanel grid = new JPanel(new GridLayout(8, 8));
for (int index = 0; index < 8 * 8; index++) {
JButton btn = new JButton(Integer.toString(index + 1));
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
lastButton = btn;
}
});
grid.add(btn);
}
JButton delete = new JButton("Delete");
delete.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (lastButton != null) {
lastButton.getParent().remove(lastButton);
grid.revalidate();
grid.repaint();
}
lastButton = null;
}
});
setLayout(new BorderLayout());
add(grid);
add(delete, BorderLayout.SOUTH);
}
}
}
Personally, a JToggleButton would give a better user experience
You have to find the Component from the Top Frame.
May be this code will help you.
public void actionPerformed(ActionEvent evt) {
Object source = evt.getSource();
if (source instanceof Component) {
Window w = findWindow((Component) source);
//Find your component and remove it from this window.
} else {
System.out.println("source is not a Component");
}
}
public static Window findWindow(Component c) {
System.out.println(c.getClass().getName());
if (c instanceof Window) {
return (Window) c;
} else if (c instanceof JPopupMenu) {
JPopupMenu pop = (JPopupMenu) c;
return findWindow(pop.getInvoker());
} else {
Container parent = c.getParent();
return parent == null ? null : findWindow(parent);
}
}

switch to an animation image in cardlayout

I want to create a login dialog. when user press login button it will show a animation image. with some search I find that use cardlayout can switch to another panel so I chose cardlayout for my login dialog. but when a switch to a panel contain a jlabel that have animation image jlabel just load text
here is my code:
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author 20133_000
*/
public class Draft9 {
public static void main(String[] args) {
TestCardLayout test = new TestCardLayout();
}
}
class TestCardLayout extends JFrame {
private JPanel mainPanel;
private CardPanel panel1;
private JPanel panel2;
private CardLayout layout;
public TestCardLayout() {
mainPanel = new JPanel();
panel1 = new CardPanel();
panel2 = new JPanel();
layout = new CardLayout();
panel1.add(new JButton("here is panel 1"));
JLabel jLabel1 = new javax.swing.JLabel("here is panel 2",new javax.swing.ImageIcon( "E:\\programming\\programming java\\Netbean Projectr\\Project1\\src\\images\\loading3.gif") , JLabel.CENTER);
jLabel1.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
//jLabel1.setIcon(new javax.swing.ImageIcon("/images/loading3.gif")); // NOI18N
// jLabel1.setIcon(new javax.swing.ImageIcon("E:\\programming\\programming java\\Netbean Projectr\\Project1\\src\\images\\loading3.gif"));
panel2.add(new JButton("here is panel 2"), BorderLayout.NORTH);
panel2.add(jLabel1, BorderLayout.CENTER);
mainPanel.setLayout(layout);
mainPanel.add("panel1", panel1);
mainPanel.add("panel2", panel2);
add(mainPanel, BorderLayout.CENTER);
setSize(400, 450);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
//layout.show(mainPanel, "panel2");
}
}
class CardPanel extends JPanel {
JButton btnChangePanel;
public CardPanel() {
btnChangePanel = new JButton("show panel 2");
btnChangePanel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
showPanel2();
calculateData();
}
});
add(btnChangePanel);
}
public void showPanel2() {
JPanel parentPanel = (JPanel) getParent();
CardLayout layout = (CardLayout) parentPanel.getLayout();
layout.show(parentPanel, "panel2");
}
public void showPanel1() {
JPanel parentPanel = (JPanel) getParent();
CardLayout layout = (CardLayout) parentPanel.getLayout();
layout.show(parentPanel, "panel1");
}
public void calculateData() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
System.out.println("calculating data...");
//doing some calculate here
Thread.sleep(3000);
System.out.println("done calculting");
//System.exit(0);
int res = 1;
if (res == 1) {
System.out.print("login ok");
showPanel2();
} else {
System.out.print("login failed");
showPanel1();
}
} catch (Exception ex) {
Logger.getLogger(CardPanel.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
}
when i leave Thread.sleep(3000); comment it work but when i uncomment that line it doesn't work. How can i fix it ?
It's because your image is animated (would work with a normal one) and your Thread.sleep(3000) freezes the whole frame, note that you also can't click the button (or move frame). You could start a new thread to solve this:
public void calculateData() {
new Thread(new Runnable() {
public void run() {
try {
System.out.println("calculating data...");
// doing some calculate here
Thread.sleep(3000);
System.out.println("done calculting");
// System.exit(0);
int res = 1;
if (res == 1) {
System.out.print("login ok");
showPanel2();
} else {
System.out.print("login failed");
showPanel1();
}
} catch (Exception ex) {
Logger.getLogger(CardPanel.class.getName()).log(Level.SEVERE, null, ex);
}
}
}).start();
}

how to make a jscrollpane scroll from the start to the end?

I'm trying to make a jscorllpane automatic scroll from the start to the end. I use set value method for verticalbar but it's doesn't work. How can i make it scroll ?
Here is my code: When i run this code it just jump to the end of the jscorllpane instead of scorlling step by step
import java.awt.event.*;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
class JScrollPaneToTopAction implements ActionListener {
JScrollPane scrollPane;
public JScrollPaneToTopAction(JScrollPane scrollPane) {
if (scrollPane == null) {
throw new IllegalArgumentException("JScrollPaneToTopAction: null JScrollPane");
}
this.scrollPane = scrollPane;
}
public void actionPerformed(ActionEvent actionEvent) {
run();
}
public void run() {
JScrollBar verticalBar = scrollPane.getVerticalScrollBar();
int i = verticalBar.getMinimum();
while (i < verticalBar.getMaximum()) {
verticalBar.setValue(verticalBar.getMinimum()+i);
i += 50;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
scrollPane.getParent().invalidate();
scrollPane.repaint();
scrollPane.invalidate();
System.out.println("changing " + i);
}
}
}
public class Draft20 {
public static void main(String args[]) {
JFrame frame = new JFrame("Tabbed Pane Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextArea tr = new JTextArea();
JLabel label = new JLabel("Label");
label.setPreferredSize(new Dimension(1000, 1000));
JScrollPane jScrollPane = new JScrollPane(label);
JButton bn = new JButton("Move");
bn.addActionListener(new JScrollPaneToTopAction(jScrollPane));
frame.add(bn, BorderLayout.SOUTH);
frame.add(jScrollPane, BorderLayout.CENTER);
frame.setSize(400, 150);
frame.setVisible(true);
}
}
I think the problem is your calls to repaint are queued for computation by EDT, but EDT is busy executing your actionPerformed. EDT will execute your repaint requests only after your run() completes. That's why you can see only the final result.
I'm not sure I can make it clear... check this code, it works for me:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
class JScrollPaneToTopAction implements ActionListener, Runnable {
JScrollPane scrollPane;
public JScrollPaneToTopAction(JScrollPane scrollPane) {
if (scrollPane == null) {
throw new IllegalArgumentException("JScrollPaneToTopAction: null JScrollPane");
}
this.scrollPane = scrollPane;
}
#Override
public void actionPerformed(ActionEvent actionEvent) {
new Thread(this).start();
}
#Override
public void run() {
JScrollBar verticalBar = scrollPane.getVerticalScrollBar();
int i = verticalBar.getMinimum();
while (i < verticalBar.getMaximum()) {
verticalBar.setValue(verticalBar.getMinimum() + i);
i += 50;
try {
Thread.sleep(100);
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
scrollPane.getParent().invalidate();
scrollPane.repaint();
scrollPane.invalidate();
}
});
System.out.println("changing " + i);
}
}
}
public class Draft20 {
public static void main(String args[]) {
JFrame frame = new JFrame("Tabbed Pane Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextArea tr = new JTextArea();
JLabel label = new JLabel("Label");
label.setPreferredSize(new Dimension(1000, 1000));
JScrollPane jScrollPane = new JScrollPane(label);
JButton bn = new JButton("Move");
bn.addActionListener(new JScrollPaneToTopAction(jScrollPane));
frame.add(bn, BorderLayout.SOUTH);
frame.add(jScrollPane, BorderLayout.CENTER);
frame.setSize(400, 150);
frame.setVisible(true);
}
}
I hope it helps.

How to Close JInternalFrame when JButton click and show another JInternalFrame?

For Example:
When JButton1 click JInternalFrame1 Show on the JDesktopPane
And when JButton2 Click JInternalFrame1 Close and JInternalFrame2 Show on the JDesktopPane.
thx before
Edit: with code from comment
if (JInternalFrame1 == null) {
JInternalFrame1 = new FJInternalFrame();
Desktop.add(JInternalFrame1);
JInternalFrame1.toFront();
} else {
JInternalFrame1.dispose();
}
Take a look at this example. I created a custom JInternalFrame that has a different title every time you create a new frame. when you click on the button, a new one is created and the old one disapears
Here is the important code that may help you out. I add a new frame if the desktop size is equal to 0, other wise I remove the previous one, add a new frame, and revalidate
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (desktop.getAllFrames().length == 0) {
desktop.add(new MyInternalFrame());
} else {
desktop.remove(0);
desktop.add(new MyInternalFrame());
revalidate();
repaint();
}
}
});
Here is the complete code. It's two different files.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class InternalFrameDemo1 extends JPanel {
JDesktopPane desktop;
JButton button;
public InternalFrameDemo1() {
desktop = new JDesktopPane();
button = new JButton("Get Next Frame");
setLayout(new BorderLayout());
add(desktop, BorderLayout.CENTER);
add(button, BorderLayout.SOUTH);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (desktop.getAllFrames().length == 0) {
desktop.add(new MyInternalFrame());
} else {
desktop.remove(0);
desktop.add(new MyInternalFrame());
revalidate();
repaint();
}
}
});
}
public static void createAndShowGui() {
JFrame frame = new JFrame();
frame.add(new InternalFrameDemo1());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.pack();
frame.setVisible(true);
}
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
import javax.swing.JInternalFrame;
public class MyInternalFrame extends JInternalFrame {
static int openFrameCount = 0;
static final int xOffset = 30, yOffset = 30;
public MyInternalFrame() {
super("Document #" + (++openFrameCount),
true, //resizable
true, //closable
true, //maximizable
true);//iconifiable
setSize(300,300);
setLocation(xOffset*openFrameCount, yOffset*openFrameCount);
setVisible(true);
}
}

Categories