Filling a HUD in Java - java

I've decided on making a HUD with the picture above, but I don't know what command in Java I need to use so as I can fill the top half and the bottom half separately.
I only know how to use the g.fillRect(); command, and it will take around twenty of these commands to fill said half.
public class HUD {
private Player player;
private BufferedImage image;
private Font font;
private Font font2;
private int Phealth = Player.getHealth();
public HUD(Player p) {
player = p;
try {
image = ImageIO.read(getClass().getResourceAsStream("/HUD/HUD_TEST.gif"));
font = new Font("Arial", Font.PLAIN, 10);
font2 = new Font("SANS_SERIF", Font.BOLD, 10);
}
catch(Exception e) {
e.printStackTrace();
}
}
public void draw(Graphics2D g) {
g.drawImage(image, 0, 10, null);
g.setFont(font2);
g.setColor(Color.black);
g.drawString("Health:", 30, 22);
g.drawString("Mana:", 25, 47);
g.setFont(font);
g.drawString(Player.getHealth() + "/" + player.getMaxHealth(), 64, 22);
g.drawString(player.getCubes() / 100 + "/" + player.getMaxCubes() / 100, 55, 47);
g.setColor(Color.red);
g.fillRect(1, 25, Phealth * 25, 4);
g.setColor(Color.blue);
g.fillRect(1, 31, player.getCubes() / 33, 4);
}
}
This is the code for the HUD so far.
Any help in filling the shape will help.

Removed Idea #1! (It didn't seem to work.)
Okay, Idea #2:
Image1
Image2
Image3
So, there are 3 .png images.
Draw Image1 first, followed by drawing Image2 and Image3 directly on top of it.
To fill up either the red/blue bars, clip Image2 and Image3 accordingly (i.e. cut away their left sides)
Take a look at this on clipping.
This will require some minor calculations on how much to clip, based on the HP/Mana of the Player, but it should be good enough.
This is what it should look like (Clipping and overlaying done in Paint)
UPDATE (Problem solved, using Idea #2!):
Code:
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
#SuppressWarnings("serial")
public class TestGraphics extends JFrame implements ActionListener
{
JPanel utilBar = new JPanel();
JButton hpUpBtn = new JButton("HP++");
JButton hpDownBtn = new JButton("HP--");
JButton mpUpBtn = new JButton("MP++");
JButton mpDownBtn = new JButton("MP--");
GraphicsPanel drawingArea = new GraphicsPanel();
TestGraphics()
{
setSize(600, 500);
setLayout(new BorderLayout());
add(utilBar, BorderLayout.NORTH);
utilBar.setLayout(new GridLayout(1, 4));
utilBar.add(hpUpBtn);
utilBar.add(hpDownBtn);
utilBar.add(mpUpBtn);
utilBar.add(mpDownBtn);
add(drawingArea, BorderLayout.CENTER);
hpUpBtn.addActionListener(this);
hpDownBtn.addActionListener(this);
mpUpBtn.addActionListener(this);
mpDownBtn.addActionListener(this);
setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == hpUpBtn) {
drawingArea.incHp();
}
else if (e.getSource() == hpDownBtn) {
drawingArea.decHp();
}
else if (e.getSource() == mpUpBtn) {
drawingArea.incMp();
}
else if (e.getSource() == mpDownBtn) {
drawingArea.decMp();
}
System.out.println("Player HP: " + drawingArea.getHp() +
" Player MP: " + drawingArea.getMp());
drawingArea.revalidate();
drawingArea.repaint();
}
public static void main(String[]agrs)
{
new TestGraphics();
}
}
#SuppressWarnings("serial")
class GraphicsPanel extends JPanel {
private static int baseX = 150;
private static int baseY = 150;
private static final int BAR_FULL = 287;
private static final int BAR_EMPTY = 8;
private BufferedImage image1 = null;
private BufferedImage image2 = null;
private BufferedImage image3 = null;
private int playerHp = 100;
private int playerMp = 100;
public GraphicsPanel() {
try {
// All 3 images are the same as those posted in answer
image1 = ImageIO.read(
getClass().getResourceAsStream("/Image1.png"));
image2 = ImageIO.read(
getClass().getResourceAsStream("/Image2.png"));
image3 = ImageIO.read(
getClass().getResourceAsStream("/Image3.png"));
} catch (Exception e) {
e.printStackTrace();
}
}
public void incHp() { playerHp += (playerHp < 100) ? 5 : 0; }
public void decHp() { playerHp -= (playerHp > 0) ? 5 : 0; }
public void incMp() { playerMp += (playerMp < 100) ? 5 : 0; }
public void decMp() { playerMp -= (playerMp > 0) ? 5 : 0; }
public int getHp() { return playerHp; }
public int getMp() { return playerMp; }
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Clear the graphics
g.setClip(null);
g.setColor(Color.BLACK);
g.fillRect(0, 0, 600, 600);
g.drawImage(image1, baseX, baseY, null);
int hpPerc = (int) ((BAR_FULL - BAR_EMPTY) * (playerHp / 100.0));
g.setClip(baseX + BAR_EMPTY + hpPerc, 0, 600, 500);
g.drawImage(image2, baseX, baseY, null);
g.setClip(null);
int mpPerc = (int) ((BAR_FULL - BAR_EMPTY) * (playerMp / 100.0));
g.setClip(baseX + BAR_EMPTY + mpPerc, 0, 600, 500);
g.drawImage(image3, baseX, baseY + 78, null);
g.setClip(null);
}
}

Related

Clearing the screen for new graphics in Java (awt)

