java clear a JPanel with a transparent background - java

I have been attempting to create a screen saver program. Essentially, there are multiple circles that move around the screen. However, when I make the background transparent I cannot use clearRect() anymore because that will force the background to be white. Is there any way to clear the already drawn circles while keeping the background transparent?
class ScreenSaver extends JPanel implements ActionListener {
static Timer t;
Ball b[];
int size = 5;
ScreenSaver() {
Random rnd = new Random();
b = new Ball[size];
for (int i = 0; i < size; i++) {
int x = rnd.nextInt(1400)+100;
int y = rnd.nextInt(700)+100;
int r = rnd.nextInt(40)+11;
Color c = new Color(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
int dx = rnd.nextInt(20)-10;
if (dx == 0)
dx++;
int dy = rnd.nextInt(20)-10;
if (dy == 0)
dy++;
b[i] = new Ball(x, y, r, c, incR, incG, incB, dx, dy);
}
}
public void actionPerformed(ActionEvent e) {
repaint();
}
public void paintComponent(Graphics g) {
//g.clearRect(0, 0, 1600, 900);
for (int i = 0; i < size; i++) {
if (b[i].x + b[i].r+b[i].dx >= 1600)
b[i].dx *= -1;
if (b[i].x - b[i].r+b[i].dx <= 0)
b[i].dx *= -1;
if (b[i].y + b[i].r+b[i].dy >= 900)
b[i].dy *= -1;
if (b[i].y - b[i].r+b[i].dy <= 0)
b[i].dy *= -1;
b[i].x += b[i].dx;
b[i].y += b[i].dy;
g.fillOval(b[i].x-b[i].r, b[i].y-b[i].r, b[i].r*2, b[i].r*2);
}
}
}
class Painter extends JFrame{
Painter() {
ScreenSaver mySS = new ScreenSaver();
mySS.setBackground(new Color(0, 0, 0, 0)); //setting the JPanel transparent
add(mySS);
ScreenSaver.t = new Timer(100, mySS);
ScreenSaver.t.start();
setTitle("My Screen Saver");
setExtendedState(JFrame.MAXIMIZED_BOTH);
setLocationRelativeTo(null);
setUndecorated(true);
setBackground(new Color(0, 0, 0, 0)); //setting the JFrame transparent
setVisible(true);
}
}

Don't use alpha based colors with Swing components, instead, simply use setOpaque(false)
Change
mySS.setBackground(new Color(0, 0, 0, 0));
to
mySS.setOpaque(false)
Swing only knows how to paint opaque or transparent components (via the opaque property)
As a personal preference, you should also be calling super.paintComponent before you do any custom painting, as your paintComponent really should be making assumptions about the state

Related

I want to iterate through an arraylist of Images

I have an arraylist of images, I am trying to have each image, slide through the screen repeatedly..
public class GraphicsT extends JPanel implements ActionListener {
Timer timer = new Timer(1, this);
Image image;
Image image2;
int x1;
int x2;
int y1;
int y2;
int num;
List<String> imageList1 = new ArrayList<String>();
GraphicsT() {
imageList1.add("image/java.jpeg");
imageList1.add("image/slide.jpg");
imageList1.add("image/giphy.gif");
x1 = 100;
y1 = 100;
x2 = 200;
y2 = 200;
num = 0;
}
public void paint(Graphics g) {
ImageIcon i2 = new ImageIcon("image/street.jpg");
image2 = i2.getImage();
g.drawImage(image2, 0, 0, null);
for (int i = 1; i < imageList1.size(); i++) {
ImageIcon im = new ImageIcon(imageList1.get(i));
image = im.getImage();
g.drawImage(image, x1, y1, x2, y2, 100, 120, 120, 240, null);
System.out.println(imageList1.get(i));
}
timer.start();
}
#Override
public void actionPerformed(ActionEvent e) {
num++;
if (num % 100 == 0) {
x1 = x1 + 10;
x2 = x2 + 10;
}
if (x2 >= 570) {
// end reached
x1 = 0;
x2 = 100;
}
repaint();
}
}
public class GraphicsApp extends JFrame {
GraphicsT gt = new GraphicsT();
public GraphicsApp() {
this.setTitle("Multiple Slide");
this.setSize(450, 400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.add(gt);
}
public static void main(String[] args) {
new GraphicsApp();
}
}
my current code can only pick one image, but i want a situation whereby after the first images goes out of the screen, the second image can follow, then the third, and so on...
Please help will be much appreciated.
Several issues:
you should be overriding paintComponent() not paint() and you invoke super.paintComponent(...) to make sure the background is painted first.
a painting method is for painting only. You should NOT be doing I/O to read the images. The images should be read in the constructor of your class
You should NOT start the Timer in the painting method. The Timer is started in the constructor.
Your basic painting code is wrong. You should have a couple of instance variables, a) the "currentImage", b) "imageNumber". Then in the painting method you simply paint the currentImage at the x/y location.
In the ActionListener, when the image is off the screen you increment the "imageNumber" and copy the image from the ArrayList to the "currentImage". Then you reset the x/y location so the image is painted starting from the right.
When the "imageNumber" reaches the end of the ArrayList you reset it back to 0.

