Change backround color of JPanel multiple times - java

I am trying to make a little program that includes changing the color of a Panel time-based.
Right now I am just trying to do that part without the rest. So I just wrote a little Interface with only one panel and I want to change the color within a loop multiple times.
The problem is, even though the thread pauses for the correct amount of time, the color of the Panel doesn't change correctly. It changes just sometimes in the loop not every time.
my Interface Class:
import javax.swing.*;
import java.awt.*;
//creates the Interface
public class Interface extends JFrame {
private JPanel frame1;
public Interface (String titel) {
super(titel);
setSize(600, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.frame1 = new JPanel();
this.frame1.setPreferredSize(new Dimension (200, 200));
setLayout(new FlowLayout());
add(frame1);
this.setVisible(true);
}
public JPanel getFrame1() {
return frame1;
}
}
my Pause Class:
import java.util.TimerTask;
//supposed to pause the thread by #pause amount of milliseconds
public class Pause extends TimerTask {
private int pause;
public Pause(int pause){
this.pause = pause;
}
#Override
public void run() {
System.out.println("Timer"+ pause+" task started at:"+System.currentTimeMillis());
pause();
System.out.println("Timer task"+ pause+" ended at:"+System.currentTimeMillis());
}
public void pause() {
try {
Thread.sleep(this.pause);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
my Blink Class
import javax.swing.*;
import java.awt.*;
public class Blink {
private JPanel frame1;
public Blink(Interface anInterface){
this.frame1 = anInterface.getFrame1();
}
// blink should change the color of the JPanel inside my Frame.
// Its supposed to change to red for 200 ms
// and then to white again for 1000 ms.
// this should be repeated 10 times.
public void blink() {
Pause pause1 = new Pause(200);
Pause pause2 = new Pause(1000);
pause2.run();
int i = 1;
while(i <= 10){
i++;
frame1.setBackground(Color.red);
frame1.repaint();
pause1.run();
frame1.setBackground(Color.white);
frame1.repaint();
pause2.run();
}
}
public static void main ( String[] args ) {
Interface anInterface = new Interface("Title");
anInterface.setVisible(true);
Blink blink = new Blink(anInterface);
blink.blink();
}
}

According to Concurrency to Swing you cannot simply Thread.sleep the Thread where the GUI runs because it will freeze it, hence events cannot take place. Instead, for any kind of animation or long-heavy task (consider Thread.sleep as one), Swing Timers and Swing Workers should be used. In your case, a javax.swing.Timer fits better.
One example of its usage:
public class Blink {
private JPanel frame1;
private int pause1TimesRan;
private int pause2TimesRan;
private Timer pauser1, pauser2;
public Blink(Interface anInterface) {
this.frame1 = anInterface.getFrame1();
//Create pauser 1 with delay 200ms
pauser1 = new Timer(200, e -> {
if (pause1TimesRan == 10) {
pauser1.stop();
return;
}
Color color = randomColor();
frame1.setBackground(color);
System.out.println("Pauser #1 changed background to: " + color);
pause1TimesRan++;
});
//Create pauser 2 with delay 1000ms
pauser2 = new Timer(1000, e -> {
if (pause2TimesRan == 10) {
pauser2.stop();
return;
}
Color color = randomColor();
frame1.setBackground(color);
System.out.println("Pauser #2 changed background to: " + color);
pause2TimesRan++;
});
}
private static Color randomColor() {
return new Color((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255));
}
public void blink() {
pauser1.start();
pauser2.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
Interface anInterface = new Interface("Title");
anInterface.setVisible(true);
Blink blink = new Blink(anInterface);
blink.blink();
});
}
static class Interface extends JFrame {
private JPanel frame1;
public Interface(String titel) {
super(titel);
setSize(600, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.frame1 = new JPanel();
this.frame1.setPreferredSize(new Dimension(200, 200));
setLayout(new FlowLayout());
add(frame1);
this.setVisible(true);
}
public JPanel getFrame1() {
return frame1;
}
}
}
One off-topic advice is to name your methods (and variables) properly. You called the method getFrame1(), but it is actually a JPanel and not a JFrame. So, a better name could be getPanel(). Also, about the SwingUtilities.invokeLater part, read What does SwingUtilities.invokeLater does.

Related

Using paintComponent() on a JFrame canvas being altered by a separate GUI

I am trying to make a JComponent application which uses two JFrames, one frame with alterable sliders and textfields for the graphical display of a firework on the second. When the "fire" button is pressed, a rendering of the firework should appear. However, I have found through placing strategic print statements, that my paintComponent() method does not run even though the conditional statement wrapping the code is satisfied. I have also double checked all of my other methods to ensure that correct values are generated at the correct times. After looking through all of the JComponent literature and questions I could find, I'm afraid I cannot get it to work - this problem is most likely derived from my lack of familiarity with the library. That being said, any advice no matter how rudimentary, will be much appreciated. Abridged code is below:
*The swing timer may also be the issue for I am not sure if I have used it correctly
[fireworksCanvas.java]
public class fireworkCanvas extends JComponent implements ActionListener{
private static final long serialVersionUID = 1L;
private ArrayList<Ellipse2D> nodes = new ArrayList<Ellipse2D>();
private ArrayList<Line2D> cNodes = new ArrayList<Line2D>();
private ArrayList<QuadCurve2D> bCurves = new ArrayList<QuadCurve2D>();
private int[] arcX;
private int[] arcY;
private Color userColor;
private Random rand = new Random();
private int shellX, shellY, fType, theta, velocity;
private Timer timer;
private int time;
private double g = -9.8; //gravity in m/s
public boolean explosivesSet;
public fireworkCanvas() {
time = rand.nextInt(3000) + 2000;
timer = new Timer(time, this); // 5 seconds
timer.start();
fType = 0;
}
#Override
public void paintComponent(Graphics g){
if (explosivesSet) {
System.out.println("fType" + fType);
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
g.setColor(Color.BLACK);
g.drawPolyline(arcX, arcY, arcX.length);
for (Ellipse2D e : nodes) {
System.out.println("painting nodes"); // NEVER PRINTS
g.setColor(userColor);
g.fillOval(shellX + (int) e.getX(), shellY + (int) e.getY(), (int) e.getWidth(), (int) e.getHeight());
}
for (Line2D l: cNodes) {
System.out.println("painting cNodes"); // NEVER PRINTS
g.setColor(determineColor("l"));
g.drawLine(shellX + (int) l.getX1(), shellY + (int) l.getY1(), shellX + (int) l.getX2(), shellY + (int) l.getY2());
}
for (QuadCurve2D c: bCurves) {
System.out.println("painting curves"); // NEVER PRINTS
g.setColor(determineColor("c"));
g2D.draw(c);
}
}
}
public Color determineColor(String type) {
// returns color
}
public void setExplosives() {
if (fType != 5 && fType != 0) {
nodes.clear(); // clears three array lists with FW components
cNodes.clear(); // these are the components to paint for the
bCurves.clear(); // firework explosion graphic
setArc(); // stores path of shell for a polyLine to be drawn
// builds and generates components for FW based on type chosen (fType)
setExplosivesSet(true);
repaint();
}
}
public void setArc() {
// builds int[] for shellX, shellY
}
#Override
public void actionPerformed(ActionEvent e) {
// nothing is here??
// should I use the action performed in some way?
}
[GUI.java]
public class GUI extends JFrame implements ActionListener, ChangeListener, ItemListener, MouseListener{
private static JFrame canvasFrame = new JFrame("Canvas");
private fireworkCanvas canvas = new fireworkCanvas();
private Choice fireworkChooser = new Choice();
private JSlider launchAngle = new JSlider();
private JSlider velocity = new JSlider();
private JSlider r = new JSlider();
private JSlider g = new JSlider();
private JSlider b = new JSlider();
private JPanel panel = new JPanel();
private JButton button = new JButton("Fire!");
private JLabel launchLabel = new JLabel("Launch Angle ");
private JLabel velocityLabel = new JLabel("Velocity ");
private JLabel rLabel = new JLabel("Red ");
private JLabel gLabel = new JLabel("Green ");
private JLabel bLabel = new JLabel("Blue ");
public static int fHeight = 500;
public static int fWidth = 500;
public GUI() {
this.add(panel);
panel.add(button);
panel.add(fireworkChooser);
panel.add(launchAngle);
panel.add(launchLabel);
panel.add(velocity);
panel.add(velocityLabel);
panel.add(r);
panel.add(rLabel);
panel.add(g);
panel.add(gLabel);
panel.add(b);
panel.add(bLabel);
addActionListener(this);
BoxLayout bl = new BoxLayout(getContentPane(), BoxLayout.Y_AXIS);
setLayout(bl);
fireworkChooser.addItemListener(this);
launchAngle.addChangeListener(this);
velocity.addChangeListener(this);
r.addChangeListener(this);
g.addChangeListener(this);
b.addChangeListener(this);
button.addActionListener(this);
fireworkChooser.add("Firework 1");
fireworkChooser.add("Firework 2");
fireworkChooser.add("Firework 3");
fireworkChooser.add("Firework 4");
fireworkChooser.add("Super Firework");
launchAngle.setMinimum(1);
launchAngle.setMaximum(90);
velocity.setMinimum(1);
velocity.setMaximum(50);
r.setMinimum(0);
r.setMaximum(255);
g.setMinimum(0);
g.setMaximum(255);
b.setMinimum(0);
b.setMaximum(255);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 200);
}
#Override
public void stateChanged(ChangeEvent e) {
// sets FW variables
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == button) {
canvas.setfType(fireworkChooser.getSelectedIndex()+1);
canvas.setExplosives();
canvas.repaint();
canvas.setExplosivesSet(false);
System.out.println("button fired");
}
}
public static void createAndShowGUI() {
GUI gui = new GUI();
gui.pack();
gui.setLocationRelativeTo(null);
gui.setVisible(true);
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fireworkCanvas canvas = new fireworkCanvas();
canvasFrame.pack();
canvasFrame.add(canvas);
canvasFrame.setLocationRelativeTo(null);
canvasFrame.setVisible(true);
canvasFrame.setSize(fWidth, fHeight);
canvasFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
First of all:
public fireworkCanvas()
Class names should start with an upper case character. All the other classes in your code follow this rule. Learn by example.
private Choice fireworkChooser = new Choice();
Choice is an AWT component don't mix AWT components in a Swing application. Use a JComboBox.
that my paintComponent() method does not run
fireworkCanvas canvas = new fireworkCanvas();
canvasFrame.pack();
canvasFrame.add(canvas);
You add the canvas to the frame AFTER you pack() the frame, so the size of the canvas is (0, 0) and there is nothing to paint.
The canvas should be added to the frame BEFORE the pack() and you should implement getPreferredSize() in your FireworkCanvas class so the pack() method can work properly.
Read the section from the Swing tutorial on Custom Painting for the basics and working examples to get you started.

KeyListener in a new thread for game input capture

I am making an old school Snake game in Java with Swing. I've read that in order to capture input in real time I need to run my game loop in a new thread so that It's wait() method won't interfere with the input capture. I've made InputCapture class implementing KeyListener and I've implemented keyPressed() method like that:
public class InputCapture implements KeyListener {
private Direction capturedDirection;
//Methods
#Override
public void keyPressed(KeyEvent e) {
boolean inputConsoleDebug = true;
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
capturedDirection = Direction.left;
if (inputConsoleDebug) System.out.println("LEFT");
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
capturedDirection = Direction.right;
if (inputConsoleDebug) System.out.println("RIGHT");
} else if (e.getKeyCode() == KeyEvent.VK_UP) {
capturedDirection = Direction.up;
if (inputConsoleDebug) System.out.println("UP");
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
capturedDirection = Direction.down;
if (inputConsoleDebug) System.out.println("DOWN");
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
public Direction getCapturedDirection() {
return capturedDirection;
}
}
Then I've made Game class extending Thread and I've put game loop code into run() method:
public class Game extends Thread {
private Board board;
private Snake snake;
private JFrame frame;
private long waitTime;
private int difficultyStep;
private Direction inputDirection;
private InputCapture inputManager;
//Constructors
Game(Dimension boardSize) {
//Set difficulty
int applesToWin = boardSize.width * boardSize.height - 1;
final int easiestWaitTime = 1000;
final int hardestWaitTime = 100;
difficultyStep = (easiestWaitTime - hardestWaitTime) / applesToWin;
waitTime = easiestWaitTime;
//Set starting point
final int startingPointX = boardSize.width / 2;
final int startingPointy = boardSize.height / 2;
//Set board and snake
board = new Board(boardSize);
snake = new Snake(board, startingPointX, startingPointy);
//Set window Frame
frame = new JFrame(SnakeApplication.getApplicationName());
frame.setContentPane(board);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setResizable(false);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
super.windowClosing(e);
interrupt();
}
});
//Set input manager
inputManager = new InputCapture();
frame.addKeyListener(inputManager);
inputDirection = null;
}
//Methods
public void run() {
board.spawnApple();
while (!isWon()) {
try {
sleep(waitTime);
} catch (InterruptedException e) {
return;
}
try {
inputDirection = inputManager.getCapturedDirection();
snake.move(inputDirection);
} catch (LosingMove e) {
showGameOverDialog();
return;
}
board.repaint();
}
showWinDialog();
}
JFrame getFrame() {
return frame;
}
private boolean isWon() {
for (int row = 0; row < board.getFields().length; row++) {
for (int col = 0; col < board.getFields()[0].length; col++) {
if (!(board.getFields()[row][col].getContent() instanceof Snake.SnakeNode)) return false;
}
}
return true;
}
private void showGameOverDialog() {
JFrame gameOverFrame = new JFrame();
JOptionPane.showMessageDialog(gameOverFrame, "Game Over!");
}
private void showWinDialog() {
JFrame gameOverFrame = new JFrame();
JOptionPane.showMessageDialog(gameOverFrame, "You Win!");
}
}
In my MainMenu class I've made startNewGame() method that is called when New Game button is clicked. This method creates Game object and starts a new thread by calling start() method.
public class MainMenu {
//Form components references
private JButton exitButton;
private JFrame frame;
private JPanel mainPanel;
private JButton newGameButton;
private JLabel titleLabel;
//Constructors
MainMenu() {
//Set window Frame
frame = new JFrame(SnakeApplication.getApplicationName());
frame.setContentPane(mainPanel);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setResizable(false);
frame.pack();
newGameButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
startNewGame();
}
});
exitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
exitGame();
}
});
}
JFrame getFrame() {
return frame;
}
private Dimension showBoardSizeDialog() {
Frame boardSizeFrame = new Frame();
int width = Integer.parseInt(JOptionPane.showInputDialog(boardSizeFrame, "Set board's width:"));
int height = Integer.parseInt(JOptionPane.showInputDialog(boardSizeFrame, "Set board's height:"));
return new Dimension(width, height);
}
private void startNewGame() {
Dimension boardSize = showBoardSizeDialog();
frame.setVisible(false);
Game game = new Game(boardSize);
game.getFrame().setVisible(true);
//Starting game loop in a new thread
game.start();
try {
game.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
frame.setVisible(true);
}
}
But when testing the app it gets stuck in the game loop and doesn't capture input at all. Why? I was trying to debug It, but every time the new thread is started it gets stuck in game loop. The Board itself is painted only when main thread ends its execution. Why? Shouldn't It be repainted many times during game loop if execution is stucked there?
Also, I've made thread interrupt when frame's close button is clicked (red X button) so execution could get back to MainMenu and reappear it, but clicking red close button has no effect.
The program freezes because of the call to game.join() in startNewGame. join keeps the thread it was called from from continuing execution until the thread it was called on dies. In your situation, join defeats the purpose of using another thread, so you should just remove that.
There are other issues, though. You probably shouldn't use a thread. You should probably use a Swing Timer. Swing isn't thread-safe, and I can already see a few places where your code isn't thread-safe either. (For example, you need to declare capturedDirection as volatile.) Writing correct multi-threaded code with Swing is a bit complicated and it would be much simpler to just use a timer.
Otherwise, if you don't use a timer, you need to use e.g. synchronization between the game thread (which writes to shared game state) and the Swing thread which does painting (and presumably reads from shared game state). If you don't, you may run in to problems that are hard to diagnose.
Also see The Use of Multiple JFrames: Good or Bad Practice?
You should make your Game class extending Runnable instead of Thread.
Then to have the game in a different thread:
Game theGame = ... // initialization code here
new Thread(theGame).start();

