I need to create a 4 x 4 grid of rectangles in Java, I then need these rectangles to change color in a sequence.
I've never done any graphical work before, just things in the console.
I started by doing some research and created a 650 x 650 JFrame to put the rectangles in.
After that I used GridLayout and managed to create a 4 x 4 grid out of buttons using window.JButton which wasn't right.
How would I create rectangles instead? And would it be right to use for loops with ++ to time the animation?
I couldn't find anything that worked for my needs when searching on stackoverflow and google. Sorry if this is a stupid question. I'm new to this and I'm doing for an apprecticeship.
Here's how I would like it to look like, with each rectangle changing color in a time interval
From #Eng.Fouad answer (so give him credit and upvote his answer too), I made some changes, this example shows how to use a Swing Timer which changes color every second from green to red. I'm using a simple JLabel for demonstration purposes, take this logic into the GridLayout you have:
Here are some screen shots on how it looks:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class SimpleTimer extends JFrame
{
private JLabel label;
private Timer timer;
private int counter = 3; // the duration
private int delay = 1000; // every 1 second
private static final long serialVersionUID = 1L;
private Color c = Color.RED;
private boolean red = true;
private boolean stop = false;
int i = counter;
public SimpleTimer()
{
super("Simple Timer");
setDefaultCloseOperation(EXIT_ON_CLOSE);
label = new JLabel("Wait for " + counter + " sec", JLabel.CENTER);
JPanel contentPane = (JPanel) getContentPane();
contentPane.add(label, BorderLayout.CENTER);
contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
pack();
timer = new Timer(delay, action);
timer.setInitialDelay(0);
timer.start();
setVisible(true);
}
ActionListener action = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent event)
{
if(i == 0)
{
timer.stop();
stop = true;
i = counter;
timer = new Timer(delay, action);
timer.setInitialDelay(0);
timer.start();
}
else
{
c = red ? Color.GREEN : Color.RED;
red = !red;
label.setBackground(c);
label.setOpaque(true);
label.setText("Wait for " + i + " sec");
i--;
}
}
};
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new SimpleTimer();
}
});
}
}
You could use jLabel, and set background color to it. How you do it, you can read here: How do I set a JLabel's background color?
Then just use for loop and Thred.sleep to change there color in animation.
Related
I am having trouble with a game I am making. I am attempting to fade a JLabel, using a Timer. So far, I have been able to set a JLabel as transparent, and I have been able to make a working Timer. But somehow, I am not able to combine them together. I can set a JLabel's background to
l.setBackground(new Color(0, 0, 0, 200));
(l being desired JLabel to change the color of, of course)
and it works. The JLabel is transparent.
But I have not been able to put it into a timer so that the color fades:
public static void fadeLabel(JLabel lab, int steps, int target) {
class fade extends Thread {
public void run() {
Timer t = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(lab.getBackground().getAlpha());
lab.setBackground(new
Color(lab.getBackground().getRed(),
lab.getBackground().getGreen(),
lab.getBackground().getBlue(),
lab.getBackground().getAlpha() + steps));
if (lab.getBackground().getAlpha() == target) {
((Timer) e.getSource()).stop();
}
}
});
t.start();
}
}
new Thread(new fade()).start();
}
instead, it just goes from black to transparent. Nothing in-between. It also throws the error java.lang.IllegalArgumentException: Color parameter outside of expected range: Alpha. However, I have set the step to -5 (the rate at which it fades, in this case, fades out, as it is negative) and if you remember, I set the alpha to something that is divisible by five, and I also have a checker for when it gets to the target, so that it stops the Timer when it reaches that target. Is there something I'm doing wrong? Is the JLabel's background updating too fast for it to show? Any help would be great.
Edit:
I have fixed the java.lang.IllegalArgumentException: Color parameter outside of expected range: Alpha. But the other one about the JLabel not fading is still there, and I don't know how to fix it.
I'm not directly answering your question. A wrote some code, take a look :D
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class MyWindow extends JFrame {
public MyWindow() {
initComponents();
}
private void initComponents() {
setTitle( "Fading labels :)" );
setDefaultCloseOperation( EXIT_ON_CLOSE );
setSize( 400, 400 );
setLocationRelativeTo( null );
setLayout( new FlowLayout() );
for ( int i = 0; i < 550; i++ ) {
JLabel lab = new JLabel( "x" );
add( lab );
fadeLabel( lab, 10, i / 10, 0 );
}
}
private void fadeLabel( JLabel label, int steps, int skipSteps, int targetAlpha ) {
new LabelFader( label, steps, skipSteps, targetAlpha ).start();
}
private class LabelFader {
JLabel label;
int steps;
int skipSteps;
int targetAlpha;
LabelFader( JLabel label, int steps, int skipSteps, int targetAlpha ) {
this.label = label;
this.steps = steps;
this.skipSteps = skipSteps;
this.targetAlpha = targetAlpha;
}
void start() {
Color startColor = label.getForeground();
int startAlpha = startColor.getAlpha();
int deltaAlpha = startAlpha - targetAlpha;
if ( deltaAlpha > 0 ) {
int alphaStep = deltaAlpha / steps;
new Thread( new Runnable() {
#Override
public void run() {
int totalIterations = steps + skipSteps;
int currIteration = 1;
for ( int i = 0; i < totalIterations; i++ ) {
if ( skipSteps == 0 ) {
int newAlpha = startAlpha - alphaStep * currIteration++;
newAlpha = newAlpha < 0 ? 0 : newAlpha;
Color newColor = new Color(
startColor.getRed(),
startColor.getGreen(),
startColor.getGreen(),
newAlpha );
label.setForeground( newColor );
} else {
skipSteps--;
}
try {
Thread.sleep( 100 );
} catch ( InterruptedException exc ) {
exc.printStackTrace();
}
}
Color newColor = new Color(
startColor.getRed(),
startColor.getGreen(),
startColor.getGreen(),
targetAlpha );
label.setForeground( newColor );
}
}).start();
}
}
}
public static void main( String[] args ) {
EventQueue.invokeLater( new Runnable() {
public void run() {
new MyWindow().setVisible( true );
}
});
}
}
A JLabel is not opaque by default, so its background is not painted. Therefore changing its background color will have no effect - unless you explicitly made your JLabel opaque by calling the relevant method, as in
lab.setOpaque(true)
Forgive me but I couldn't find that in the code you posted.
Also, code that affects the GUI needs to be performed on the Event Dispatch Thread (EDT). Your code that changes the JLabel background color is being run in a separate thread. The result of running that code is therefore unpredictable. The javax.swing.Timer class does not need to be run in a separate thread. Simply create a Timer object and then call its start method. So just take your code that creates the Timer out of the Thread and put it in with the rest of your GUI code.
If you would like a small, demo program showing how to fade the text of a JLabel, let me know.
EDIT: Here is the demo that fades the JLabel text. A JFrame containing a JLabel and a JButton. Click the JButton and the JLabel text fades until it disappears.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.Timer;
import javax.swing.WindowConstants;
/**
* Tests <i>Swing</i> {#link javax.swing.Timer timer}.
*/
public class LabelDim {
private int alpha;
private JButton button;
private JFrame frame;
private JLabel label;
private Timer timer;
public LabelDim() {
timer = new Timer(200, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (alpha > 0) {
alpha -= 15;
label.setForeground(new Color(0, 0, 0, alpha));
}
else {
timer.stop();
}
}
});
}
private void showGui() {
frame = new JFrame("Dim");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
label = new JLabel("I am a fading label.", SwingConstants.CENTER);
alpha = label.getForeground().getAlpha();
label.setFont(label.getFont().deriveFont(24.0f));
label.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20));
frame.add(label, BorderLayout.CENTER);
button = new JButton("Start");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
JPanel panel = new JPanel();
panel.add(button);
frame.add(panel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
LabelDim instance = new LabelDim();
EventQueue.invokeLater(() -> instance.showGui());
}
}
SECOND EDIT:
Here's some sample code that works. It'll throw the Exception you've already fixed but this is just for demonstration purposes only :).
Play with the label.setOpaque and its background and tell what happens with yourself. If you need to draw the label background set that flag to true.
If you do not need to draw its background do not modify label's background and do not set it to be opaque and modifying the foreground color should be more than enough! :)
package main;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Main extends JFrame {
JLabel label;
JButton btn;
public Main() {
setSize(500,500);
setLayout(new FlowLayout());
label = new JLabel("My super awesome label");
//label.setOpaque(true); //Play with these lines and see what happens
//label.setBackground(Color.BLUE); //Play with these lines and see what happens
btn = new JButton("Click me");
btn.setSize(200,200);
btn.addActionListener(
(ActionEvent evt) -> {
Timer t = new Timer(100,
(ActionEvent event) -> {
Color foreground = label.getForeground();
Color background = label.getBackground();
foreground = decreaseAlpha(foreground);
background = decreaseAlpha(background);
label.setForeground(foreground);
label.setBackground(background);
}
);
t.start();
}
);
this.add(label);
this.add(btn);
}
public static void main(String[] args) {
(new Main()).setVisible(true);
}
public Color decreaseAlpha(Color original) {
return new Color(original.getRed(), original.getGreen(), original.getBlue(), original.getAlpha() - 10);
}
}
EDIT:
You might be changing your background of your label instead of its foreground...
Timer t = new Timer(10, (ActionEvent evt)-> {
l.setForeground(new
Color(l.getForeground().getRed(),
l.getForeground().getGreen(),
l.getForeground().getBlue(),
l.getForeground().getAlpha() - 1)
);
l.invalidate();
});
t.start();
Being l your label
Also, don't do this:
new Thread(new fade()).start();
Your fade class is already a Thread because it's extending it. Use (new fade()).start(); instead
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I want to set the location of JButtons with coordinates but how to make each button don't "touch" the others? The Layout must be null !!! I tried the method contains and with Rectangle but it didn't work.
Thanks
You will want to use intersects(), not contains(). contains() will only return true if comp1 entirely contains comp2. Here is an example that continues to add new JButton's at a random position, as long as they don't intersect another Component. (click here for a preview)
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.Timer;
public class Example {
private final int BUTTON_WIDTH = 100;
private final int BUTTON_HEIGHT = 20;
public Example() {
JFrame frame = new JFrame();
frame.setLayout(null);
Timer timer = new Timer(100, new ActionListener() {
Random random = new Random();
#Override
public void actionPerformed(ActionEvent arg0) {
JButton button = new JButton("Button");
button.setBounds(random.nextInt(frame.getContentPane().getWidth() - BUTTON_WIDTH),
random.nextInt(frame.getContentPane().getHeight() - BUTTON_HEIGHT), BUTTON_WIDTH,
BUTTON_HEIGHT);
for (int tries = 0; tries < 50; tries++) {
if (intersectsComponent(button, frame.getContentPane().getComponents())) {
button.setBounds(random.nextInt(frame.getContentPane().getWidth() - BUTTON_WIDTH),
random.nextInt(frame.getContentPane().getHeight() - BUTTON_HEIGHT), BUTTON_WIDTH,
BUTTON_HEIGHT);
} else {
frame.add(button);
break;
}
}
frame.revalidate();
frame.repaint();
}
});
timer.start();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.setVisible(true);
}
public boolean intersectsComponent(Component component, Component[] components) {
for (Component c : components) {
if (c.getBounds().intersects(component.getBounds())) {
return true;
}
}
return false;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Example();
}
});
}
}
Let's say you have a total space of H pixels by W pixels.
You can divide this space to a grid of 10 by 10.
Each "slot" is now H/10 by W/10.
Now you can create 100 buttons which do not collide using random setBounds(...) in each slot using a null layout.
Each JButton has its own space and you still get semi-randomness.
Note that MadProgrammer would prolly tell you it's a very bad idea to use null layouts.
EDIT:
Not only MadProgrammer.
Disclaimer:
I did once used a null layout for JDekstopPane.
I still have this line of code with me.
The rest 1M or so lines of code are free of such rebellious concepts.
I'm trying to resize a label on MouseEnter, but on MouseExit, I want it back to the previous state. How would I do this?
I want the label to be bigger when it is moused over, but when the mouse exits, the label will back to normal size.
Can anybody explain to me how to do that?
If it's possible, I want to see the resize slowly.
This is the code:
package kk
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.GroupLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class ScrollGroup extends JPanel {
private static final int N = 8;
private static final int NN = N * N;
private static final int GAP = 5;
private static final int SIZE = 100;
public ScrollGroup() {
this.setLayout(new GridLayout(N, N, GAP, GAP));
for (int i = 0; i < NN; i++) {
final JLabel label = new JLabel();
label.setOpaque(true);
label.setBackground(Color.getHSBColor((float) i / NN, 1, 1));
label.setPreferredSize(new Dimension(SIZE, SIZE));
this.add(label);
label.addMouseListener(new MouseAdapter() {
public void mouseEntered(MouseEvent e){
}
public void mouseExited(MouseEvent e) {
}
});
}
}
private void display() {
JFrame f = new JFrame("ScrollGroup");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane sp = new JScrollPane(this);
GroupLayout layout = new GroupLayout(f.getContentPane());
f.setLayout(layout);
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
layout.setHorizontalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup().addComponent(sp)));
layout.setVerticalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup().addComponent(sp)));
f.pack();
f.setSize(N * SIZE, N * SIZE);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ScrollGroup().display();
}
});
}
}
I'm trying to resize a label in MouseEntred,
Define "resize".
You are adding your JLabels to a panel using a GridLayout. All the labels are already set to the maximum size permitted by the space available to the panel, so what do you expect the resize to do?
If you want it to appear that the label is getting bigger, then maybe you can assign a MatteBorder to each label. You can make the MatteBorder whatever size you want and then set the color equal to the background color of the panel.
If you want to animate then then you can use a Swing Timer. In the mouse#ntered you start the Timer. Every time the Timer fires you change the MatteBorder to be one less pixedl until the size is zero and you stop the Timer. On mouseExited, you just restore the default Border.
See the sections from the Swing tutorial on How to Use Timers and How to Use Borders for more information.
I'm making an app where a user would be able to add a button to the screen or remove it (I don't have those options implemented yet). So, for now I'm manually populating it with a for() loop and manually removing one of the buttons. My problem is that after the button has been removed (the removal action in the main()), there's just a blank spot. I want to be able to repaint the screen after I remove one of those buttons. In this example, index 2 (block #3) has been removed, leaving an empty space, where it was before... and I have no idea how to repaint it. I've tried validating or repainting from different places in the program with no success.
Here's the code (P.S. I'm sure my code is not the most efficient way to accomplish what I'm trying to and I'm using setLayout(null), which is not a preferred method, but for now I'm just trying to learn certain things and then expand on that to better myself and my code):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
class TestApp extends JFrame{
JFrame frame = new JFrame("Test Program");
ArrayList<JButton> grid = new ArrayList<JButton>();
private int w = 14;
private static int amount = 102;
private static int counter = 0;
//Default Constructor (sets up JFrame)
TestApp(){
frame.setLayout(null);
frame.setPreferredSize(new Dimension(1186, 880));
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setResizable(false);
paintGrid();
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void newWindow()
{
JFrame select_win = new JFrame("Selected Frame");
JPanel select_panel = new JPanel();
select_panel.setPreferredSize(new Dimension(600, 800));
select_panel.setBackground(Color.ORANGE);
select_win.add(select_panel);
select_win.pack();
select_win.setResizable(false);
select_win.setVisible(true);
select_win.setLocationRelativeTo(null);
}
private void paintGrid()
{
for(int i = 0, y = 4; i < ((amount / w) + (amount % w)); i++, y += 104)
{
for(int j = 0, x = 4; j < w && (counter < amount); j++, x += 84)
{
addBlock(counter, x, y);
counter++;
}
}
}
//Adds a block
private void addBlock(int index, int x, int y){
int height = 100;
int width = 80;
grid.add(new JButton("counter: " + (counter + 1)));
(grid.get(index)).addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
newWindow();
}
});
}
});
(grid.get(index)).setBorder(new LineBorder(Color.BLACK));
(grid.get(index)).setBackground(Color.YELLOW);
(grid.get(index)).setVisible(true);
(grid.get(index)).setBounds(x, y, width, height);
frame.add(grid.get(index));
}
//Removes a block
private void removeBlock(int index){
frame.remove(grid.get(index));
grid.remove(index);
amount--;
counter--;
}
public static void main(String [] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TestApp app = new TestApp();
//testing block removal
app.removeBlock(2);
}
});
}
}
The proper way would be: revalidate()
revalidate() method informs the layout manager that this component and all parents above it are marked as needing to be laid out. This means the Layout Manager will try to realign the components. Often used after removing components.
I would think that you will only know this if you are actually using Swing
As you said, is not good to use NullLayout. To fix your problem you only need to do two changes:
Change the layout to FlowLayout on the constructor, like this:
frame.setLayout(new FlowLayout());
Change the setBounds call to a setPreferredSize:
(grid.get(index)).setPreferredSize(new Dimension(width, height));
Now the FlowLayout will automatically align your items and you don't need to worry about it anymore.
in what way can this be programmed.
a UI box that displays random number between min and max value for 2 seconds then shows blank for 2 seconds then shows another random numer for 2 seconds then shows blank for 10 seonds and then repeats the cycle infitely until form closed. Font of the text to be configurable.
any help at all will be appreciated.
UPDATE after feedback
this is my progress so far. simple jpanel. now how do i add random number and timer
import javax.swing.JFrame;
import javax.swing.JPanel;
public class RandomSlide {
public static void main(String[]args)
{
//Create a JPanel
JPanel panel=new JPanel();
//Create a JFrame that we will use to add the JPanel
JFrame frame=new JFrame("Create a JPanel");
//ADD JPanel INTO JFrame
frame.add(panel);
//Set default close operation for JFrame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Set JFrame size to :
//WIDTH : 400 pixels
//HEIGHT : 400 pixels
frame.setSize(400,400);
//Make JFrame visible. So we can see it
frame.setVisible(true);
}
}
You have multiple languages in your tags, so I'm unsure what to repond with.
For java you'd make a JPanel with the appropriate UI elements and build a Timer instance to shoot off scheduled events every 2 seconds to update the value.
In VBA for Excel you'd have to do the same with a Form and Timer Control, however you may encounter more issues in Excel/VBA than in java.
Update 16/04/2010
You can actually sub-class the JPanel to clean up the code.
class RandomDialog extends JFrame
{
private Timer _timer;
private JPanel _container;
public RandomDialog()
{
_timer = new Timer();
_container = new JPanel();
// Etc...
}
}
From here you can instantiate your children and register an event on the timer to call a function on your class which generates the random number and displays it to a JLabel.
Then you can just call your dialog in your driver like so:
public static void main(string [] args)
{
RandomDialog rand = new RandomDialog();
rand.show();
}
Here is some code that will get you rolling.
Note that you could just extend a JLabel instead of JPanel. I used JPanel based on your question. Also, note that you may use timer.setDelay() API to change the timing. Also, you could stop the timer by a stop() call.
package answer;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class RandomPanel extends JPanel implements ActionListener {
private static final int TWO_SECONDS=2000;
private static final int MAX=99999;
private static final int MIN=0;
private Timer timer = new javax.swing.Timer(TWO_SECONDS, this);
private JLabel msgLabel;
Random generator = new Random();
public RandomPanel(Font f){
msgLabel = new JLabel();
msgLabel.setFont(f);
msgLabel.setText(rand());
add(msgLabel);
}
#Override
public void actionPerformed(ActionEvent e) {
msgLabel.setText(msgLabel.getText().equals("")?rand():"");
}
private String rand() {
//generate random beteween MIN & MAX
return Integer.toString((int) (MIN + Math.random() * ( MAX - MIN) + 0.5));
}
public void start(){
timer.start();
}
/**
* Rudimentary test
* #param args
*/
public static void main(String[] args) {
JFrame frame = new JFrame();
RandomPanel randomPanel = new RandomPanel(new Font("Serif", Font.BOLD, 50));
frame.getContentPane().add(randomPanel);
frame.setSize(400,300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
randomPanel.start();
}
}