I have this code which is basically a home menu with two clickable rectangles.
Start Game
Info
Start Game works fine.
Info is what is not really working. When pressed, the info screen will appear, but the home menu buttons will still be there though not visible (can be clicked).. it seems that when the info menu is appearing, the home menu buttons are not getting cleared.
Also, any point on the info menu is clickable and will show the home menu again. (not what intended, only the back buttons should do that).
How can I fix those problems ?
package test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;
public class HomeMenu extends JComponent implements MouseListener, MouseMotionListener {
private static final String GAME_TITLE = "BRICK DESTROY";
private static final String START_TEXT = "START";
private static final String INFO_TEXT = "INFO";
private static final String howtoPlay = """
1- Click Start\n
2- Choose the mode\n
3- Each mode has 3 levels\n
4- To play/pause press space, use 'A' and 'D' to move\n
5- To open pause menu press 'ESC'\n
6- To open DebugPanel press 'ALT-SHIFT-F1'""";
private static final String backText = "BACK";
private static final Color BORDER_COLOR = new Color(200,8,21); //Venetian Red
private static final Color DASH_BORDER_COLOR = new Color(255, 216, 0);//school bus yellow
private static final Color TEXT_COLOR = new Color(255, 255, 255);//white
private static final Color CLICKED_BUTTON_COLOR = Color.ORANGE.darker();;
private static final Color CLICKED_TEXT = Color.ORANGE.darker();
private static final int BORDER_SIZE = 5;
private static final float[] DASHES = {12,6};
private Rectangle menuFace;
private Rectangle infoFace;
private Rectangle startButton;
private Rectangle infoButton;
private Rectangle backButton;
private BasicStroke borderStoke;
private BasicStroke borderStoke_noDashes;
private Image img = Toolkit.getDefaultToolkit().createImage("1.jpeg");
private Font gameTitleFont;
private Font infoFont;
private Font buttonFont;
private Font howtoPlayFont;
private GameFrame owner;
private boolean startClicked;
private boolean infoClicked = false;
private boolean backClicked = false;
public HomeMenu(GameFrame owner,Dimension area){
this.setFocusable(true);
this.requestFocusInWindow();
this.addMouseListener(this);
this.addMouseMotionListener(this);
this.owner = owner;
menuFace = new Rectangle(new Point(0,0),area);
infoFace = new Rectangle(new Point(0,0),area);
this.setPreferredSize(area);
Dimension btnDim = new Dimension(area.width / 3, area.height / 12);
startButton = new Rectangle(btnDim);
infoButton = new Rectangle(btnDim);
backButton = new Rectangle(btnDim);
borderStoke = new BasicStroke(BORDER_SIZE,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND,0,DASHES,0);
borderStoke_noDashes = new BasicStroke(BORDER_SIZE,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
gameTitleFont = new Font("Calibri",Font.BOLD,28);
infoFont = new Font("Calibri",Font.BOLD,24);
buttonFont = new Font("Calibri",Font.BOLD,startButton.height-2);
howtoPlayFont = new Font("Calibri",Font.PLAIN,14);
}
public void paint(Graphics g){
drawMenu((Graphics2D)g);
}
public void drawMenu(Graphics2D g2d){
if(infoClicked) {
drawInfoMenu(g2d);
return;
}else{
drawContainer(g2d);
Color prevColor = g2d.getColor();
Font prevFont = g2d.getFont();
double x = menuFace.getX();
double y = menuFace.getY();
g2d.translate(x,y);
//methods calls
drawText(g2d);
drawButton(g2d);
//end of methods calls
g2d.translate(-x,-y);
g2d.setFont(prevFont);
g2d.setColor(prevColor);
}
Toolkit.getDefaultToolkit().sync();
}
private void drawContainer(Graphics2D g2d){
Color prev = g2d.getColor();
//g2d.setColor(BG_COLOR);
g2d.drawImage(img,0,0,menuFace.width,menuFace.height,this);
//g2d.fill(menuFace);
Stroke tmp = g2d.getStroke();
g2d.setStroke(borderStoke_noDashes);
g2d.setColor(DASH_BORDER_COLOR);
g2d.draw(menuFace);
g2d.setStroke(borderStoke);
g2d.setColor(BORDER_COLOR);
g2d.draw(menuFace);
g2d.setStroke(tmp);
g2d.setColor(prev);
}
private void drawText(Graphics2D g2d){
g2d.setColor(TEXT_COLOR);
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D gameTitleRect = gameTitleFont.getStringBounds(GAME_TITLE,frc);
int sX,sY;
sY = (int)(menuFace.getHeight() / 4);
sX = (int)(menuFace.getWidth() - gameTitleRect.getWidth()) / 2;
sY += (int) gameTitleRect.getHeight() * 1.1;//add 10% of String height between the two strings
g2d.setFont(gameTitleFont);
g2d.drawString(GAME_TITLE,sX,sY);
}
private void drawButton(Graphics2D g2d){
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D txtRect = buttonFont.getStringBounds(START_TEXT,frc);
Rectangle2D mTxtRect = buttonFont.getStringBounds(INFO_TEXT,frc);
g2d.setFont(buttonFont);
int x = (menuFace.width - startButton.width) / 2;
int y =(int) ((menuFace.height - startButton.height) * 0.5);
startButton.setLocation(x,y);
x = (int)(startButton.getWidth() - txtRect.getWidth()) / 2;
y = (int)(startButton.getHeight() - txtRect.getHeight()) / 2;
x += startButton.x;
y += startButton.y + (startButton.height * 0.9);
if(startClicked){
Color tmp = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(startButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(START_TEXT,x,y);
g2d.setColor(tmp);
}
else{
g2d.draw(startButton);
g2d.drawString(START_TEXT,x,y);
}
x = startButton.x;
y = startButton.y;
y *= 1.3;
infoButton.setLocation(x,y);
x = (int)(infoButton.getWidth() - mTxtRect.getWidth()) / 2;
y = (int)(infoButton.getHeight() - mTxtRect.getHeight()) / 2;
x += infoButton.getX();
y += infoButton.getY() + (startButton.height * 0.9);
if(infoClicked){
Color tmp = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(infoButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(INFO_TEXT,x,y);
g2d.setColor(tmp);
}
else{
g2d.draw(infoButton);
g2d.drawString(INFO_TEXT,x,y);
}
}
private void drawInfoMenu(Graphics2D g2d){
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D infoRec = infoFont.getStringBounds(INFO_TEXT,frc);
Color prev = g2d.getColor();
Stroke tmp = g2d.getStroke();
g2d.setStroke(borderStoke_noDashes);
g2d.setColor(DASH_BORDER_COLOR);
g2d.draw(infoFace);
g2d.setStroke(borderStoke);
g2d.setColor(BORDER_COLOR);
g2d.draw(infoFace);
g2d.fillRect(0,0,infoFace.width,infoFace.height);
g2d.setStroke(tmp);
g2d.setColor(prev);
g2d.setColor(TEXT_COLOR);
int sX,sY;
sY = (int)(infoFace.getHeight() / 15);
sX = (int)(infoFace.getWidth() - infoRec.getWidth()) / 2;
sY += (int) infoRec.getHeight() * 1.1;//add 10% of String height between the two strings
g2d.setFont(infoFont);
g2d.drawString(INFO_TEXT,sX,sY);
TextLayout layout = new TextLayout(howtoPlay, howtoPlayFont, frc);
String[] outputs = howtoPlay.split("\n");
for(int i=0; i<outputs.length; i++) {
g2d.setFont(howtoPlayFont);
g2d.drawString(outputs[i], 40, (int) (80 + i * layout.getBounds().getHeight() + 0.5));
}
backButton.setLocation(getWidth()/3,getHeight()-50);
int x = (int)(backButton.getWidth() - infoRec.getWidth()) / 2;
int y = (int)(backButton.getHeight() - infoRec.getHeight()) / 2;
x += backButton.x+11;
y += backButton.y + (layout.getBounds().getHeight() * 1.35);
backButton.setLocation(getWidth()/3,getHeight()-50);
if(backClicked){
Color tmp1 = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(backButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(backText,x,y);
g2d.setColor(tmp1);
infoClicked = false;
repaint();
}
else{
g2d.draw(backButton);
g2d.drawString(backText,x,y);
}
}
#Override
public void mouseClicked(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if(startButton.contains(p)){
owner.enableGameBoard();
}
else if(infoButton.contains(p)){
infoClicked = true;
}
else if(backButton.contains(p)){
infoClicked = false;
}
repaint();
}
#Override
public void mousePressed(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if(startButton.contains(p)){
startClicked = true;
repaint(startButton.x,startButton.y,startButton.width+1,startButton.height+1);
}
else if(infoButton.contains(p)){
infoClicked = true;
}
else if(backButton.contains(p)){
infoClicked = false;
}
repaint();
}
#Override
public void mouseReleased(MouseEvent mouseEvent) {
if(startClicked){
startClicked = false;
repaint(startButton.x,startButton.y,startButton.width+1,startButton.height+1);
}
else if(infoClicked){
infoClicked = false;
}
else if(backClicked){
infoClicked = true;
}
repaint();
}
#Override
public void mouseEntered(MouseEvent mouseEvent) {
}
#Override
public void mouseExited(MouseEvent mouseEvent) {
}
#Override
public void mouseDragged(MouseEvent mouseEvent) {
}
#Override
public void mouseMoved(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if(startButton.contains(p) || infoButton.contains(p) || backButton.contains(p)) {
this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else {
this.setCursor(Cursor.getDefaultCursor());
}
}
}
Here are the images of both windows
main menu
info menu, pressing anywhere = back to home menu, pressing roughly in the middle = start game or back to main menu too
First read, Performing Custom Painting and Painting in AWT and Swing to get a better understanding how painting in Swing works and how you're suppose to work with it.
But I already have ...
public void paint(Graphics g){
drawMenu((Graphics2D)g);
}
would suggest otherwise. Seriously, go read those links so you understand all the issues that the above decision is going to create for you.
You're operating in a OO language, you need to take advantage of that and decouple your code and focus on the "single responsibility" principle.
I'm kind of tired of talking about it, so you can do some reading:
https://softwareengineering.stackexchange.com/questions/244476/what-is-decoupling-and-what-development-areas-can-it-apply-to
Cohesion and Decoupling, what do they represent?
Single Responsibility Principle
Single Responsibility Principle in Java with Examples
SOLID Design Principles Explained: The Single Responsibility Principle
These are basic concepts you really need to understand as they will make your live SOOO much easier and can be applied to just about any language.
As an example, from your code...
public HomeMenu(GameFrame owner,Dimension area){
//...
this.setPreferredSize(area);
There is no good reason (other than laziness (IMHO)) that any caller should be telling a component what size it should be, that's not their responsibility. It's the responsibility of the component to tell the parent container how big it would like to be and for the parent component to figure out how it's going to achieve that (or ignore it as the case may be).
The "basic" problem you're having is a simple one. Your "God" class is simply trying to do too much (ie it's taken on too much responsibility). Now we "could" add a dozen or more flags into the code to compensate for this, which is just going to increase the coupling and complexity, making it harder to understand and maintain, or we can take a step back, break it down into individual areas of responsibility and build the solution around those, for example...
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new HomePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class HomePane extends JPanel {
public HomePane() {
setLayout(new BorderLayout());
navigateToMenu();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected void navigateToMenu() {
removeAll();
HomeMenuPane pane = new HomeMenuPane(new HomeMenuPane.NavigationListener() {
#Override
public void navigateToInfo(HomeMenuPane source) {
HomePane.this.navigateToInfo();
}
#Override
public void navigateToStartGame(HomeMenuPane source) {
startGame();
}
});
add(pane);
revalidate();
repaint();
}
protected void navigateToInfo() {
removeAll();
HowToPlayPane pane = new HowToPlayPane(new HowToPlayPane.NavigationListener() {
#Override
public void navigateBack(HowToPlayPane source) {
navigateToMenu();
}
});
add(pane);
revalidate();
repaint();
}
protected void startGame() {
removeAll();
add(new JLabel("This is pretty awesome, isn't it!", JLabel.CENTER));
revalidate();
repaint();
}
}
public abstract class AbstractBaseMenuPane extends JPanel {
protected static final Color BORDER_COLOR = new Color(200, 8, 21); //Venetian Red
protected static final Color DASH_BORDER_COLOR = new Color(255, 216, 0);//school bus yellow
protected static final Color TEXT_COLOR = new Color(255, 255, 255);//white
protected static final Color CLICKED_BUTTON_COLOR = Color.ORANGE.darker();
protected static final Color CLICKED_TEXT = Color.ORANGE.darker();
protected static final int BORDER_SIZE = 5;
protected static final float[] DASHES = {12, 6};
private Rectangle border;
private BasicStroke borderStoke;
private BasicStroke borderStoke_noDashes;
private BufferedImage backgroundImage;
public AbstractBaseMenuPane() {
borderStoke = new BasicStroke(BORDER_SIZE, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0, DASHES, 0);
borderStoke_noDashes = new BasicStroke(BORDER_SIZE, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
border = new Rectangle(new Point(0, 0), getPreferredSize());
// You are now responsible for filling the background
setOpaque(false);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
BufferedImage backgroundImage = getBackgroundImage();
if (backgroundImage != null) {
g2d.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), this);
}
Color prev = g2d.getColor();
Stroke tmp = g2d.getStroke();
g2d.setStroke(borderStoke_noDashes);
g2d.setColor(DASH_BORDER_COLOR);
g2d.draw(border);
g2d.setStroke(borderStoke);
g2d.setColor(BORDER_COLOR);
g2d.draw(border);
g2d.dispose();
}
public void setBackgroundImage(BufferedImage backgroundImage) {
this.backgroundImage = backgroundImage;
repaint();
}
public BufferedImage getBackgroundImage() {
return backgroundImage;
}
}
public class HomeMenuPane extends AbstractBaseMenuPane {
public static interface NavigationListener {
public void navigateToInfo(HomeMenuPane source);
public void navigateToStartGame(HomeMenuPane source);
}
private static final String GAME_TITLE = "BRICK DESTROY";
private static final String START_TEXT = "START";
private static final String INFO_TEXT = "INFO";
private Rectangle startButton;
private Rectangle infoButton;
private Font gameTitleFont;
private Font buttonFont;
// Don't do this, this just sucks (for so many reasons)
// Use ImageIO.read instead and save yourself a load of frustration
//private Image img = Toolkit.getDefaultToolkit().createImage("1.jpeg");
private Point lastClickPoint;
private NavigationListener navigationListener;
public HomeMenuPane(NavigationListener navigationListener) {
this.navigationListener = navigationListener;
try {
setBackgroundImage(ImageIO.read(getClass().getResource("/images/BrickWall.jpg")));
} catch (IOException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
lastClickPoint = p;
if (startButton.contains(p)) {
peformStartGameAction();
} else if (infoButton.contains(p)) {
performInfoAction();
}
repaint();
}
#Override
public void mouseReleased(MouseEvent mouseEvent) {
lastClickPoint = null;
repaint();
}
});
this.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if (startButton.contains(p) || infoButton.contains(p)) {
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
} else {
setCursor(Cursor.getDefaultCursor());
}
}
});
Dimension area = getPreferredSize();
Dimension btnDim = new Dimension(area.width / 3, area.height / 12);
startButton = new Rectangle(btnDim);
infoButton = new Rectangle(btnDim);
gameTitleFont = new Font("Calibri", Font.BOLD, 28);
buttonFont = new Font("Calibri", Font.BOLD, startButton.height - 2);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Color prevColor = g2d.getColor();
Font prevFont = g2d.getFont();
//methods calls
drawText(g2d);
drawButton(g2d);
//end of methods calls
g2d.setFont(prevFont);
g2d.setColor(prevColor);
g2d.dispose();
}
private void drawText(Graphics2D g2d) {
g2d.setColor(TEXT_COLOR);
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D gameTitleRect = gameTitleFont.getStringBounds(GAME_TITLE, frc);
int sX, sY;
sY = (int) (getHeight() / 4);
sX = (int) (getWidth() - gameTitleRect.getWidth()) / 2;
sY += (int) gameTitleRect.getHeight() * 1.1;//add 10% of String height between the two strings
g2d.setFont(gameTitleFont);
g2d.drawString(GAME_TITLE, sX, sY);
}
private void drawButton(Graphics2D g2d) {
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D txtRect = buttonFont.getStringBounds(START_TEXT, frc);
Rectangle2D mTxtRect = buttonFont.getStringBounds(INFO_TEXT, frc);
g2d.setFont(buttonFont);
int x = (getWidth() - startButton.width) / 2;
int y = (int) ((getHeight() - startButton.height) * 0.5);
startButton.setLocation(x, y);
x = (int) (startButton.getWidth() - txtRect.getWidth()) / 2;
y = (int) (startButton.getHeight() - txtRect.getHeight()) / 2;
x += startButton.x;
y += startButton.y + (startButton.height * 0.9);
if (lastClickPoint != null && startButton.contains(lastClickPoint)) {
Color tmp = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(startButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(START_TEXT, x, y);
g2d.setColor(tmp);
} else {
g2d.draw(startButton);
g2d.drawString(START_TEXT, x, y);
}
x = startButton.x;
y = startButton.y;
y *= 1.3;
infoButton.setLocation(x, y);
x = (int) (infoButton.getWidth() - mTxtRect.getWidth()) / 2;
y = (int) (infoButton.getHeight() - mTxtRect.getHeight()) / 2;
x += infoButton.getX();
y += infoButton.getY() + (startButton.height * 0.9);
if (lastClickPoint != null && infoButton.contains(lastClickPoint)) {
Color tmp = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(infoButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(INFO_TEXT, x, y);
g2d.setColor(tmp);
} else {
g2d.draw(infoButton);
g2d.drawString(INFO_TEXT, x, y);
}
}
protected void peformStartGameAction() {
navigationListener.navigateToStartGame(this);
}
protected void performInfoAction() {
navigationListener.navigateToInfo(this);
}
}
public class HowToPlayPane extends AbstractBaseMenuPane {
public static interface NavigationListener {
public void navigateBack(HowToPlayPane source);
}
private static final String HOW_TO_PLAY_TEXT = """
1- Click Start\n
2- Choose the mode\n
3- Each mode has 3 levels\n
4- To play/pause press space, use 'A' and 'D' to move\n
5- To open pause menu press 'ESC'\n
6- To open DebugPanel press 'ALT-SHIFT-F1'""";
private static final String BACK_TEXT = "BACK";
private static final String INFO_TEXT = "INFO";
private Rectangle backButton;
private boolean backClicked = false;
private Font infoFont;
private Font howtoPlayFont;
private NavigationListener navigationListener;
public HowToPlayPane(NavigationListener navigationListener) {
this.navigationListener = navigationListener;
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if (backButton.contains(p)) {
backClicked = true;
repaint();
performBackAction();
}
}
#Override
public void mouseReleased(MouseEvent e) {
backClicked = false;
}
});
this.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if (backButton.contains(p)) {
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
} else {
setCursor(Cursor.getDefaultCursor());
}
}
});
Dimension btnDim = new Dimension(getPreferredSize().width / 3, getPreferredSize().height / 12);
backButton = new Rectangle(btnDim);
infoFont = new Font("Calibri", Font.BOLD, 24);
howtoPlayFont = new Font("Calibri", Font.PLAIN, 14);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(BORDER_COLOR);
g2d.fillRect(0, 0, getWidth(), getHeight());
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D infoRec = infoFont.getStringBounds(INFO_TEXT, frc);
//
// Color prev = g2d.getColor();
//
// Stroke tmp = g2d.getStroke();
//
// g2d.setStroke(borderStoke_noDashes);
// g2d.setColor(DASH_BORDER_COLOR);
// g2d.draw(infoFace);
//
// g2d.setStroke(borderStoke);
// g2d.setColor(BORDER_COLOR);
// g2d.draw(infoFace);
//
// g2d.fillRect(0, 0, infoFace.width, infoFace.height);
//
// g2d.setStroke(tmp);
//
// g2d.setColor(prev);
//
g2d.setColor(TEXT_COLOR);
int sX, sY;
sY = (int) (getHeight() / 15);
sX = (int) (getWidth() - infoRec.getWidth()) / 2;
sY += (int) infoRec.getHeight() * 1.1;//add 10% of String height between the two strings
g2d.setFont(infoFont);
g2d.drawString(INFO_TEXT, sX, sY);
TextLayout layout = new TextLayout(HOW_TO_PLAY_TEXT, howtoPlayFont, frc);
String[] outputs = HOW_TO_PLAY_TEXT.split("\n");
for (int i = 0; i < outputs.length; i++) {
g2d.setFont(howtoPlayFont);
g2d.drawString(outputs[i], 40, (int) (80 + i * layout.getBounds().getHeight() + 0.5));
}
backButton.setLocation(getWidth() / 3, getHeight() - 50);
int x = (int) (backButton.getWidth() - infoRec.getWidth()) / 2;
int y = (int) (backButton.getHeight() - infoRec.getHeight()) / 2;
x += backButton.x + 11;
y += backButton.y + (layout.getBounds().getHeight() * 1.35);
backButton.setLocation(getWidth() / 3, getHeight() - 50);
if (backClicked) {
Color tmp1 = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(backButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(BACK_TEXT, x, y);
g2d.setColor(tmp1);
repaint();
} else {
g2d.draw(backButton);
g2d.drawString(BACK_TEXT, x, y);
}
g2d.dispose();
}
protected void performBackAction() {
navigationListener.navigateBack(this);
}
}
}
Now, this example makes use of components to present different views (it even has a nice abstract implementation to allow for code re-use 😱), but it occurs to me, that, if you "really" wanted to, you could have a series of "painter" classes, which could be used to delegate the painting of the current state to, and mouse clicks/movements could be delegated to, meaning you could have a single component, which would simple delegate the painting (via the paintComponent method) to which ever painter is active.
And, wouldn't you know it, they have a design principle for that to, the Delegation Pattern
The above example also makes use of the observer pattern, so you might want to have a look into that as well