JPanel not displaying after button pressed in another JPanel

Hi I'm building a game which includes 3 JPanels on a JFrame, a Startscreen, a DrawingPanel and a GameOver screen. If I just create the DrawingPanel and tell the GameController class to begin updating it works fine, but if I create a StartScreen with a button to start the game, then when I press the start game button the game window does not display, although the game code runs.
EDIT:
I have created a new program which mimics the creation of the JPanels, but excludes all of the game code to make it a bit simpler to follow. Below I have included all the relevant classes:
This class creates a JFrame and two JPanels. It also runs the code that updates the game state and tells the DrawingPanel to repaint.
public class TestController{
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
private final int FRAME_WIDTH = (int)screenSize.getWidth();
private final int FRAME_HEIGHT = (int)screenSize.getHeight();
public boolean gameStarted = false;
private JFrame gameWindow;
private TestDrawingPanel myDrawingPanel;
private TestStartGame startGame;
int counter;
Set<Rectangle> rects;
//creates a JFrame and all the JPanels
public TestController(String title)
{
gameWindow = new JFrame(title);
gameWindow.setSize(FRAME_WIDTH, FRAME_HEIGHT);
gameWindow.setVisible(true);
gameWindow.setResizable(false);
gameWindow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
startGame = new TestStartGame(getAvailableWidth(), getAvailableHeight());
startGame.addAL(new StartButton());
myDrawingPanel = new TestDrawingPanel(getAvailableWidth(), getAvailableHeight());
gameWindow.add(startGame);
gameWindow.add(myDrawingPanel);
myDrawingPanel.setVisible(false);
myDrawingPanel.setEnabled(false);
rects = new HashSet();
}
private int getAvailableWidth()
{
return gameWindow.getWidth() - gameWindow.getInsets().left - gameWindow.getInsets().right;
}
private int getAvailableHeight()
{
return gameWindow.getHeight() - gameWindow.getInsets().top - gameWindow.getInsets().bottom;
}
//starts the game running
public void startTheGame()
{
myDrawingPanel.setEnabled(true);
startGame.setVisible(false);
startGame.setEnabled(false);
myDrawingPanel.setVisible(true);
gameStarted = true;
update();
}
public boolean getGameStarted()
{
return gameStarted;
}
//loop that runs the game code
public void update()
{
counter = 0;
while(gameStarted)
{
updatePictureState();
myDrawingPanel.draw(rects);
myDrawingPanel.repaint();
}
}
//updates the game state
public void updatePictureState()
{
rects.clear();
for (int i = counter + 10; i < counter + 100; i = i + 10)
{
rects.add(new Rectangle(i,i,10,10));
}
}
//an action listener to be added to the start screen
private class StartButton implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
Object buttonPressed = e.getSource();
if(buttonPressed.equals(TestStartGame.start))
{
startTheGame();
}
}
}
}
This class is an extended JPanel with a single button to start the game:
public class TestStartGame extends JPanel{
private final JPanel buttons;
public static JButton start;
//creates a JPanel with a single button to start the game
public TestStartGame(int width, int height)
{
setSize(width, height);
setLayout(new GridLayout(2,1));
setBackground(Color.GREEN);
buttons = new JPanel();
buttons.setSize(width, height / 2);
buttons.setBackground(Color.red);
start = new JButton("Start");
buttons.add(start);
add(buttons, BorderLayout.SOUTH);
}
//adds an action listener to the button
public void addAL(ActionListener al)
{
start.addActionListener(al);
}
}
This class is an extended JPanel and acts as the main screen for the game, being updated to with each cycle of the game to display it's current state:
public class TestDrawingPanel extends JPanel{
Set<Rectangle> drawSet;
//creates the drawing panel and sets the size and background
public TestDrawingPanel(int width, int height)
{
setSize(width, height);
this.setBackground(Color.CYAN);
drawSet = new HashSet();
}
public void draw(Set<Rectangle> platforms)
{
drawSet.clear();
drawSet = platforms;
}
//draws the game window
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
System.out.println("works here");
g.setColor(Color.red);
for (Rectangle r : drawSet)
{
g.fillRect((int)r.getX(), (int)r.getY(), (int)r.getWidth(), (int)r.getHeight());
}
}
}
If I just add the TestDrawingPanel, it displays fine, but if I start with a TestStartScreen then when I click the start game button the TestStartScreen does not disappear and the TestDrawingPanel never displays. Interestingly, if I have both screens but do not call the update method is TestController then the start game button works correctly and the TestDrawingPanel displays, although obviously nothing happens as the update method is where the game state is changed.
I have discovered the problem is that if the TestDrawingPanel is not the only JPanel created then the call to repaint it fails.
Here:
Thread.sleep(20);
You are most likely sleeping on the Event Dispatcher Thread. That will freeze your whole application. You have to step back and look into invokeLater to ensure "correct" threading within your UI.
Problem solved courtesy of #Andrew-Thompson:
"while(gameStarted) .. No, no a thousand times no. An infinite loop will likely freeze the GUI. Use a Swing based Timer to call those code statements in the loop, in the actionPerformed method of an ActionListener"

