Hi im making a Gui programme using a null layout and a setBounds() method for lay out . In the programme I want 25 strings printed out on the screen in random locations . I know that i could do this with a for loop however i have been trying this to no avail.
public void paint(Graphics g){
super.paint(g);
for(i=0;i<25;i++){
g.drawString("string name",Math.random()*250,Math.random()*250);
g.setColor(Color.RED);
}
}
I have been trying this and it has not been working so my question is is there some better way to do this or am i making some sort of obvious mistake.
You are not using the Math.random() part correctly try this instead:
import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
*
* #author David
*/
public class JavaApplication142 extends JFrame {
private int width = 300, height = 300;
public JavaApplication142() {
createAndShowUI();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JavaApplication142 jApp = new JavaApplication142();
}
});
}
private void createAndShowUI() {
setTitle("Painting");
setSize(width, height);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
addComponentsToContentPane(getContentPane());
setVisible(true);
}
private void addComponentsToContentPane(Container contentPane) {
Panel panel1 = new Panel();
contentPane.add(panel1);
}
class Panel extends JPanel {
private Random rand;
public Panel() {
rand = new Random();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < 25; i++) {
g.drawString("string name", (int) rand.nextInt(width), (int) rand.nextInt(height));
g.setColor(Color.RED);
}
}
}
}
This will help to get all the strings drawn within the region of the panel, although strings with varying length might go offscreen, just add some extra code to check the length of the string and set its co-ords appropriately
Related
I can draw static things to the screen, but I want to make them move with user key input. I don't know what to do, I've been searching and searching and haven't come up with an answer yet. Please help!
package com.Game.game;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Game extends JFrame
{
final static int width = 500;
final static int height = 500;
public int x = 250;
public int y = 250;
public int changeX = 10;
public int changeY = 10;
public static void main(String[] args)
{
new Game();
}
public Game()
{
KeyListener listener = new KeyListening();
addKeyListener(listener);
setFocusable(true);
DrawingStuff drawingstuff = new DrawingStuff();
add(drawingstuff);
setSize(width, height);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public class DrawingStuff extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawString("Hey there!", 300, 300);
g.setColor(Color.RED);
g.fillRect(x, y, 50, 50);
}
}
public class KeyListening implements KeyListener
{
DrawingStuff drawingstuff = new DrawingStuff();
#Override
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_UP)
{
y = y + changeY;
System.out.println("Hey");
drawingstuff.repaint();
}
}
#Override
public void keyReleased(KeyEvent e)
{
}
#Override
public void keyTyped(KeyEvent e)
{
}
}
public void update()
{
}
}
EDIT: Fixed it. I took away the key listener stuff in the constructor method, added a command to focus on "drawingstuff" in the constructor method, and, most importantly, added this bit of code to the end of the constructor method:
while(true)
{
drawingstuff.repaint();
}
The problem is that your KeyListening object has a reference to a different DrawingStuff object than the one you added to your UI inside the Game constructor.
public class KeyListening implements KeyListener
{
DrawingStuff drawingstuff = new DrawingStuff();
...
You should pass a DrawingStuff reference to the KeyListening instance so that it can tell the right object to repaint itself.
I want my button to change color on the mod == 0 of i % 3. The paintComponent(...) is called when the form is re-sized and index is passed in so I would think that this should change the color of my button ever time I start moving the form around the screen.
I have two components on the screen but both will not show up this might be a factor.
Code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class testform {
public static void main (String[] p) {
testBall3 j1 = new testBall3();
myButton b1 = new myButton("test");
JPanel testPane = new JPanel();
testPane.setBackground(Color.green);
testPane.setLayout(new BorderLayout());
j1.setPreferredSize(new Dimension(10,10));
//testPane.add(b1);
testPane.add(j1);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(testPane);
frame.pack();
frame.setSize(300, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
//j1.setColorBall(Color.BLACK);
//j1.repaint();
}
}
class myButton extends JButton {
private static final long serialVersionUID = 1L;
public myButton(String s) {
super(s);
}
public void setPrefferedSize(Dimension d) {
//this.setBounds(x, y, width, height)
setPreferredSize(d);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
index += i;
System.out.println(i);
if (index % 3 == 0) {
setBackground(Color.RED);
}
else {
setBackground(Color.BLACK);
}
}
}
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;
class testBall3 extends JComponent
{
private static final long serialVersionUID = 1L;
private Color colorBall = Color.red;
private int x1, y1;
int index = 0;
public void setColorBall(Color c)
{
this.colorBall = c;
}
public testBall3()
{
super();
System.out.println("MyBall (0)");
}
public testBall3(int x, int y, int diameter)
{
super();
this.setLocation(x, y);
this.setSize(diameter, diameter);
System.out.println("MyBall (1)");
x1 = x;
y1 = y;
}
public void paintBorder(Graphics g)
{
super.paintBorder(g);
g.setColor(Color.YELLOW);
g.fillOval(100, 100, 50, 50);
System.out.println("PaintBorder");
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(colorBall);
g.fillOval(x1, y1, 10, 10);
System.out.println("paintComponent");
}
public void paint(Graphics g)
{
super.paint(g);
paintComponent(g);
paintBorder(g);
paintChildren(g);
System.out.println("Paint");
}
}
But paintComponent doesn't take a second parameter, how are you passing it? I would think that instead of trying to pass i, you would want make i an attribute of class myButton instead and initialize it to 0 upon instantiation. That is, if you want each button to have its own counter. That sounds like the better plan.
You've got a lot of strange stuff going on...
You've got a component where you override all four major painting methods for no good reason.
In this component, your paint method override calls the super method, and calls the other 3 methods, which in essence will make those 3 methods be called twice.
You've got program logic (advancement of i) inside of your myButton's paintComponent method -- something that should never be done. You do not have full control over when or even if this method is called.
You are calling setBackground(...) from within paintComponent, something which shouldn't be done.
Your class names do not begin with an upper case letter, going against coding conventions, and potentially confusing anyone who tries to read your code.
If you want to change the state of a component on resize, use a ComponentListener.
e.g.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class Foo2 extends JPanel {
protected static final Color MAGIC_BACKGROUND = Color.red;
protected static final int MAGIC_NUMBER = 3;
private static final int TIMER_DELAY = 20;
private int index = 0;
private JButton myButton = new JButton("My Button");
protected int DELTA_SIZE = 2;
public Foo2() {
add(myButton);
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
index++;
if (index % MAGIC_NUMBER == 0) {
myButton.setBackground(MAGIC_BACKGROUND);
} else {
myButton.setBackground(null);
}
}
});
new Timer(TIMER_DELAY, new ActionListener() {
private Toolkit toolkit = Toolkit.getDefaultToolkit();
private int screenWidth = toolkit.getScreenSize().width;
private int screenHeight = toolkit.getScreenSize().height;
#Override
public void actionPerformed(ActionEvent e) {
if (getWidth() >= screenWidth || getHeight() >= screenHeight) {
((Timer)e.getSource()).stop();
} else {
int width = getWidth() + DELTA_SIZE;
int height = getHeight() + DELTA_SIZE;
setPreferredSize(new Dimension(width, height));
Window win = SwingUtilities.getWindowAncestor(Foo2.this);
win.pack();
win.setLocationRelativeTo(null);
}
}
}).start();
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Foo2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Foo2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I looked and the codes seems fine to me. Got an error but hopefully it's the source code, not something wrong with the cpu I have nor JDK.
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.*;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable {
public static int width = 300;
public static int height = width / 16*9;
public static int scale = 3;
private Thread thread;
private boolean running = false;
private JFrame frame;
public synchronized void start() {
running = true;
thread = new Thread(this, "Display");
thread.start();
}
public synchronized void stop() {
running = false;
try{
thread.join();
}catch(InterruptedException e){
e.printStackTrace();
}
}
public void run(){
while(running){
tick();
render();
}
}
public void tick() {
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if(bs==null){
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
bs.dispose();
bs.show();
}
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
frame = new JFrame();
}
public static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("Title");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
Then I got this error, even when I countlessly modified the source code I had.
Exception in thread "Display" java.lang.NullPointerException
at java.awt.Component$BltBufferStrategy.showSubRegion(Component.java:4307)
at java.awt.Component$BltBufferStrategy.show(Component.java:4255)
at com.thecherno.Rain.Game.render(Game.java:58)
at com.thecherno.Rain.Game.run(Game.java:39)
at java.lang.Thread.run(Thread.java:695)
Im starting to seem if it because of an outdated JDK. Current Version I have is JDK 6.
You state:
What Im trying to do is change color as seen in the render method. The background to be black.
Use Swing components such as a JComponent or JPanel.
Simply call setBackground(Color.BLACK) on the component will do.
You appear to be creating a game loop of some type. Consider using a Swing Timer for this.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Game2 extends JPanel {
private static final int PREF_W = 300;
private static final int PREF_H = PREF_W / 16 * 9;
private static final int SCALE = 3;
private static final Color BACKGROUND = Color.BLACK;
private static final int TIMER_DELAY = 20;
private Timer swingTimer;
public Game2() {
setBackground(BACKGROUND);
swingTimer = new Timer(TIMER_DELAY, new TimerListener());
swingTimer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// TODO: add any custom painting here
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W * SCALE, PREF_H * SCALE);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// TODO add code that gets called in game loop
}
}
private static void createAndShowGui() {
Game2 mainPanel = new Game2();
JFrame frame = new JFrame("Game2");
frame.setDefaultCloseOperation(JFrame.EXIT_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();
}
});
}
}
Note that this code is based on your stated requirements and what I'm guessing are other requirements based on your code. If there are further requirements not mentioned, please elaborate them for us.
Try using g.dispose(); followed by bs.show(); and then
g = (Graphics2D)bs.getDrawGraphics();. I know it looks weird, but you are emptying the canvas and then refilling it using your strategy. You may also need to do an initial check for g being null and initialize it before the first display loop.
I am trying to print the contents of an array of ints on the screen one at a time but keep the previous elements on screen, how can i do this? This is what i have so far which prints each element but doesnt keep the previous elements on the screen
import javax.swing.*;
import java.awt.*;
class test extends JFrame
{
JPanel panel;
public static void main(String[] args)
{
test obj = new test();
obj.makeAnim();
}
public void makeAnim() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Animate");
setResizable(false);
setSize(400,400);
Animate arr1 = new Animate();
Animate arr2 = new Animate();
//arr1.add(arr2);
getContentPane().add(arr1);
setVisible(true);
new Thread(arr1).start();
//new Thread(arr2).start();
}
}
class Animate extends JPanel implements Runnable
{
int j = 1;
int [] a = {1,2,3,5,6,7,2,1,10,99};
String temp;
public Animate()
{
setPreferredSize(new Dimension(400,400));
}
public void run()
{
for (int i = 0; i < 10; i++) {
temp = Integer.toString(a[i]);
j++;
repaint();
try {
Thread.sleep(2000);
} catch (Exception ex) {}
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.red);
g.setFont(new Font("Courier",Font.PLAIN, 20));
g.drawString(temp, (50+(j*10)), 50);
}
}
There a number of problems your are facing.
Painting in Swing is stateless, that means what ever was previously painting during one cycle, will not appear in the next, unless you physically paint it.
Take a look at Performing Custom Painting and Painting in AWT and Swing for more details.
Unless you synchronize you threads and paint routines (which is not advisable), you should never change the state of any variable that the paint methods may be reliant on out side of the Event Dispatching Thread.
Instead of using a Thread you should be using a javax.swing.Timer.
You may find Concurrency in Swing and Initial Threads informative
You shouldn't be relying on "magic" numbers (such as the character width offset), you should be relying on the underlying system to provide you with useful hints. In this case, you will want to look at FontMetrics
You should also avoid using setPreferredSize and override getPreferredSize
Below is an example of how I might solve the same problem...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
class TestPaint02 extends JFrame {
JPanel panel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
TestPaint02 obj = new TestPaint02();
obj.makeAnim();
}
});
}
public void makeAnim() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Animate");
setResizable(false);
setSize(400, 400);
Animate arr1 = new Animate();
getContentPane().add(arr1);
setVisible(true);
}
public class Animate extends JPanel {
int i = 0;
int[] a = {1, 2, 3, 5, 6, 7, 2, 1, 10, 99};
public Animate() {
Timer timer = new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
i++;
repaint();
if (i >= a.length) {
((Timer) e.getSource()).stop();
}
}
});
timer.setRepeats(true);
timer.setInitialDelay(0);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.setFont(new Font("Courier", Font.PLAIN, 20));
FontMetrics fm = g.getFontMetrics();
int x = 50;
int y = 50;
for (int loop = 0; loop < i; loop++) {
g.drawString(String.valueOf(a[loop]), x, y);
x += fm.stringWidth(String.valueOf(a[loop]));
}
}
}
}
I have some code for a Scrabble Game I am writing (actually rewriting), and it is split up into 3 classes so far. The Tile class seems to be generating a BorderFactory artifact when it is put in the window. Why is this artifact appearing, and how can I eliminate it?
*If you don't see the artifact, try resizing the window slowly.
Here is the Scrabble class.
import javax.swing.JFrame;
import java.awt.BorderLayout;
public class Scrabble extends JFrame implements Runnable
{
public Board board;
public Scrabble()
{
super("Scrabble!");
board = new Board();
addBorderLayoutObjects();
}
public void run()
{
makeSettings();
setVisible(true);
}
public void makeSettings()
{
setSize(850, 900);
setDefaultCloseOperation(EXIT_ON_CLOSE);
//this.setResizable(false);
}
public void addBorderLayoutObjects()
{
getContentPane().add(BorderLayout.CENTER, board);
}
public static void main(String[] args)
{
Scrabble s = new Scrabble();
javax.swing.SwingUtilities.invokeLater(s);
}
}
Here is the Board class.
import javax.swing.JPanel;
import java.awt.Point;
import java.awt.Color;
import java.awt.GridLayout;
public class Board extends JPanel
{
public Tile [][] board;
public Board()
{
super(new GridLayout(15, 15));
board = new Tile[15][15];
makeBoard();
}
public void makeBoard()
{
for(int k = 0; k < 225; k++)
{
board[k/15][k%15] = new Tile(new Color(0xCBC4A8), Color.BLACK);
}
for(int a = 0; a < 15; a++)
{
for(int l = 0; l < 15; l++)
{
add(board[a][l]);
}
}
}
}
And the Tile class.
import javax.swing.JPanel;
import javax.swing.BorderFactory;
import java.awt.Point;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
public class Tile extends JPanel implements MouseListener
{
private Color color;
private Color border;
public Tile(Color _color, Color _border)
{
color = _color;
border = _border;
}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseClicked(MouseEvent e){}
#Override
public void paintComponent(Graphics g)
{
g.setColor(color);
setBorder(BorderFactory.createLineBorder(border, 2));
}
}
This is your first problem (and possibly your second)
public void paintComponent(Graphics g)
{
g.setColor(color);
setBorder(BorderFactory.createLineBorder(border, 2));
}
Firstly, you must call super.paintComponent or take responsibility for its actions. This will clear and prepare the Graphics context for further painting.
Secondly, you should never modify any UI component from within a paintXxx method that may cause it be invalidated or repainted. Doing so will end you an infinite loop of burning CPU...
Set the border within the constructor or change it as the program needs, do not do so from within the paint method...
Updated with additional examples
When you need to change the border, simply call setBorder on the instance of the title you want change....
public Tile(Color _color, Color _border)
{
color = _color;
border = _border;
setBorder(BorderFactory.createLineBorder(border, 2));
}
or
Title tile = new Tile(Color.RED, Color.BLUE);
//...
title.setBorder(BorderFactory.createLineBorder(Color.GREEN, 2));
Check out How to use borders for more info...