Rotate image without clear background

i have read about a lot of articles of drawing images, but i cant get those to work when i need to keep the background. I'm trying to rotate an image which is over another image after click on a JButton. The background image is generated on a JPanel by:
public void paintComponent(Graphics g){
int index = 0;
Graphics2D g2 = (Graphics2D) g;
super.paintComponent(g);
try {
image = ImageIO.read(url1);
image2 = ImageIO.read(url2);
image3 = ImageIO.read(url3);
} catch (IOException e) {
}
g.drawImage(image, 0, 0, null);
g.drawImage(image3, 0, 0, null);
if(scaleDrawnFlag == 0){
for(index = 0; index < 60; index ++){
tx = AffineTransform.getRotateInstance(Math.toRadians(6*index), this.getHeight()/2, this.getWidth()/2);
op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
g.drawImage(op.filter(image3, null), 0, 0, null);
}
scaleDrawnFlag = 1;
}
g.drawImage(image2, 0, 0, null);
}
Which is into a JPanel named panel and draw a image only one time to keep the refresh performance, only for the animated image. This draws a scale for a tachometer, by a total of 60 lines, where each line is a copy of image3
The animated image, is generated by pressing a JButton, and is made by:
public void paintComponent(Graphics g){
super.paintComponent(g);
BufferedImage img = new BufferedImage(370, 370, BufferedImage.TRANSLUCENT);
Graphics2D g2d = img.createGraphics();
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.0f));
Graphics2D temp = (Graphics2D) g;
tx = AffineTransform.getRotateInstance(Math.toRadians(degrees), this.getHeight()/2, this.getWidth()/2);
op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
temp.drawImage(op.filter(image2, null), 0, 0, null);
temp.dispose();
}
Which is into another JPanel named overPanel, which is over the initial JPanel.
But, when i call the methods:
public void up(){
degrees ++;
if(degrees == 360) degrees = 0;
repaint();
}
public void down(){
degrees --;
if(degrees == -360) degrees = 0;
repaint();
}
Which are on the overPanel class, the JPanel is entirely cleared. The animation is working well but, the Background disappear.
What must i do to keep the Background?
I also tried another solution, by drawing the 60 lines again on every up() and down() call. The background is repainted, but takes too much time to complete, so, the animation to rotate the tachometer's indicator lags.
Never dispose of a Graphics object given to you by the JVM. You're doing this:
// temp **is** the same object as g and is the Graphics object given by the JVM
Graphics2D temp = (Graphics2D) g;
//....
temp.dispose();
and shouldn't do it since it completely breaks the painting chain. You should instead be disposing of the g2d object, one you created.
Also, this would be OK
Graphics2D temp = (Graphics2D) g.create(); // temp **is** a new object
//....
temp.dispose(); // this is OK
Other issues:
I also wouldn't be creating my BufferedImage inside of paintComponent but rather would make it a field of the class, and display it inside paintComponent.
Your top code shows ignored critical exceptions -- you don't want to do this.
It also shows reading in of image files within a painting method, something that will unnecessarily slow down graphics. Again, don't do this, read in the images once outside of any painting method, store the results, and use them in the painting method.
The paintComponent method is protected, not public. Avoid increasing its visibility unnecessarily.
In your minimal example program, your scaleDrawnFlag variable and its associated if-block appear to be messing you up. What is the purpose of that variable and the if block? If you get rid of the variable and the if block, your background would persist. Myself, I'd do things differently by creating a stable background image and drawing it every time in the paintComponent(...) method. I would not override update(...) either as that's an AWT kludge and not for Swing graphics. I also try to avoid null layouts and setBounds(...) like the plague since that leads to inflexible, rigid GUI's that are very difficult to debug, maintain and enhance. For example:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class MyMainPanel extends JPanel {
private MyDrawingPanel myDrawingPanel;
public MyMainPanel() {
try {
myDrawingPanel = new MyDrawingPanel();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
JPanel rightPanel = new JPanel();
rightPanel.setLayout(new GridLayout(0, 1, 5, 5));
rightPanel.add(new JButton(new MyUpAction("Up", KeyEvent.VK_U)));
rightPanel.add(new JButton(new MyDownAction("Down", KeyEvent.VK_D)));
JPanel rightWrapPanel = new JPanel(new BorderLayout());
rightWrapPanel.add(rightPanel, BorderLayout.PAGE_START);
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
setLayout(new BorderLayout());
add(myDrawingPanel, BorderLayout.CENTER);
add(rightWrapPanel, BorderLayout.LINE_END);
}
private class MyUpAction extends AbstractAction {
public MyUpAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
myDrawingPanel.up();
}
}
private class MyDownAction extends AbstractAction {
public MyDownAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
myDrawingPanel.down();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("MyMainPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MyMainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class MyDrawingPanel extends JPanel {
private static final String NEEDLE_IMG_PATH = "http://1.bp.blogspot.com/"
+ "-fq-oPGBSLp4/Ttoj7DoAMWI/AAAAAAAABtc/t7gKJlfRQuo/s400/secondHand.png";
private static final String ORANGE_DISK_IMG_PATH = "http://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Circle_Fulvous_Solid.svg/200px-Circle_Fulvous_Solid.svg.png";
private static final String GREEN_LINE_IMG_PATH = "http://www.xtremeskater.com/math/images/circle_radius.png";
private static final int MAX_DEGREES = 360;
private int imgWidth = 0;
private int imgHeight = 0;
private BufferedImage needleImg = null;
private BufferedImage orangeDiskImg = null;
private BufferedImage greenLineImg = null;
private BufferedImage backgroundImg = null;
private int degrees;
public MyDrawingPanel() throws IOException {
URL needleUrl = new URL(NEEDLE_IMG_PATH);
URL orangeDiskUrl = new URL(ORANGE_DISK_IMG_PATH);
URL greenLineUrl = new URL(GREEN_LINE_IMG_PATH);
needleImg = ImageIO.read(needleUrl);
orangeDiskImg = ImageIO.read(orangeDiskUrl);
greenLineImg = ImageIO.read(greenLineUrl);
imgWidth = Math.max(orangeDiskImg.getWidth(),
greenLineImg.getWidth());
imgHeight = Math.max(orangeDiskImg.getHeight(),
greenLineImg.getHeight());
backgroundImg = new BufferedImage(imgWidth, imgHeight,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = backgroundImg.createGraphics();
drawBackground(g2, imgWidth, imgHeight);
g2.dispose();
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(imgWidth, imgHeight);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (backgroundImg != null) {
g.drawImage(backgroundImg, 0, 0, null);
}
AffineTransform tx = AffineTransform.getRotateInstance(Math.toRadians(degrees),
this.getHeight() / 2, this.getWidth() / 2);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
g.drawImage(op.filter(needleImg, null), 0, 0, null);
}
public void up() {
degrees++;
degrees %= MAX_DEGREES;
repaint();
}
public void down() {
degrees--;
degrees += MAX_DEGREES;
degrees %= MAX_DEGREES;
repaint();
}
public int getDregrees() {
return degrees;
}
private void drawBackground(Graphics2D g2, int biWidth, int biHeight) {
int index;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawImage(orangeDiskImg, 0, 0, null);
g2.drawImage(greenLineImg, 0, 0, null);
AffineTransform tx = AffineTransform.getRotateInstance(Math.toRadians(6),
biWidth / 2, biHeight / 2);
for (index = 0; index < 60; index++) {
g2.transform(tx);
g2.drawImage(greenLineImg, 0, 0, null);
}
}
}
i have found the way to make the Background permanent, by first creating it into a Buffered image, then on each action, repaint that image, without redraw all the primitive forms or the image rotations. I mean, first, i create the Background rotating a basic image multiple times. This is created using a Buffered image. Then, on the paintComponent() method, i redraw the buffered image:
public MyPanel(){
try {
image = ImageIO.read(url1);
image2 = ImageIO.read(url2);
image3 = ImageIO.read(url3);
} catch (IOException e) {
}
img = createImage();
}
private Image createImage(){
double index = 0;
BufferedImage bufferedImage = new BufferedImage(370,370,BufferedImage.TYPE_INT_ARGB);
Graphics g = bufferedImage.getGraphics();
for(index = 0; index <= scale; index = index + count){
tx = AffineTransform.getRotateInstance(Math.toRadians(deg2), 185, 185);
op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
g.drawImage(op.filter(image3, null), 0, 0, null);
deg2 = deg2 + (270.0/(scale/count));
}
return bufferedImage;
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(image, 0, 0, null); //Indicator drawing
g.drawImage(img, 0, 0, null); //Scale drawing
//Indicator rotation
tx = AffineTransform.getRotateInstance(Math.toRadians(degrees), this.getHeight()/2, this.getWidth()/2);
op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
g.drawImage(op.filter(image2, null), 0, 0, null);
}
Here the complete code for a basic example:
package rotateOnImage;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JButton;
import javax.swing.AbstractAction;
import java.awt.event.ActionEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.swing.Action;
public class MainFrame extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private MyPanel panel = new MyPanel();
private final Action upAction = new upAction();
private final Action dnAction = new dnAction();
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainFrame frame = new MainFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public MainFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 345, 227);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JButton btnNewButton = new JButton("UP");
btnNewButton.setAction(upAction);
btnNewButton.setBounds(212, 12, 117, 25);
contentPane.add(btnNewButton);
JButton button = new JButton("DN");
button.setAction(dnAction);
button.setBounds(212, 49, 117, 25);
contentPane.add(button);
panel.setBounds(0, 0, 200, 200);
contentPane.add(panel);
}
private class upAction extends AbstractAction {
/**
*
*/
private static final long serialVersionUID = 1L;
public upAction() {
putValue(NAME, "UP");
}
public void actionPerformed(ActionEvent e) {
panel.up();
}
}
private class dnAction extends AbstractAction {
/**
*
*/
private static final long serialVersionUID = 1L;
public dnAction() {
putValue(NAME, "DN");
}
public void actionPerformed(ActionEvent e) {
panel.down();
}
}
}
class MyPanel extends JPanel{
private static final long serialVersionUID = 1L;
/**
*
*/
private int degrees = 0;
private AffineTransform tx = null;
private AffineTransformOp op = null;
private BufferedImage image1 = null;
private BufferedImage image2 = null;
private BufferedImage image3 = null;
Image img = null;
public static final String IMAGE_PATH1 = "http://1.bp.blogspot.com/"+"-fq-oPGBSLp4/Ttoj7DoAMWI/AAAAAAAABtc/t7gKJlfRQuo/s400/secondHand.png";
public static final String IMAGE_PATH2 = "http://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Circle_Fulvous_Solid.svg/200px-Circle_Fulvous_Solid.svg.png";
public static final String IMAGE_PATH3 ="http://www.xtremeskater.com/math/images/circle_radius.png";
public MyPanel(){
try {
URL url1 = new URL(IMAGE_PATH1);
URL url2 = new URL(IMAGE_PATH2);
URL url3 = new URL(IMAGE_PATH3);
image1 = ImageIO.read(url1);
image2 = ImageIO.read(url2);
image3 = ImageIO.read(url3);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
img = createImage();
}
public void up(){
degrees ++;
if(degrees == 360) degrees = 0;
repaint();
}
public void down(){
degrees --;
if(degrees == -360) degrees = 0;
repaint();
}
public int getDregrees(){
return degrees;
}
private Image createImage(){
double index = 0.0;
BufferedImage bufferedImage = new BufferedImage(200,200,BufferedImage.TYPE_INT_ARGB);
Graphics g = bufferedImage.getGraphics();
for(index = 0.0; index <= 36; index ++){
tx = AffineTransform.getRotateInstance(Math.toRadians(index*10), 100, 100);
op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
g.drawImage(op.filter(image3, null), 0, 0, null);
}
return bufferedImage;
}
public void update(Graphics g){
paint(g);
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(image2, 0, 0, null); //Dibujado de la manecilla
g.drawImage(img, 0, 0, null); //Dibujado de la escala
//Rotación de la manecilla
tx = AffineTransform.getRotateInstance(Math.toRadians(degrees), this.getHeight()/2, this.getWidth()/2);
op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
g.drawImage(op.filter(image1, null), 0, 0, null);
}
}

CardLayout showing two panels, flashing

I'm trying to use CardLayout to show two JPanels, a main menu, and a controls screen. When I add two JPanels to my cards JPanel, it just shows two with flashing images. Here is my code:
package main;
public class MazeGame {
// Layout
public static JPanel cards = new JPanel();
// Window
public static JFrame window;
public static String windowLabel = "2D Maze Game - Before Alpha";
// Window Dimensions and Location
public static int WIDTH = 600;
public static int HEIGHT = 600;
public static Component center = null;
public static int exit = 3;
public static void main(String[] args) {
window = new JFrame(windowLabel);
window.setSize(new Dimension(WIDTH, HEIGHT));
window.setResizable(false);
window.setLocationRelativeTo(center);
window.setDefaultCloseOperation(exit);
cards.setLayout(new CardLayout());
cards.add(new MazeGamePanel(), "main");
cards.add(new MazeControlsPanel(), "controls");
window.add(cards);
CardLayout cl = (CardLayout) cards.getLayout();
cl.show(cards, "main");
window.setVisible(true);
}
}
MazeGamePanel:
public class MazeGamePanel extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
// Timer
public Timer timer;
// Font
public Font bitTrip;
public Thread thread;
public BufferedImage canvas;
public Graphics2D g;
public boolean running;
public int HEIGHT = MazeGame.HEIGHT;
public int WIDTH = MazeGame.WIDTH;
public int FPS = 30;
public int opacity = 255;
public int selectedOption = 0;
public String option1 = "Play";
public String option2 = "Controls";
public String option3 = "Quit";
public MazeGamePanel() {
this.setFocusable(true);
this.requestFocus();
addKeyListener(new MazeGameKeyListener());
try {
bitTrip = Font.createFont(Font.TRUETYPE_FONT, new File(
"res/font/BitTrip7.TTF"));
} catch (FontFormatException | IOException e) {
e.printStackTrace();
}
/**
ActionListener action = new ActionListener () {
public void actionPerformed (ActionEvent e) {
if(opacity != 0) {
opacity--;
} else {
timer.stop();
opacity = 0;
}
}
};
timer = new Timer(10, action);
timer.setInitialDelay(0);
timer.start();
*/
}
public void addNotify() {
super.addNotify();
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
public void run() {
running = true;
canvas = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) canvas.getGraphics();
long startTime = 0;
long millis = 0;
long waitTime = 0;
long targetTime = 1000 / FPS;
while (running) {
startTime = System.nanoTime();
update();
render();
draw();
millis = (System.nanoTime() - startTime) / 1000000;
waitTime = targetTime - millis;
try {
Thread.sleep(waitTime);
} catch (Exception e) {
}
}
}
// TODO
public void render() {
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
bitTrip = bitTrip.deriveFont(40F);
g.setFont(bitTrip);
if (selectedOption == 0) {
//Play
g.setColor(Color.BLACK);
g.drawString(option1, WIDTH / 2 - 200, HEIGHT / 2);
//Controls
g.setColor(Color.GRAY);
g.drawString(option2, WIDTH / 2 - 200, HEIGHT / 2 + 50);
//Quit
g.setColor(Color.GRAY);
g.drawString(option3, WIDTH / 2 - 200, HEIGHT / 2 + 100);
} else if (selectedOption == 1) {
//Play
g.setColor(Color.GRAY);
g.drawString(option1, WIDTH / 2 - 200, HEIGHT / 2);
//Controls
g.setColor(Color.BLACK);
g.drawString(option2, WIDTH / 2 - 200, HEIGHT / 2 + 50);
//Quit
g.setColor(Color.GRAY);
g.drawString(option3, WIDTH / 2 - 200, HEIGHT / 2 + 100);
} else if (selectedOption == 2) {
//Play
g.setColor(Color.GRAY);
g.drawString(option1, WIDTH / 2 - 200, HEIGHT / 2);
//Controls
g.setColor(Color.GRAY);
g.drawString(option2, WIDTH / 2 - 200, HEIGHT / 2 + 50);
//Quit
g.setColor(Color.BLACK);
g.drawString(option3, WIDTH / 2 - 200, HEIGHT / 2 + 100);
}
//g.setColor(new Color(0, 0, 0, opacity));
//g.fillRect(0, 0, WIDTH, HEIGHT);
}
public void update() {
}
public void draw() {
Graphics g2 = this.getGraphics();
g2.drawImage(canvas, 0, 0, null);
g2.dispose();
}
private class MazeGameKeyListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) {
if (selectedOption == 1) {
selectedOption = 0;
} else if (selectedOption == 2) {
selectedOption = 1;
}
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
if (selectedOption == 0) {
selectedOption = 1;
} else if (selectedOption == 1) {
selectedOption = 2;
}
}
if(e.getKeyCode() == KeyEvent.VK_ENTER) {
if(selectedOption == 1) {
MazeGame.window.removeAll();
MazeGame.window.add(new MazeControlsPanel());
MazeGame.window.validate();
}
}
}
}
}
MazeControlsPanel:
package screens;
public class MazeControlsPanel extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
// Font
public Font bitTrip;
public Thread thread;
public BufferedImage canvas;
public Graphics2D g;
public boolean running;
public int HEIGHT = MazeGame.HEIGHT;
public int WIDTH = MazeGame.WIDTH;
public int FPS = 30;
public int opacity = 255;
public int selectedOption = 0;
public MazeControlsPanel() {
this.setFocusable(true);
this.requestFocus();
addKeyListener(new MazeControlsKeyListener());
try {
bitTrip = Font.createFont(Font.TRUETYPE_FONT, new File(
"res/font/BitTrip7.TTF"));
} catch (FontFormatException | IOException e) {
e.printStackTrace();
}
/**
final Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
if (opacity != 0) {
opacity--;
} else {
timer.cancel();
opacity = 0;
}
}
}, 0, 4);
*/
}
public void addNotify() {
super.addNotify();
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
public void run() {
running = true;
canvas = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) canvas.getGraphics();
long startTime = 0;
long millis = 0;
long waitTime = 0;
long targetTime = 1000 / FPS;
while (running) {
startTime = System.nanoTime();
update();
render();
draw();
millis = (System.nanoTime() - startTime) / 1000000;
waitTime = targetTime - millis;
try {
Thread.sleep(waitTime);
} catch (Exception e) {
}
}
}
// TODO
public void render() {
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
bitTrip = bitTrip.deriveFont(40F);
g.setFont(bitTrip);
// Quit
g.setColor(Color.BLACK);
g.drawString("Main Menu", WIDTH / 2 - 200, HEIGHT / 2 + 100);
//g.setColor(new Color(0, 0, 0, opacity));
//g.fillRect(0, 0, WIDTH, HEIGHT);
}
public void update() {
}
public void draw() {
Graphics g2 = this.getGraphics();
g2.drawImage(canvas, 0, 0, null);
g2.dispose();
}
private class MazeControlsKeyListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
}
}
}
}
Here's a problem:
final Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
Don't use a java.util.Timer in a Swing program as you will have threading problems. Instead use a Swing Timer.
Also, you're making Swing calls in background threads and using Graphics object obtained by calling getGraphics() on a component, two no-nos for Swing programs.
EDIT
Here is a program that I worked on that swaps components with a CardLayout, but fades one component out as it fades the other one in. What it does:
The program adds all the swapping components to the CardLayout using JPanel.
It also adds a single SwappingImgPanel, a JPanel created to draw two images, one of the component that is fading out, and one of the component that is fading in.
When you swap components, you create images of the two components, the one currently visible, and the one that will next be visible.
You send the images to the SwappingImgPanel instance
You call swap() on the SwappingImgPanel instance.
The SwappingImgPanel will then draw both images but uses a Swing Timer to change the Graphic object's composite value. This is what causes an image to be partially visible.
When the SwappingImgPanel's Timer is done, a done() method is called which sets the SwappingImgPanel's State to State.DONE.
The main GUI is listening to the SwappingImgPanel's state value, and when it achieves State.DONE, the main GUI shows the actual next component (and not an image of it).
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;
#SuppressWarnings("serial")
public class DimmingPanelSwaps extends JPanel {
private static final int DELTA_TIME = 10;
private static final int ELAPSED_TIME = 3000;
private static final String SWAPPING_IMG_PANEL = "swapping img panel";
private CardLayout cardlayout = new CardLayout();
private JPanel cardHolderPanel = new JPanel(cardlayout);
private DefaultComboBoxModel<String> comboModel = new DefaultComboBoxModel<>();
private JComboBox<String> cardCombo = new JComboBox<>(comboModel);
private Map<String, JComponent> componentMap = new HashMap<String, JComponent>();
private String key = "";
private SwappingImgPanel swappingImgPanel = new SwappingImgPanel(DELTA_TIME, ELAPSED_TIME);
public DimmingPanelSwaps() {
registerComponent(createComponentOne(), "one");
registerComponent(createComponentTwo(), "two");
registerComponent(createComponentThree(), "three");
registerComponent(createComponentFour(), "four");
key = "one";
cardHolderPanel.add(swappingImgPanel, SWAPPING_IMG_PANEL);
JPanel southPanel = new JPanel();
southPanel.add(cardCombo);
setLayout(new BorderLayout());
add(cardHolderPanel, BorderLayout.CENTER);
add(southPanel, BorderLayout.SOUTH);
swappingImgPanel.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (pcEvt.getNewValue() == State.DONE) {
cardlayout.show(cardHolderPanel, key);
cardCombo.setEnabled(true);
}
}
});
cardCombo.addActionListener(new CardComboListener());
}
private JPanel createComponentFour() {
int rows = 4;
int cols = 4;
int gap = 5;
int tfColumns = 8;
JPanel panel = new JPanel(new GridLayout(rows, cols, gap, gap));
for (int i = 0; i < rows * cols; i++) {
JTextField textField = new JTextField(tfColumns);
JPanel tfPanel = new JPanel();
tfPanel.add(textField);
panel.add(tfPanel);
}
return panel;
}
private JLabel createComponentThree() {
int biWidth = 200;
BufferedImage img = new BufferedImage(biWidth, biWidth, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(new GradientPaint(0, 0, Color.red, 20, 20, Color.blue, true));
g2.fillOval(0, 0, biWidth, biWidth);
g2.dispose();
Icon icon = new ImageIcon(img);
JLabel label = new JLabel(icon);
return label;
}
private JScrollPane createComponentTwo() {
JTextArea textArea = new JTextArea(15, 40);
JScrollPane scrollpane = new JScrollPane(textArea);
scrollpane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
scrollpane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
return scrollpane;
}
private JPanel createComponentOne() {
JPanel innerPanel = new JPanel(new GridLayout(1, 0, 5, 0));
String[] btnTitles = {"One", "Two", "Three"};
for (String btnTitle : btnTitles) {
JButton btn = new JButton(btnTitle);
innerPanel.add(btn);
}
JPanel panel = new JPanel(new GridBagLayout());
panel.add(innerPanel);
return panel;
}
#SuppressWarnings("hiding")
private void registerComponent(JComponent jComp, String key) {
cardHolderPanel.add(jComp, key);
componentMap.put(key, jComp);
comboModel.addElement(key);
}
private class CardComboListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
final String oldKey = key;
key = (String) cardCombo.getSelectedItem();
cardCombo.setEnabled(false);
final JComponent firstComp = componentMap.get(oldKey);
final BufferedImage firstImg = extractComponentImg(firstComp);
final JComponent secondComp = componentMap.get(key);
final BufferedImage secondImg = extractComponentImg(secondComp);
cardlayout.show(cardHolderPanel, SWAPPING_IMG_PANEL);
swappingImgPanel.setFirstImg(firstImg);
swappingImgPanel.setSecondImg(secondImg);
swappingImgPanel.swap();
}
private BufferedImage extractComponentImg(final JComponent component) {
Dimension size = component.getSize();
BufferedImage img = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
component.paint(g2);
g2.dispose();
return img;
}
}
private static void createAndShowGui() {
DimmingPanelSwaps mainPanel = new DimmingPanelSwaps();
JFrame frame = new JFrame("Dimming Panel Swaps");
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();
}
});
}
}
/**
* A JPanel that draws two images
* When swap is called, the first image is shown
* Then a Timer dims the first image while it reveals
* the second image.
* When the elapsed time is complete, it sets its state to State.DONE.
* #author Pete
*
*/
#SuppressWarnings("serial")
class SwappingImgPanel extends JPanel {
public static final String STATE = "state";
private BufferedImage firstImg;
private BufferedImage secondImg;
private int deltaTime;
private int elapsedTime;
// state is a "bound" property, one that is listened to via PropertyChangeSupport
private State state = State.PENDING;
private float alpha1;
private float alpha2;
public SwappingImgPanel(final int deltaTime, final int elapsedTime) {
this.deltaTime = deltaTime;
this.elapsedTime = elapsedTime;
}
public void swap() {
setState(State.STARTED);
if (firstImg == null || secondImg == null) {
done();
}
alpha1 = 1.0f;
alpha2 = 0.0f;
new Timer(deltaTime, new ActionListener() {
private int counter = 0;
private int max = elapsedTime / deltaTime;
#Override
public void actionPerformed(ActionEvent e) {
if (counter >= elapsedTime / deltaTime) {
((Timer)e.getSource()).stop();
done();
return;
}
// set new alpha composite values
alpha1 = ((float)max - counter) / (float) max;
alpha2 = (float) counter / (float) max;
// make sure alphas are within bounds
alpha1 = Math.min(1f, alpha1);
alpha1 = Math.max(0f, alpha1);
alpha2 = Math.min(1f, alpha2);
alpha2 = Math.max(0f, alpha2);
repaint();
counter++;
}
}).start();
}
private void done() {
firstImg = null;
secondImg = null;
setState(State.DONE);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (firstImg == null || secondImg == null) {
return;
}
// create a new Graphics2D object with g.create()
// to avoid any possible side effects from changing the
// composite of the JVM's Graphics object
Graphics2D g2 = (Graphics2D) g.create();
// set the first alpha composite, and draw the image
g2.setComposite(((AlphaComposite)g2.getComposite()).derive(alpha1));
g2.drawImage(firstImg, 0, 0, this);
// set the second alpha composite, and draw the image
g2.setComposite(((AlphaComposite)g2.getComposite()).derive(alpha2));
g2.drawImage(secondImg, 0, 0, this);
g2.dispose(); // can get rid of this Graphics because we created it
}
public void setFirstImg(BufferedImage firstImg) {
this.firstImg = firstImg;
}
public void setSecondImg(BufferedImage secondImg) {
this.secondImg = secondImg;
}
public State getState() {
return state;
}
public void setState(State state) {
State oldValue = this.state;
State newValue = state;
this.state = state;
firePropertyChange(STATE, oldValue, newValue);
}
}
/**
* Modeled on SwingWorker.StateValue
* #author Pete
*
*/
enum State {
PENDING, STARTED, DONE
}