Grapghic doesn't move

I'm trying to make a code that will move a red ball with JButtons (and later add keybinders). There are no problems when I compile and when I run I see the ball but the JButtons won't affect him. I think the problem might be that the ball is drawed only once and then is called again and again without being drawed in the new position but I don't know how to fix that.
1) does anybody know how I can fix that?
2) is there a way to change the shape of a JPanel to a ball? (that would probably be a simpler way to move him)
package il.co.atlantis;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class KeyBinders implements ActionListener {
boolean right=true, left=false, up=false, down=false, inGame=true;
JPanel backgroundPanel, bannerPanel, scorePanel, applePanel;
JLabel currentScoreLabel, highestScoreLabel;
JButton upButton, downButton, rightButton, leftButton;
long millis =System.currentTimeMillis(), millisn =System.currentTimeMillis();
public static final int WID = 10, HEI = 10;
public static int x1 = 100, y1 = 100;
public class MyGraphics extends JComponent {
private static final long serialVersionUID = 1L;
MyGraphics() {
setPreferredSize(new Dimension(700, 500));
}
public void moveRight(){
++x1;
}
public void moveLeft(){
--x1;
}
public void moveUp(){
--y1;
}
public void moveDown(){
++y1;
}
public void paintComponent(Graphics g){
super.paintComponents(g);
g.setColor(Color.red);
g.fillOval(x1, y1, WID, HEI);
}
}
public JPanel CreateContentPane (){
JPanel totalGUI = new JPanel();
totalGUI.setLayout(null);
backgroundPanel = new JPanel();
backgroundPanel.setBackground(Color.black);
backgroundPanel.setLocation(100, 10);
backgroundPanel.setSize(700, 500);
totalGUI.add(backgroundPanel);
upButton = new JButton("up");
upButton.setLocation(0,0);
upButton.setSize(50,50);
totalGUI.add(upButton);
downButton = new JButton ("down");
downButton.setLocation(0,50);
downButton.setSize(50,50);
totalGUI.add(downButton);
rightButton = new JButton("right");
rightButton.setLocation(0,100);
rightButton.setSize(50,50);
totalGUI.add(rightButton);
leftButton = new JButton("left");
leftButton.setLocation(0,150);
leftButton.setSize(50,50);
totalGUI.add(leftButton);
MyGraphics tr = new MyGraphics();
tr.setLocation(100, 100);
backgroundPanel.add(tr);
return totalGUI;
}
public void ActionPerformed(ActionEvent h){
if(h.getSource() == upButton) {
--y1;
}
else if(h.getSource() == downButton){
++y1;
}
else if(h.getSource() == leftButton){
--x1;
}
else if(h.getSource() == rightButton){
++x1;
}
}
private static void createAndShowGUI() {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("[=] JButton Scores! [=]");
//Create and set up the content pane.
KeyBinders demo = new KeyBinders();
frame.setContentPane(demo.CreateContentPane());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(280, 190);
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public KeyBinders() {
// TODO Auto-generated constructor stub
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
When you invoke action event, actionPerformed() function gets called, as you did. You have change the drawing position too. you need to call Component.repaint() which tells Swing t hat the entire component, whichever one you specified to be repainted , must be updated . So add this function calling in your code. For example:
public void ActionPerformed(ActionEvent h){
if(h.getSource() == upButton) {
--y1;
}
else if(h.getSource() == downButton){
++y1;
}
else if(h.getSource() == leftButton){
--x1;
}
else if(h.getSource() == rightButton){
++x1;
}
repaint();
}
Check the tutorial: Performing Custom Painting.
There's a method called repaint() you should familiarize yourself with.
When called on a component (such as a JFrame) it'll repaint all the components within. Naturally you need to call it if you want your changes to become visible on the screen.
As for custom painting, you shouldn't use a Component at all, rather use the Graphics.fillRect/fillOval etc. methods to just draw what you want.
See here for the custom painting tutorial.

Run and pause a GUI background thread by clicking a button

I need to run a background thread in my Java GUI that only runs when I click a button and pauses when I click that button again. I am not exactly sure how to set this up, but I have placed a thread in my constructor and the while loop within is set to go through when I set a specific boolean to TRUE. One button switches from setting this boolean TRUE or FALSE.
Everything else I have in this GUI works fine. When I tried debugging the thread, it actually works as I step through the thread but nothing when I try running the GUI completely. The GUI is rather large so I'm gonna put up a portion of the constructor and the action listener of the button. The rest of the code is unnecessary since it works just fine. I need to know what I am doing wrong here:
public BasketballGUI() {
// certain labels and buttons
Thread runningSim = new Thread() {
public void run() {
while(simRun) {
// do stuff here
}
}
};
runningSim.start();
}
// other GUI stuff
// actionListener that should run the thread.
class SimButtonListener implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
if(!simRun) {
simRun = true;
sim.setText("Pause Simulator");
}
else if(simRun) {
simRun = false;
sim.setText("Run Simulator");
}
// other stuff in this actionListener
}
}
Establish a Swing based Timer with an ActionListener that will be called repeatedly.
In the actionPerformed(ActionEvent) method call repaint().
Start the timer (Timer.start()) when the user clicks Start
Stop the timer (Timer.stop()) when the user clicks Stop
If you cannot get it working from that description, I suggest you post an SSCCE of your best attempt.
I thought I had one 'lying around'.. Try this working SSCCE which uses images created in this SSCCE.
I could see this background thread useful for a Java GUI when handling button events to affect something like a text area or progress bar.
For the sake of argument, I will build you a tiny GUI that affects a Text Area. I hope this helps you.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.*;
public class TestClass extends JPanel {
super("TestClass - Title");
private AtomicBoolean paused;
private JTextArea jta;
private JButton btn;
private Thread thread;
public TestClass() {
paused = new AtomicBoolean(false);
jta = new JTextArea(100, 100);
btn = new JButton();
initialize();
}
public void initialize() {
jta.setLineWrap(true);
jta.setWrapStyleWord(true);
add(new JScrollPane(jta));
btn.setPreferredSize(new Dimension(100, 100));
btn.setText("Pause");
btn.addActionListener(new ButtonListener());
add(btn);
Runnable runnable = new Runnable() {
#Override
public void run() {
while(true) {
for(int i = 0; i < Integer.MAX_VALUE; i++) {
if(paused.get()) {
synchronized(thread) {
try {
thread.wait();
} catch(InterruptedException e) {
}
}
}
}
jta.append(Integer.toString(i) + ", ");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
};
thread = new Thread(runnable);
thread.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 30);
}
class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent event) {
if(!paused.get()) {
btn.setText("Start");
paused.set(true);
} else {
btn.setText("Pause");
paused.set(false);
synchronized(thread) {
thread.notify();
}
}
}
}
}
Main class to call everything.
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class MainClass {
public static void main(final String[] arg) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestClass());
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
});
}
}
I did not test this code to see if it works exactly, Its main goal is to break you through your coders block and use my components to fix your issue. Hope this helped. Need anything else Email me at DesignatedSoftware#gmail.com

Categories

Resources