Alternative to pack()

I am making a terrain generator, and I am loading upwards of a million JPanels into my frame, and that takes more than an hour. I have isolated most of the problem in the pack() method. Are there any alternatives to using it, or maybe a way to do it faster? Here is some of my code:
setLayout(new FlowLayout(0, 0, 0));
System.out.println("Generating...");
Chunk spawnChunk = new Chunk(this.mapSize);
System.out.println("Done\nAdding Tiles...");
for (double[] row : Chunk.tileData) {
for (double d : row) {
int v = (int) (20 - d / 500);
if(v < 0) {
v = 0;
}
else if (v > 20){
v = 20;
}
add(new Tile(v, tileSize));
}
}
System.out.println("Done\nPacking...");
pack();
System.out.println("Done\nRepainting...");
repaint();
System.out.println("Done");
Note: Tile is just a JPanel with a background color
That is a lot of JPanels. My recommendation - if 'Tile is just a JPanel with a background color', then just do the custom drawing yourself using a single JPanel. Override the paintComponent method and use the passed Graphics object to draw the colors.
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
for ( int i = 0; i < numberOfTiles; i++ ){
g.setColor(colorOfCurrentTile);
g.fillRect(left, top, width, height);
}
}

Mini Tennis Game using Threads Java

I am having a some difficulty with developing of my code. Since I am not too advanced with Java I need some help. I am trying to develop Mini Tennis game using Threads. The aim of this game is to catch the balls moving on the window with the paddle that can be controlled with the left and right buttons on the keyboard.
Those balls should move diagonally on the window and when they touch to any of the corner (out of bottom) they should change their ways like light reflection. Apart from this, when a ball touches to one of the obstacles they should change their ways as well.
Paddle on the bottom of the window can be controlled with left and right keys.The task of the player is to catch the balls. The number of balls that the user catches will be shown on the Score part with the total number of balls going to the bottom corner.
User may need to save the state of the game. When the user clicks to the “save game” button; ball locations and score should save to the file. And when the user clicks to the open button, the state of game should be reloaded.
My source code files are:
public class BallPanel extends JPanel implements Runnable {
int RED, GREEN, BLUE;
int Xdirection = 1, Ydirection = 1;
boolean pleaseWait = false;
BallPanel(int X, int Y){
locateBall(X, Y, 30, 30);
/* Random r = new Random();
RED = r.nextInt(255);
GREEN = r.nextInt(255);
BLUE = r.nextInt(255);
*/
}
public void paint(Graphics g){
int panelWidth = this.getWidth();
int panelHeight = this.getHeight();
// g.setColor( new Color(RED, GREEN, BLUE ));
g.setColor(Color.ORANGE);
g.fillOval(panelWidth/2, panelHeight/2,panelWidth/2, panelHeight/2);
}
public void locateBall(int x, int y, int width, int height){
setBounds(x, y, width, height);
repaint();
}
public void run() {
int width = this.getWidth();
int height = this.getHeight();
Random r = new Random();
while(true){
if(!pleaseWait){
int lastX = this.getX();
int lastY = this.getY();
if (lastX > 675) Xdirection = -1;
if (lastY > 485) Ydirection = -1;
if (lastX < -5) Xdirection = 1;
if (lastY < -5) Ydirection = 1;
/* if(lastX > 280 && lastY > 170){
Xdirection = -1;
Ydirection = -1;
}
*/
locateBall(lastX + Xdirection*r.nextInt(3),
lastY + Ydirection*r.nextInt(3),
width, height );
}
try{
Thread.sleep(5);
}catch(Exception e){};
}
}
}
public class BallWindow extends JFrame implements ActionListener{
JButton btnStop = new JButton("STOP");
JButton btnSave = new JButton("SAVE");
Vector<BallPanel> ballVector = new Vector<BallPanel>();
JPanel p1 = createPanel(280, 200, 200, 20, Color.gray);
JPanel p2 = createPanel(280, 300, 200, 20, Color.gray);
JPanel bottomp = createPanel(345, 540, 70, 15, Color.black);
JPanel lborder = createPanel(10, 10, 2, 560, Color.black);
JPanel rborder = createPanel(720, 10, 2, 560, Color.black);
JPanel tborder = createPanel(10, 10, 710, 2, Color.black);
public BallWindow() {
setLayout(null);
btnStop.setBounds(12, 15, 100, 30);
btnStop.addActionListener(this);
add(btnStop);
btnSave.setBounds(12, 50, 100, 30);
//btnSave.addActionListener(this);
add(btnSave);
Random r = new Random();
for(int i=0; i<7; i++){
BallPanel bp = new BallPanel(r.nextInt(740), r.nextInt(590));
Thread t = new Thread(bp);
ballVector.add(bp);
t.start();
add(bp);
}
add(p1);
add(p2);
add(bottomp);
add(lborder);
add(rborder);
add(tborder);
setSize(740, 590);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
repaint();
}
JPanel createPanel(int x, int y, int width, int height, Color pColor){
JPanel temp = new JPanel();
temp.setBackground(pColor);
temp.setBounds(x, y, width, height);
return temp;
}
public static void main(String[] args) {
new BallWindow();
}
public void actionPerformed(ActionEvent arg0) {
for (BallPanel ball : ballVector) {
ball.pleaseWait = !ball.pleaseWait;
}
if( btnStop.getText().equalsIgnoreCase("STOP"))
btnStop.setText("START");
else
btnStop.setText("STOP");
// if(arg0.getSource())
}
}
I'm stuck with obstacles part and the keylistener. Any type of help will be greatly appreciated.
Hava a look at http://zetcode.com/tutorials/javagamestutorial/
You should especially check out the Basics and the Animation section. It will help clean up the animation and thread stuff you are doing. It also shows a general pattern how one could implement a java game.