How to do different drawings in different methods using paintComponent? [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I have 2 classes, one which extends a panel and other which extends a frame.
First class, the panel(used for drawings):
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class GraficPne extends JPanel{
public int dim1 = 0, dim2 = 0;
public JLabel lblSem1GraficPne, lblSem2GraficPne;
public GraficPne(){
super();
this.setLayout(null);
this.setupComponents();
}
public void setupComponents(){
lblSem1GraficPne = new JLabel("Sem I");
lblSem2GraficPne = new JLabel("Sem II");
lblSem1GraficPne.setFont(new Font("Serif", Font.PLAIN, 12));
lblSem2GraficPne.setFont(new Font("Serif", Font.PLAIN, 12));
this.add(lblSem1GraficPne);
this.add(lblSem2GraficPne);
}
public void layComponents(int firstConv, int secondConv){
lblSem1GraficPne.setBounds(20, getHeight() - firstConv - 20, 100, 20);
lblSem2GraficPne.setBounds(100, getHeight() - secondConv - 20, 100, 20);
}
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.BLACK);
g.drawRect(0, 0, getWidth()-1, getHeight()-1);
this.setBackground(Color.GREEN);
g.setColor(Color.RED);
g.fillRect(20, getHeight()-dim1, 40, dim1);
g.setColor(Color.BLUE);
g.fillRect(100, getHeight()-dim2, 40, dim2);
}
public void setData(int dim1, int dim2){
this.dim1 = dim1;
this.dim2 = dim2;
}
}
Second class, the frame, used to add the panel on it:
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
public class GraficFrm extends JFrame implements ActionListener{
private JButton btnApply;
private JLabel lblSem1, lblSem2;
private JTextField txtSem1, txtSem2;
private GraficPne ob; //the object from first class
private int firstConv = 0, secondConv = 0;
public GraficFrm() {
super("Grafic soft");
initSettings();
setupComponents();
}
private void initSettings() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(null);
this.setSize(400, 450);
this.setLocation(100, 100);
this.setResizable(false);
}
private void setupComponents() {
ob = new GraficPne();
lblSem1 = new JLabel("Sem I");
txtSem1 = new JTextField();
lblSem2 = new JLabel("Sem II");
txtSem2 = new JTextField();
btnApply = new JButton("Apply");
ob.setBounds(30, 50, 340, 200);
lblSem1.setBounds(30, 280, 100, 20);
txtSem1.setBounds(150, 280, 220, 20);
lblSem2.setBounds(30, 330, 100, 20);
txtSem2.setBounds(150, 330, 220, 20);
btnApply.setBounds(170, 380, 80, 30);
this.add(lblSem1);
this.add(ob);
this.add(txtSem1);
this.add(lblSem2);
this.add(txtSem2);
this.add(btnApply);
btnApply.addActionListener(this);
}
public void getConvertedValues(){
String txtField1 = txtSem1.getText();
firstConv = Integer.parseInt(txtField1);
String txtField2 = txtSem2.getText();
secondConv = Integer.parseInt(txtField2);
}
public void getHighValues(){
if((firstConv > 100) || (secondConv > 100)) {
JOptionPane.showMessageDialog(this, "Only values < 100 are allowed");
firstConv = 0;
secondConv = 0;
txtSem1.setText("");
txtSem2.setText("");
ob.removeAll();
ob.repaint();
}
}
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(btnApply)){
try{
new GraficFrm();
getConvertedValues();
getHighValues();
ob.setData(firstConv, secondConv);
ob.layComponents(firstConv,secondConv);
ob.repaint();
}catch(NumberFormatException ex1){
JOptionPane.showMessageDialog(this, "Only natural numbers are allowed");
}
}
}
public static void main(String[] args) {
GraficFrm frm = new GraficFrm();
frm.setVisible(true);
}
}
All I want to do is to create a new method called getNegativeValues(), which would be called by pressing the Apply button, and this method to be executed when firstConv or secondConv would be < than 0. The block of my method, getNegativeValues(), i want to keep only the green background of the panel, as it is in paint(Graphics g), but to draw a center horizontal line(g.drawLine(0, getHeight()/2, getWidth(), getHeight()/2);). Then, when i execute the program and i type, let's say the value 55 for the first textfield and -40 for the second one, to draw 55 over my center horizontal line and -40 under my center horizontal line, and the 0 point would be on this center horizontal line.
LE:
#nIcE cOw i'll make a short recap: So, first, when i execute my app, i just want to appear my green panel and those 2 labels which have 2 textfields, as in my example(try to follow my example, please)(all good, i already did this, so this part is done). After, when i complete those 2 textfields let's say with 2 positive values, and then when i press the Apply button to happen exactly like in my example(without any center vertical line)(so already did this, also). All good, but my problem is: If complete one of those 2 textfields with a negative value and other with a positive one, and after i press the Apply button, i want that my application to recognize that there is a negative value typped in one of my textfields, thus to draw me on my green panel a center horizontal line(after i press the Apply button) and to draw those 2 rectangles exactly as you did in your first picture uploaded. Please help me, as i said i'll help you to understand what i want to do, and also i want to say i really appreciate your effort and i'm sorry (again) if i was confused(again).
I guess, what you looking for is a method as presented below, that might can calculate, the starting point of Rectangles that you are trying to draw on the JPanel. Here pos is Positive Value and neg is Negative Value:
public void setValues(int above, int below)
{
midPoint = getHeight() / 2;
heightAbove = Math.abs(above);
heightBelow = Math.abs(below);
/*
* If both are negative values,
* we need a Mid-Point in this case.
*/
if (above < 0 && below < 0)
{
rectAbove = midPoint;
diff = 120;
rectBelow = midPoint;
flag = true;
}
else if (above >= 0 && below >= 0)
{
rectAbove = getHeight() - heightAbove;
diff = 120;
rectBelow = getHeight() - heightBelow;
flag = false;
}
else if (above < 0 && below >= 0)
{
rectAbove = midPoint;
diff = 40;
rectBelow = midPoint - heightBelow;
flag = true;
}
else if (above >= 0 && below < 0)
{
rectAbove = midPoint - heightAbove;
diff = 40;
rectBelow = midPoint;
flag = true;
}
repaint();
}
Here is the code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PaintingRectangles
{
private JTextField aboveField;
private JTextField belowField;
private JButton applyButton;
private MyCanvas canvas;
private void displayGUI()
{
JFrame frame = new JFrame("Painting Rectangles Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout(5, 5));
JPanel rightPanel = new JPanel();
rightPanel.setLayout(new GridLayout(3, 1, 5, 5));
aboveField = new JTextField(10);
belowField = new JTextField(10);
applyButton = new JButton("Apply");
applyButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent ae)
{
int above = 0;
int below = 0;
try
{
above = Integer.parseInt(aboveField.getText());
below = Integer.parseInt(belowField.getText());
}
catch(NumberFormatException nfe)
{
aboveField.setText("0");
belowField.setText("0");
above = 0;
below = 0;
nfe.printStackTrace();
}
canvas.setValues(above, below);
}
});
rightPanel.add(aboveField);
rightPanel.add(belowField);
rightPanel.add(applyButton);
canvas = new MyCanvas();
contentPane.add(canvas, BorderLayout.CENTER);
contentPane.add(rightPanel, BorderLayout.LINE_END);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
new PaintingRectangles().displayGUI();
}
});
}
}
class MyCanvas extends JPanel
{
private int midPoint = getHeight() / 2;
private int rectAbove = getHeight() / 2;
private int rectBelow = getHeight() / 2;
private int width = 40;
private int heightAbove = 0;
private int heightBelow = 0;
private int diff = 0;
private boolean flag = false;
public MyCanvas()
{
setBackground(Color.GREEN);
}
public void setValues(int above, int below)
{
midPoint = getHeight() / 2;
heightAbove = Math.abs(above);
heightBelow = Math.abs(below);
/*
* If both are negative values,
* we need a Mid-Point in this case.
*/
if (above < 0 && below < 0)
{
rectAbove = midPoint;
diff = 120;
rectBelow = midPoint;
flag = true;
}
else if (above >= 0 && below >= 0)
{
rectAbove = getHeight() - heightAbove;
diff = 120;
rectBelow = getHeight() - heightBelow;
flag = false;
}
else if (above < 0 && below >= 0)
{
rectAbove = midPoint;
diff = 40;
rectBelow = midPoint - heightBelow;
flag = true;
}
else if (above >= 0 && below < 0)
{
rectAbove = midPoint - heightAbove;
diff = 40;
rectBelow = midPoint;
flag = true;
}
repaint();
}
#Override
public Dimension getPreferredSize()
{
return (new Dimension(400, 400));
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLACK);
g.drawRect(0, 0, getWidth(), getHeight());
if (flag)
g.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
makeRectangles(g);
}
private void makeRectangles(Graphics g)
{
g.setColor(Color.RED);
g.fillRect(40, rectAbove, width, heightAbove);
g.setColor(Color.BLUE);
g.fillRect(diff, rectBelow, width, heightBelow);
g.dispose();
}
}
Here is the output:

