i'm making a tank game. in my menu i want to use pictures as jbuttons, they are partly transparent and when they appear on screen the transparent parts become white.
i tried using .setOpaque but this doesn't work. i can't think of any other method to get rid of the white parts. i've been looking all over stack overflow but none of the methods seem to help. anyone who has an idea?
Thanks!
package menu;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class MenuPanel extends JPanel implements ActionListener
{
private Button playKnop, highScoreKnop, quitKnop, HTPKnop;
private JTextField naam;
private Image achtergrond;
private Tanks mainVenster;
public static String naam_input;
int x = 95, width = 200, height = 50;
public MenuPanel(Tanks mainVenster)
{
this.mainVenster = mainVenster;
this.setLayout(null);
playKnop = new Button("/buttons/PLAY.png", 350, this);
highScoreKnop = new Button("/buttons/HS.png", 460, this);
HTPKnop = new Button("/buttons/HTP.png", 515, this);
quitKnop = new Button("/buttons/QUIT.png", 570, this);
this.add(playKnop);
this.add(quitKnop);
this.add(HTPKnop);
this.add(highScoreKnop);
validate();
}
public class Button extends JButton
{
JButton button;
ImageIcon buttonImage;
String backgroundPath;
int y;
public Button(String backgroundPath, int y, MenuPanel menuPanel)
{
super();
this.backgroundPath = backgroundPath;
this.y = y;
buttonImage = new
ImageIcon(PlayPanel.class.getResource(backgroundPath));
this.setIcon(buttonImage);
this.setBounds(x, y, width, height);;
this.addActionListener(menuPanel);
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(achtergrond, 0, 0, this.getWidth(), this.getHeight(),
this);
}
}
Remove some of the default rendering properties of the JButton including
contentAreaFilled
borderPainted
focusPainted
Which will reduce the button to, well, nothing. JButton already supports the painting of icons (and can do so for a verity of states), so there should be no need to override it's paintComponent method...
public class TestPane extends JPanel {
public TestPane() {
setBackground(Color.RED);
setLayout(new GridBagLayout());
try {
BufferedImage img = ImageIO.read(getClass().getResource("/1xaN3.png"));
JButton btn = new JButton(new ImageIcon(img));
btn.setOpaque(false);
btn.setContentAreaFilled(false);
btn.setBorderPainted(false);
btn.setFocusPainted(false);
add(btn);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Personally, I prefer to load my images using ImageIO instead of ImageIcon (or other methods), mostly because it will throw an IOException if something goes wrong (rather the failing silently) and won't return until the image is loaded (and supports progress feedback if you do it right)
Have a look at Reading/Loading an Image for more details
Related
I'm making a browser just to practice my Java skills, is there a way to make my address bar which is a JTextField, larger instead of the swing's default value and also curvier. Here's my code.
//imports of the GUI
//import java.awt.*;
//import java.awt.event.*;
//import javax.swing.*;
//import javax.swing.event.*;
//import javax.swing.text.*;
//import javax.swing.GroupLayout.*;
//extends is to use the GUI class
public class ReadFile extends JFrame {
private JTextField addressBar; //to have the address bar
private JEditorPane display; //display the html information
//constructor
//Set the frame icon to an image loaded from a file.
public ReadFile() {
super("SPHERE"); //name of the browser
addressBar = new JTextField("enter an URL", 50); //inside the URL
addressBar.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent event){
loadCrap(event.getActionCommand());
}
}
);
add(addressBar, BorderLayout.NORTH);
display = new JEditorPane();
display.setEditable(false);
display.addHyperlinkListener(
new HyperlinkListener(){
public void hyperlinkUpdate(HyperlinkEvent event){
if(event.getEventType()==HyperlinkEvent.EventType.ACTIVATED){
loadCrap(event.getURL().toString());
}
}
}
);
add(new JScrollPane(display), BorderLayout.CENTER);
setSize(600,200);
setVisible(true);
}
//load crap to display on the screen
private void loadCrap(String userText){
try{display.setPage(userText);
addressBar.setText(userText);}catch(Exception e){System.out.println("crap!")}
}
}
I want to make a really usable browser, like I want the html and its' CSS pages to show, what else do I have to learn to make this work.
Almost all of this comes down to manipulating the border, but this may not produce the results your after, for example...
JTextField field = new JTextField(10);
field.setBorder(new CompoundBorder(field.getBorder(), new EmptyBorder(10, 0, 10, 0)));
Creating a rounded border is more difficult...
and also curvier
There are a few ways you might achieve, this for example, you could create a Border of your own, for example...
public class RoundedBorder extends AbstractBorder {
#Override
public Insets getBorderInsets(Component c, Insets insets) {
insets.left = 5;
insets.right = 5;
insets.top = 5;
insets.bottom = 5;
return insets;
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Graphics2D g2d = (Graphics2D) g.create();
RoundRectangle2D shape = new RoundRectangle2D.Float(0, 0, width - 1, height - 1, 20, 20);
g2d.setColor(Color.BLACK);
g2d.draw(shape);
g2d.dispose();
}
}
Then apply it to your field...
field.setBorder(new CompoundBorder(new RoundedBorder(), new EmptyBorder(10, 0, 10, 0)));
Which produces something like...
But I don't like this, as, if you look closely, the area outside the border is still painted...You could have the border fill this area, but I like having the ability to provide transparent capabilities to components, so instead, you could fake it...
Basically, what this does is creates a custom component that can paint the around the field, but, because it can better control the painting process, can also provide transparency outside the border effect...
public class FakeRoundedBorder extends JPanel {
private JTextField field;
public FakeRoundedBorder(JTextField field) {
this.field = field;
setBorder(new EmptyBorder(5, 5, 5, 5));
field.setBorder(new EmptyBorder(10, 0, 10, 0));
setLayout(new BorderLayout());
add(field);
setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
RoundRectangle2D shape = new RoundRectangle2D.Float(0, 0, getWidth() - 1, getHeight() - 1, 20, 20);
g2d.setColor(field.getBackground());
g2d.fill(shape);
g2d.setColor(Color.BLACK);
g2d.draw(shape);
g2d.dispose();
}
}
This is just a bunch of examples of course, you'll need to clean it up and provide customisation to the values yourself ;)
I'm not sure what you mean by "curvier". But here's a way to resize it and set the font:
addressBar.setFont(new Font("TimesRoman", Font.ITALIC, 30));
Alright, I figured out everything that I got but now I am really stuck. Every time you choose a different shape the previously selected one disappears. How do I make it so they don't disappear and stay on the screen until you exit?
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;
public class ShapeStamper extends JFrame{
Random rand = new Random();
public int x;
public int y;
private JPanel panel1, panel2;
private JButton button1, button2, button3, button4;
private int option = 0;
public ShapeStamper(){
super("Shape Stamper!");
panel1 = new JPanel();
button1 = new JButton("Circle");
button2 = new JButton("Square");
button3 = new JButton("Rectangle");
button4 = new JButton("Oval");
button1.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent ae){
option = 1;
}
}
);
button2.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent ae){
option = 2;
}
}
);
button3.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent ae){
option = 3;
}
}
);
button4.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent ae){
option = 4;
}
}
);
panel2 = new JPanel();
panel2.setBackground(Color.WHITE);
MouseHandler mouse = new MouseHandler();
setVisible(true);
addMouseListener(mouse);
addMouseMotionListener(mouse);
add(panel2);
panel1.add(button1);
panel1.add(button2);
panel1.add(button3);
panel1.add(button4);
add(panel1, BorderLayout.SOUTH);
setSize(500,500);
setVisible(true);
}
private class MouseHandler extends MouseAdapter implements MouseMotionListener{
#Override
public void mousePressed(MouseEvent e){
x = e.getX();
y = e.getY();
repaint();
}
}
public void paint(Graphics g){
super.paintComponents(g);
Graphics2D g2d = (Graphics2D) g;
if(option == 0){
g.setFont(new Font("Serif", Font.BOLD, 32));
g.drawString("Shape Stamper!", 150, 220);
g.setFont(new Font("Serif", Font.ITALIC, 16));
g.drawString("Programmed by: Chris", 150, 230);
}
if(option == 1){
Color randColor1 = new Color(rand.nextInt(256), rand.nextInt(256), rand.nextInt(256));
g2d.setPaint(randColor1);
g2d.drawOval(50, 50, 100, 100);
}
if(option == 2){
Color randColor2 = new Color(rand.nextInt(256), rand.nextInt(256), rand.nextInt(256));
g2d.setPaint(randColor2);
g2d.drawRect(50, 50, 100, 100);
}
if(option == 3){
Color randColor3 = new Color(rand.nextInt(256), rand.nextInt(256), rand.nextInt(256));
g2d.setPaint(randColor3);
g2d.draw(new Rectangle2D.Double(75,50,150,100));
}
if(option == 4){
Color randColor4 = new Color(rand.nextInt(256), rand.nextInt(256), rand.nextInt(256));
g2d.setPaint(randColor4);
g2d.draw(new Ellipse2D.Double(50, 25, 100, 50));
}
}
public static void main(String[] args) {
ShapeStamper application = new ShapeStamper();
application.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
You should not be overriding paint of a top level container and then trying to painting over the top of the components you have already added.
The basic problem you will encounter is, the paint system is clever enough that it may not ever call paint of the frame, but simply update the child components directly instead.
Instead, create yourself a custom component, extending from something like JPanel and override it's paintComponent method and perform your custom painting there. Then add this component to your frame.
You will also find the the paint updates are cleaner and won't flicker when updated.
You should also make sure you are calling repaint on this custom component when ever you change one it's options to ensure that changes are painted back to the component
Take a look at Performing Custom Painting for more details.
Also, just to be clear, you should not be calling super.paintComponents from paint (or in fact anywhere except for when you override paintComponents...which there really should be a need to do...)
First of all, sorry for the vague title I don't know how to word the question in a sentence.
I have a simple programme that slides one JPanel into view as another gets pushed out, when a button is clicked.
If the first JPanel's width is set as getWidth() then the JPanel will not move when the button is clicked, however if I change the width to getWidth() - 1 it works perfectly fine!?!
A simple example is shown below
public class SlidingJPanel extends JFrame{
public JPanel panel = new JPanel();
public JPanel panel2 = new JPanel();
public JLabel label = new JLabel(" SUCCESS!!!!!!!");
public JButton button = new JButton("TESTING");
public class MyJPanel extends JPanel implements ActionListener{
public int x = 0;
public int delay = 70;
final Timer timer = new Timer(delay,this);
public MyJPanel(){};
public void paintComponent(Graphics g)
{
super.paintComponent(g);
button.setBounds(10, 20, 100, 50);
button.addActionListener(this);
panel.setBorder(BorderFactory.createLineBorder(Color.black));
panel.setBounds(x, 0, getWidth(), getHeight());
panel.add(button);
panel2.setBorder(BorderFactory.createLineBorder(Color.blue));
panel2.setBounds(x - getWidth(), 0, getWidth(), getHeight());
panel2.add(label);
add(panel);
add(panel2);
}
#Override
public void actionPerformed(ActionEvent arg0) {
timer.addActionListener(move);
timer.start();
}
ActionListener move = new ActionListener(){
public void actionPerformed(ActionEvent e){
repaint();
x++;
}
};
}
public static void main(String args [])
{
new SlidingJPanel();
}
SlidingJPanel()
{
Container container = getContentPane();
MyJPanel panel = new MyJPanel();
container.add(panel);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(500,500);
setTitle("JPanel Draw Rect Animation");
setVisible(true);
}
}
ignore any coding conventions I may have ignored or missed this is just a rough draft.
Hope someone can help :)
The paintComponent() method is for painting only! There is no need for you to override this method.
You should NOT be:
updating the property of components (ie. bounds, border)
adding components to a container
If you want to animate a component then when the timer fires you can use setLocation(...) or setSize() or setBounds(). The component will automatically be repainted.
I don't know if fixing this will solve your problem, but the current approach is wrong.
I've got an applet with radio buttons to select the color of the line, but when I try to run it, I get this error:
java.lang.NullPointerException
This is what I have thus far. Any suggestions on making color selection work?
import java.awt.*;
import java.applet.*;
import javax.swing.*;
import java.awt.event.*;
public class ProjectPaint extends Applet {
private JRadioButton redButton = new JRadioButton("Red");
private JRadioButton blueButton = new JRadioButton("Blue");
private JRadioButton greenButton = new JRadioButton("Green");
private JRadioButton blackButton = new JRadioButton("Black");
Graphics g;
public void init() {
// Create a border layout design
setLayout(new BorderLayout());
// Make a new object of type DrawPanel
DrawPanel dp = new DrawPanel();
// Add a draw panel in the center
add("Center", dp);
// Add another draw panel for color selection on top
add("North",new DrawControls(dp));
}
int x1;
int y1;
class DrawPanel extends Panel
{
public boolean mouseDown(Event e, int x, int y)
{
// User has started a mouse drag.
// Remember where:
x1 = x;
y1 = y;
return true;
}
public boolean mouseDrag(Event e, int x, int y)
{
// User is continuing a mouse drag.
// Draw line from last point to this
// point:
g = getGraphics();
g.drawLine( x1,y1, x,y );
// Remember new "last point":
x1 = x;
y1 = y;
return true;
}
}
class DrawControls extends Panel
{
public DrawControls(DrawPanel target)
{
setLayout(new BorderLayout());
JPanel panel = new JPanel();
ButtonGroup radioButtonGroup = new ButtonGroup();
radioButtonGroup.add(redButton);
radioButtonGroup.add(blueButton);
radioButtonGroup.add(greenButton);
radioButtonGroup.add(blackButton);
panel.add(redButton);
panel.add(blueButton);
panel.add(greenButton);
panel.add(blackButton);
add(panel, BorderLayout.NORTH);
redButton.addActionListener(new RadioButtonListener());
blueButton.addActionListener(new RadioButtonListener());
greenButton.addActionListener(new RadioButtonListener());
blackButton.addActionListener(new RadioButtonListener());
blackButton.doClick();
}
}
private class RadioButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
int color = -1;
if(e.getSource() == redButton)
{
g.setColor(Color.red);
}
if(e.getSource() == blueButton)
{
g.setColor(Color.blue);
}
if(e.getSource() == greenButton)
{
g.setColor(Color.green);
}
if(e.getSource() == blackButton)
{
g.setColor(Color.black);
}
}
}
}
The Graphics reference has not been assigned hence the NPE.
Don't attempt any custom painting from an ActionListener or MouseListener. Instead use a Color class member variable to set the color. For Swing applications, all custom painting should be done in the paintComponent method. In this case DrawPanel will need to changed so as to extend JPanel so that it can override the method. Add the #Override annotation and make sure to invoke super.paintComponent(g).
JApplet has support for the JFC/Swing component architecture so use that also.
I have a case where I put the JLabel inside JButton and adapts the JButton size.
The issue here is everytime I click the button, the JLabel catches most of the events.
When I tried to add ActionListener to the JButton, it didn't work.
But when I tried to add MouseListener to JLabel, all the event handlers work.
I want the ActionListener for the JButton to work. I don't want the JLabel to catches all of the events without destroying my default configuration on them.
I tried setting the JLabel focusable property to false but it didn't work also.
So what should I do then?
I have a case where I put the JLabel inside JButton and adapts the
JButton size.
this is basic property, by default top layed JComponent consume all events came from Mouse & Keyboard
there are two ways
(no idea why is there JLabel) if is possible to use plain JButton with implemented methods in API instead
add MouseListener (maybe there no reason to override all MouseEvents add only MouseAdapter) to JLabel and from mouseClicked to call JButton.doClick()
EDIT
#Mad,
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.swing.*;
public class JButtonAndIcon {
private JLabel label = new JLabel();
private Random random = new Random();
private ImageIcon image1; // returns null don't worry about in Swing
private ImageIcon image2; // returns null don't worry about in Swing
private Timer backTtimer;
private int HEIGHT = 300, WEIGHT = 200;
public JButtonAndIcon() {
label.setPreferredSize(new Dimension(HEIGHT, WEIGHT));
final JButton button = new JButton("Push");
button.setBorderPainted(false);
button.setBorder(null);
button.setFocusable(false);
button.setMargin(new Insets(0, 0, 0, 0));
button.setContentAreaFilled(false);
button.setLayout(new BorderLayout());
button.add(label);
button.setMultiClickThreshhold(1000);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (button.getIcon() == image1) {
label.setIcon(image2);
} else {
label.setIcon(image1);
if(backTtimer.isRunning()){
backTtimer.restart();
}
}
}
});
JFrame frame = new JFrame("Test");
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
startBackground();
frame.setVisible(true);
}
public static void main(String[] args) throws IOException {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JButtonAndIcon t = new JButtonAndIcon();
}
});
}
private void startBackground() {
backTtimer = new javax.swing.Timer(1500, updateBackground());
backTtimer.start();
backTtimer.setRepeats(true);
}
private Action updateBackground() {
return new AbstractAction("Background action") {
private final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
label.setIcon(new ImageIcon(getImage()));
}
};
}
public BufferedImage getImage() {
int w = label.getWidth();
int h = label.getHeight();
GradientPaint gp = new GradientPaint(0f, 0f, new Color(
127 + random.nextInt(128),
127 + random.nextInt(128),
127 + random.nextInt(128)),
w, w,
new Color(random.nextInt(128), random.nextInt(128), random.nextInt(128)));
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bi.createGraphics();
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
g2d.setColor(Color.BLACK);
return bi;
}
}