Components on the JPanel doesn't show

I created a JPanel and i modify it a bit. I change it's background to gradient color here is the class.
public class JGradientPanel extends JPanel {
private static final int N = 32;
private Color color1, color2;
public JGradientPanel(Color color1, Color color2) {
this.setBorder(BorderFactory.createEmptyBorder(N, N, N, N));
this.color1 = color1;
this.color2 = color2;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//Color color1 = getBackground();
//Color color2 = color1.darker();
int w = getWidth();
int h = getHeight();
GradientPaint gp = new GradientPaint(
0, 0, color1, 0, h, color2);
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
}
}
Now i added few components to the panel but it didn't display anything, here is the code
public JPanel getMenu() {
JGradientPanel menu = new JGradientPanel(Color.WHITE, Color.white.darker());
int menuHeight = (int) ((int) getHeight() * 0.07);
menu.setPreferredSize(new Dimension(screenWidth,menuHeight));
menu.setLayout(new GridLayout(1,10));
menu.setBackground(Color.LIGHT_GRAY);
//test
JGradientButton test = new JGradientButton("test",Color.GREEN, Color.BLUE);
menu.add(test);
JLabel space = new JLabel(); // first blank space on the menu
space.setBounds(0, 0, menu.getPreferredSize().width - 50, menu.getPreferredSize().height);
space.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, Color.GREEN));
menu.add(space);
JLabel moreSpaces[] = new JLabel[6];
buttons = new JButton[buttonLabels.length];
for(int counter = 0; counter < moreSpaces.length + buttonLabels.length; counter ++ ) {
if(counter < 3) {
buttons[counter] = new JButton(buttonLabels[counter]); //menu buttons
} else {
moreSpaces[counter - 3] = new JLabel(); // the rest of the blank in the menu
}
}
// adding components to menu panel
for(int counter = 0; counter < moreSpaces.length + buttonLabels.length; counter ++){
if(counter < 3) {
buttons[counter].setFocusPainted(false);
menu.add(buttons[counter]);
} else {
menu.add(moreSpaces[counter - 3]);
}
}
return menu;
}
Did i miss something or i did it wrong? What's wrong with my code?
override getPreferredSize in public class JGradientPanel extends JPanel {
Painting in Swing by public void paintComponent(Graphics g) { by default never to returns PreferredSize to JPanel,
JPanel returns Dimension[0, 0];
EDIT
see very informative and interesting thread about GradientPaint

Add a JPanel to a Graphics Panel and making the JPanel Transparent except for objects

I am trying to make a Blackjack Game and way I want to design my program is with a graphics panel (Images, drawing of cards, etc.) and on top of that panel a JPanel with buttons. I want this JPanel to be transparent so that the Graphics Panel underneath is Visible but the JButtons do not turn transparent as well.
If someone can send me in the right direction?
Graphic Layer:
public class GraphicsBoard {
String[] fileName = { "cards.png", "BlackJackBoard.png" };
ClassLoader cl = GraphicsBoard.class.getClassLoader();
URL imgURL[] = new URL[2];
Toolkit tk = Toolkit.getDefaultToolkit();
Image imgCards, imgBG;
public GraphicsBoard() throws Exception {
for (int x = 0; x < imgURL.length; x++)
imgURL[x] = cl.getResource("pictures/" + fileName[x]);
imgCards = tk.createImage(imgURL[0]);
imgBG = tk.createImage(imgURL[1]);
}
public void paintComponent(Graphics g) {
g.drawImage(imgBG, 0, 0, 550, 450, 0, 0, 551, 412, this);
Graphics2D g2 = (Graphics2D) g;
for (int x = 0; x <= 550; x += 50) {
g2.drawLine(x, 0, x, 450);
g2.drawString("" + x, x + 5, 20);
}
for (int y = 5; y <= 450; y += 50) {
g2.drawLine(0, y, 550, y);
g2.drawString(" " + y, 0, y + 20);
}
}
}
Button Layer:
public class OverBoard extends JPanel implements ActionListener{
JButton btnDeal = new JButton("Deal");
public OverBoard(){
btnDeal.addActionListener(this);
add(btnDeal);
setOpaque(false);
}
}
I want the ButtonLayer to be on top of the GraphicLayer.
I want this JPanel to be transparent so that the Graphics Panel
underneath is Visible but the JButtons do not turn transparent as
well.
an OverlayLayout JPanel will do what you descibe.
there are a few ways, proper could be to
use GlassPane, have to consume() or redispatch KeyEvents
JLayer (Java7), based on JXLayer(Java6)

Categories

Resources