Change background and font color of jpanel on button click

I want to change Background color of Jpanel and its font on button click.
Can anyone tell me what i am doing wrong?
Can I set JPanel background transparent?if yes How?
On button click test4.action method is called where i need to change Jpanel background color?
Here is the code:
import java.applet.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.event.*;
import javax.swing.*;
public class test3 extends Applet {
JPanel c;
JScrollPane s;
Button connect;
Panel controls;
Color back, fore;
public void init() {
back = Color.black;
fore = Color.white;
setBackground(Color.darkGray);
setLayout(new BorderLayout());
s = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
//s.setSize(100, 100);
add("Center", s);
c = new myCanvas11(this);
s.setOpaque(false);
s.setViewportView(c);
//s.add(c);
c.setSize(1000, 16000);
add("North", controls = new Panel());
controls.setLayout(new FlowLayout());
controls.add(connect = new Button("Change Color"));
}
public void start() {
// s.setScrollPosition(100, 100);
}
public boolean action(Event e, Object arg) {
back = Color.magenta;
fore = Color.blue;
//setBackground(back);
//invalidate();
//repaint();
c.setBackground(back);
c.repaint();
//s.getViewport().setBackground(back);
// s.getViewport().repaint();
//c.repaint();
c.setFocusable(true);
return true;
}
}
class myCanvas11 extends JPanel implements KeyListener {
Image buffImage;
Graphics offscreen;
boolean initDone = false;
int chw, chh; // size of a char (in pixels)
int chd; // offset of char from baseline
int width, height; // size of applet (in pixels)
int w, h; // size of applet (in chars)
Font fn;
Graphics gr;
int nh, nw;
test3 owner;
static int counter = 0;
myCanvas11(test3 t) {
super();
owner = t;
nh = 16000;
nw = 1000;
this.setOpaque(true);
this.setFocusable(true);
addKeyListener(this);
}
public void reshape(int nx, int ny, int nw1, int nh1) {
if (nw1 != width || nh1 != height) {
width = nw;
height = nh;
gr = getGraphics();
fn = new Font("Courier", Font.PLAIN, 11);
if (fn != null) {
gr.setFont(fn);
}
FontMetrics fnm = gr.getFontMetrics();
chw = fnm.getMaxAdvance();
chh = fnm.getHeight();
chd = fnm.getDescent();
// kludge for Windows NT and others which have too big widths
if (chw + 1 >= chh) {
chw = (chw + 1) / 2;
}
// work out size of drawing area
h = nh / chh;
w = nw / chw;
buffImage = this.createImage(nw, nh);
offscreen = buffImage.getGraphics();
//offscreen.setColor(Color.black);
//offscreen.fillRect(0, 0, nw, nh);
offscreen.setColor(Color.blue);
offscreen.setFont(fn);
if (initDone) {
offscreen.drawString("Hello World!", 0, 50);
} else {
offscreen.drawString("khushbu", 2, 50);
}
initDone = true;
offscreen.drawImage(buffImage, 0, 0, this);
}
super.reshape(nx, ny, nw, nh);
}
public void paint(Graphics g) {
// if (!initDone)
// initpaint(g);
// else
g.drawImage(buffImage, 0, 0, this);
//g.drawImage(buffImage, 0, 0, owner.back, this);
}
public void update(Graphics g) {
g.drawImage(buffImage, 0, 0, this);
super.update(g);
//g.drawImage(buffImage, 0, 0, owner.back, this);
}
public void initpaint(Graphics g) {
try {
nh = getHeight();
nw = getWidth();
gr = getGraphics();
fn = new Font("Courier", Font.PLAIN, 11);
if (fn != null) {
gr.setFont(fn);
}
FontMetrics fnm = gr.getFontMetrics();
chw = fnm.getMaxAdvance();
chh = fnm.getHeight();
chd = fnm.getDescent();
// kludge for Windows NT and others which have too big widths
if (chw + 1 >= chh) {
chw = (chw + 1) / 2;
}
// work out size of drawing area
h = nh / chh;
w = nw / chw;
buffImage = this.createImage(nw, nh);
offscreen = buffImage.getGraphics();
//offscreen.setColor(Color.black);
//offscreen.fillRect(0, 0, nw, nh);
offscreen.setColor(Color.white);
offscreen.setFont(fn);
if (initDone) {
offscreen.drawString("Hello World!", 0, 50);
} else {
offscreen.drawString("khushbu", 2, 50);
}
initDone = true;
g.drawImage(buffImage, 0, 0, this);
} catch (Exception e) {
e.printStackTrace();
}
}
/** Handle the key typed event from the text field. */
public void keyTyped(KeyEvent e) {
}
/** Handle the key pressed event from the text field. */
public void keyPressed(KeyEvent e) {
String s;
offscreen.setColor(owner.fore);
offscreen.setFont(fn);
for (int i = counter; i < counter + 25; ++i) {
s = Integer.toString(i);
offscreen.drawString(s, 3, i * chh);
offscreen.drawLine(10, i * chh, 160, i * chh);
}
//owner.s.setScrollPosition(0, counter * 16);
counter = counter + 25;
repaint();
}
/** Handle the key released event from the text field. */
public void keyReleased(KeyEvent e) {
}
public boolean keyDown(Event e, int k) {
String s;
offscreen.setColor(owner.fore);
offscreen.setFont(fn);
for (int i = counter; i < counter + 25; ++i) {
s = Integer.toString(i);
offscreen.drawString(s, 3, i * chh);
offscreen.drawLine(10, i * chh, 160, i * chh);
}
//owner.s.setScrollPosition(0, counter * 16);
counter = counter + 25;
repaint();
return true;
}
}
Can I set JPanel background transparent?if yes How?
Yes, just call setOpaque(false); on that JPanel. On the contrary, if you want the background to be painted, call setOpaque(true); on that panel.
Additional remarks:
public boolean action(Event e, Object arg) is Deprecated. Add the appropriate listeners instead.
Follow Java coding conventions and use an Uppercase letter for the first character of a class
You should almost never call getGraphics(); on a Component
Don't override public void paint(Graphics g) but protected void paintComponent(Graphics g). Don't forget to call super.paintComponent if you want the background to be painted
Why do you override reshape?
Why do you create an internal buffer? Swing already has built-in double buffering and they do a much better job.
If you overrode already paint() why do you also override update()? You are performing the same job twice.
Remove that gr class variable, it does not make any sense. When you use Graphics object, use the one provided as a parameter of the paintComponent method but don't keep a reference to it, as it will be disposed later.
counter does not need to be static. Try to avoid static as much as possible.
Try to avoid so much coupling between your classes. It makes your code harder to maintain and less predictable.
Next time, post an SSCCE with something else than an Applet (a JFrame, for example) unless the problem you are having really requires an Applet to be reproduced.

Categories