Creating a custom button in Java with JButton - java

I am trying to create a button that has a custom shape (hexagon), but otherwise acts like a normal JButton would (that is, works with an ActionListener).
I have created a class that extends AbstractButton, but it doesn't seem to be sending events to the ActionListener when I click it. If I change the class to extend JButton it works perfectly, but it screws up the way the button is displayed. I'm assuming that there is a method that I need to override to get it to fire events, but I can't figure out what it is.

If you want to create a CustomButtonUI then you have to look
deepest to the BasicXxxUI.
overide List of Colors from JButton
Note there isn't paintComponent(). It's wrong, just use the paint() method,
Below is just a simple example if that is possible (for Metal JButton). Note just for Metal LaF, I'm so lazy and there isn't something about override paintText, paintIcon, paintFocus, paintBorder (for all funcionalities you have to check available methods from BasicButtonUI), and something I put to the ButtonModel, just for my enjoyment.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.AbstractBorder;
import javax.swing.border.Border;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.metal.MetalButtonUI;
public class TextAreaInButton {
private JFrame frame = new JFrame("sssssssss");
private JButton tip1Null = new JButton(" test button ");
public TextAreaInButton() {
Border line, raisedbevel, loweredbevel, title, empty;
line = BorderFactory.createLineBorder(Color.black);
raisedbevel = BorderFactory.createRaisedBevelBorder();
loweredbevel = BorderFactory.createLoweredBevelBorder();
title = BorderFactory.createTitledBorder("");
empty = BorderFactory.createEmptyBorder(1, 1, 1, 1);
final Border compound;
Color crl = (Color.blue);
compound = BorderFactory.createCompoundBorder(empty, new OldRoundedBorderLine(crl));
Color crl1 = (Color.red);
final Border compound1;
compound1 = BorderFactory.createCompoundBorder(empty, new OldRoundedBorderLine(crl1));
Color crl2 = (Color.black);
final Border compound2;
compound2 = BorderFactory.createCompoundBorder(empty, new OldRoundedBorderLine(crl2));
tip1Null.setFont(new Font("Serif", Font.BOLD, 14));
tip1Null.setForeground(Color.darkGray);
tip1Null.setPreferredSize(new Dimension(50, 30));
tip1Null.addActionListener(new java.awt.event.ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
}
});
tip1Null.setBorderPainted(true);
tip1Null.setFocusPainted(false);
tip1Null.setBorder(compound);
tip1Null.setHorizontalTextPosition(SwingConstants.CENTER);
tip1Null.setVerticalTextPosition(SwingConstants.BOTTOM);
tip1Null.setUI(new ModifButtonUI());
tip1Null.getModel().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
ButtonModel model = (ButtonModel) e.getSource();
if (model.isRollover()) {
tip1Null.setBorder(compound1);
} else {
tip1Null.setBorder(compound);
}
if (model.isPressed()) {
tip1Null.setBorder(compound2);
}
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(tip1Null, BorderLayout.CENTER);
frame.setLocation(150, 150);
frame.setPreferredSize(new Dimension(310, 75));
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
TextAreaInButton taib = new TextAreaInButton();
}
});
}
}
class OldRoundedBorderLine extends AbstractBorder {
private final static int MARGIN = 5;
private static final long serialVersionUID = 1L;
private Color color;
OldRoundedBorderLine(Color clr) {
color = clr;
}
public void setColor(Color clr) {
color = clr;
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
((Graphics2D) g).setRenderingHint(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(color);
g.drawRoundRect(x, y, width, height, MARGIN, MARGIN);
}
#Override
public Insets getBorderInsets(Component c) {
return new Insets(MARGIN, MARGIN, MARGIN, MARGIN);
}
#Override
public Insets getBorderInsets(Component c, Insets insets) {
insets.left = MARGIN;
insets.top = MARGIN;
insets.right = MARGIN;
insets.bottom = MARGIN;
return insets;
}
}
class ModifButtonUI extends MetalButtonUI {
private static final ModifButtonUI buttonUI = new ModifButtonUI();
ModifButtonUI() {
}
public static ComponentUI createUI(JComponent c) {
return new ModifButtonUI();
}
#Override
public void paint(Graphics g, JComponent c) {
final Color color1 = new Color(230, 255, 255, 0);
final Color color2 = new Color(255, 230, 255, 64);
final Color alphaColor = new Color(200, 200, 230, 64);
final Color color3 = new Color(
alphaColor.getRed(), alphaColor.getGreen(), alphaColor.getBlue(), 0);
final Color color4 = new Color(
alphaColor.getRed(), alphaColor.getGreen(), alphaColor.getBlue(), 64);
super.paint(g, c);
Graphics2D g2D = (Graphics2D) g;
GradientPaint gradient1 = new GradientPaint(
0.0F, (float) c.getHeight() / (float) 2, color1, 0.0F, 0.0F, color2);
Rectangle rec1 = new Rectangle(0, 0, c.getWidth(), c.getHeight() / 2);
g2D.setPaint(gradient1);
g2D.fill(rec1);
GradientPaint gradient2 = new GradientPaint(
0.0F, (float) c.getHeight() / (float) 2, color3, 0.0F, c.getHeight(), color4);
Rectangle rec2 = new Rectangle(0, c.getHeight() / 2, c.getWidth(), c.getHeight());
g2D.setPaint(gradient2);
g2D.fill(rec2);
}
#Override
public void paintButtonPressed(Graphics g, AbstractButton b) {
paintText(g, b, b.getBounds(), b.getText());
g.setColor(Color.red.brighter());
g.fillRect(0, 0, b.getSize().width, b.getSize().height);
}
public void paintBorder(Graphics g) {
}
#Override
protected void paintFocus(Graphics g, AbstractButton b,
Rectangle viewRect, Rectangle textRect, Rectangle iconRect) {
}
}

You will have to extend JButton class not AbstractButton. Try the following things and you will get idea.
The first move is to subclass JButton.
Then, in your subclass, start by redefining the paintComponent(Graphics) method. If you want any changes.
Then, override paintBorder(Graphics) to give it a shape of hexagon.

I know this question has been answered, but you might want to look at using the built-in methods, and using images to draw your button in different states.
Here is a bit of code I used to generate a custom button.
BufferedImage startButton = ImageIO.read(getClass().getResource("/icons/standard/buttons/start_backup.png"));
BufferedImage startButtonHover = ImageIO.read(getClass().getResource("/icons/standard/buttons/start_backup_hover.png"));
BufferedImage startButtonActive = ImageIO.read(getClass().getResource("/icons/standard/buttons/start_backup_active.png"));
JButton startBackupButton = new JButton(new ImageIcon(startButton));
startBackupButton.setRolloverIcon(new ImageIcon(startButtonHover));
startBackupButton.setPressedIcon(new ImageIcon(startButtonActive));
startBackupButton.setBorder(BorderFactory.createEmptyBorder());
startBackupButton.setContentAreaFilled(false);
startBackupButton.setFocusable(false);
You can then add an action listener to it as normal.

try a Jlabel and use an image for any shape!!
JLabel lbl = new JLabel("");
lbl.setIcon(new ImageIcon("shape.png"));
lbl.setBounds(548, 11, 66, 20);
contentPane.add(lbl);
lbl.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
System.exit(0);
}
});

Related

Weird issue updating a JLabel on JSlider change

Huy guys, I have a weird problem.
I'm kinda new to swing and java applications.
I'm trying to make a custom UI jslider that changes a jlabel text when you move the thumb.
My problem is: when I use the addChangeListener(), it creates a weird glitch when moving the thumb.
If I don't use it, it works perfectly fine.
How can I update the JLabel without using the change listener or how can I fix this graphic bug?
Most of this code comes from stackoverflow since I don't know much about painting components.
See pictures at the button to better understand the problem
Thanks!
The code in my jpanel
JSlider slider = new JSlider(SwingConstants.HORIZONTAL, 1, 10, 1) {
#Override
public void updateUI() {
setUI(new CustomSliderUI(this));
}
};
// If I comment this line the visual glitch is gone when moving the thumb, but the value doesnt update
slider.addChangeListener((event) -> RAM_LABEL.setText(slider.getValue() + " Gb"));
slider.setMinorTickSpacing(1);
slider.setMajorTickSpacing(10);
slider.setSnapToTicks(true);
slider.setBounds(96, 317, 300, 35);
slider.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
slider.setOpaque(false);
this.add(slider);
The custom slider ui class
private static class CustomSliderUI extends BasicSliderUI
{
private static final int TRACK_HEIGHT = 8;
private static final int TRACK_ARC = 5;
private static final Dimension THUMB_SIZE = new Dimension(22, 20);
private final RoundRectangle2D.Float trackShape = new RoundRectangle2D.Float();
private final Image knob;
public CustomSliderUI(final JSlider b)
{
super(b);
knob = Swinger.getResource("knob.png");
}
#Override
protected void calculateTrackRect() {
super.calculateTrackRect();
trackRect.y = trackRect.y + (trackRect.height - TRACK_HEIGHT) / 2;
trackRect.height = TRACK_HEIGHT;
trackShape.setRoundRect(trackRect.x, trackRect.y, trackRect.width, trackRect.height, TRACK_ARC, TRACK_ARC);
}
#Override
protected void calculateThumbLocation() {
super.calculateThumbLocation();
thumbRect.y = trackRect.y + (trackRect.height - thumbRect.height) / 2;
}
#Override
protected Dimension getThumbSize() {
return THUMB_SIZE;
}
#Override
public void paint(final Graphics g, final JComponent c) {
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
super.paint(g, c);
}
#Override
public void paintTrack(final Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Shape clip = g2.getClip();
boolean inverted = slider.getInverted();
// Paint shadow.
g2.setColor(new Color(170, 170 ,170));
g2.fill(trackShape);
// Paint track background.
g2.setColor(new Color(200, 200 ,200));
g2.setClip(trackShape);
trackShape.y += 1;
g2.fill(trackShape);
trackShape.y = trackRect.y;
g2.setClip(clip);
// Paint selected track.
boolean ltr = slider.getComponentOrientation().isLeftToRight();
if (ltr) inverted = !inverted;
int thumbPos = thumbRect.x + thumbRect.width / 2;
if (inverted) {
g2.clipRect(0, 0, thumbPos, slider.getHeight());
} else {
g2.clipRect(thumbPos, 0, slider.getWidth() - thumbPos, slider.getHeight());
}
g2.setColor(Swinger.getTransparentWhite(0));
g2.fill(trackShape);
g2.setClip(clip);
}
#Override
public void paintThumb(final Graphics g)
{
g.drawImage(knob, thumbRect.x, thumbRect.y, null);
}
#Override
public void paintFocus(final Graphics g) {}
}
Visual glitch when you are moving the cursor, as soon as you stop pressing the mouse it goes back to normal
Regular cursor / when I move it without the change listener
Solved. I went with drawing my own background it was simplier.
private static class CustomSliderUI extends BasicSliderUI
{
private static final Dimension THUMB_SIZE = new Dimension(22, 20);
private final Image thumb, background;
private final JSlider slider;
public CustomSliderUI(final JSlider b)
{
super(b);
slider = b;
thumb = Swinger.getResource("thumb.png");
background = Swinger.getResource("slider.png");
}
#Override
protected Dimension getThumbSize() {
return THUMB_SIZE;
}
#Override
public void paintTrack(final Graphics g) {
g.drawImage(background, 10, 11, 280, 10, null);
}
#Override
public void paintThumb(final Graphics g)
{
g.drawImage(thumb, thumbRect.x, thumbRect.y, null);
slider.repaint();
}
#Override
public void paintFocus(final Graphics g) {}
}
JSlider slider = new JSlider(SwingConstants.HORIZONTAL, 1, 10, 1) {
#Override
public void updateUI() {
setUI(new CustomSliderUI(this));
}
};
slider.addChangeListener((event) -> RAM_LABEL.setText(slider.getValue() + " Gb"));
slider.setBounds(96, 317, 300, 35);
slider.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
slider.setOpaque(false);
this.add(slider);

Flappy bird Pipes how to randomize in java the program I am using for school is JGrasp

In the paint component.graphics g I was creating pipes for my flappy bird game but I don't know how to approach making multiple pipes that are randomized. I've made the first one randomize but I don't know how to make more and have those new ones be randomized. Does anyone know any ways I can do this?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
public class FlappyPanel extends JPanel
{
private static final int FRAME = 1000;
private static final Color BACKGROUND = new Color(135, 206, 235);
private static final Color GREEN = new Color(0, 255, 0);
private BufferedImage myImage;
private Graphics myBuffer;
private Polkadot pd;
private Timer t;
int top = (int)(Math.random()*1000/2);
int bot = (int)(Math.random()*1000/2);
int x = 1000;
int w = 20;
int speed = 1;
public FlappyPanel()
{
myImage = new BufferedImage(400, 400, 1);
myBuffer = this.myImage.getGraphics();
pd = new Polkadot(200, 200, 25, Color.black);
pd.jump(400, 400);
pd.setX(75);
pd.setY(200);
setFocusable(true);
t = new Timer(10, new Listener());
t.start();
addKeyListener(new Key());
setFocusable(true);
}
public void paintComponent(Graphics g)
{
g.drawImage(myImage, 0, 0, getWidth(), getHeight(), null);
g.setColor(GREEN);
g.drawRect(x, 0, w, top);
g.drawRect(x, 1000-bot, w, bot);
g.fillRect(x, 0, w, top);
g.fillRect(x, 1000-bot, w, bot);
}
private class Listener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
x -= speed;
myBuffer.setColor(BACKGROUND);
myBuffer.fillRect(0, 0, FRAME, FRAME);
if(pd.getY()+1 <= 400)
{
pd.setY(pd.getY()+1);
}
pd.draw(myBuffer);
repaint();
}
}
private class Key extends KeyAdapter
{
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_UP)//bumper2 goes up 30 pixels when UP arrow key is pressed
{
if(pd.getY()-1 >= 0){
pd.setY(pd.getY()-50);//stops pd from getting out of frame
}
}
}
}
}

Getting input from a JOptionPane which is in a JDialog

For purposes that involve fancy looking components, I wrote a function that creates and shows a JOptionPane in a JDialog. Now, I need to get input from that JDialog but I can't. Is there a way that will let me get input from that JDialog without extending either JDialog or JOptionPane? (I also can't use UIManager to alter the appearance of JDialog that's why I'm having the problem in the first place)
public static final Color WHITE = Color.WHITE;
public static final Color RED = Color.RED;
public static final Color LIGHTER_RED = new Color(255, 0, 0, 100);
public static final Color LIGHT_RED = new Color(255, 0, 0, 160);
public static final Color DARK_BLUE = new Color(22, 44, 66);
public static final Font GEORGIA_BOLD_12 = new Font("Georgia", Font.BOLD, 12);
public static final BasicStroke STROKE_0 = new BasicStroke(0);
private static void recursivePaint(Container ct) {
for (Component c : ct.getComponents()) {
if (c instanceof Container) {
c.setBackground(DARK_BLUE);
c.setForeground(WHITE);
recursivePaint((Container) c);
}
}
}
public static int showInputDialog(final Container parent) {
int portNumber = 0;
final JLabel label = new JLabel("Enter an Open Port: ", SwingConstants.LEFT);
label.setOpaque(true);
label.setBackground(DARK_BLUE);
label.setForeground(WHITE);
final JButton button = new JButton("OK") {
private static final long serialVersionUID = -4808194362293478299L;
#Override
public int getWidth() {
return 51;
}
#Override
public int getHeight() {
return 26;
}
#Override
public void paintComponent(final Graphics g) {
final Graphics2D g2d = (Graphics2D) g;
g2d.clearRect(0, 0, getWidth(), getHeight());
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setStroke(STROKE_0);
g2d.setColor(LIGHTER_RED);
if (this.getModel().isRollover()) {
g2d.setColor(LIGHT_RED);
}
if (this.getModel().isPressed()) {
g2d.setColor(RED);
}
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.setColor(RED);
g2d.drawRect(0, 0, getWidth(), getHeight());
g2d.setColor(WHITE);
g2d.setFont(GEORGIA_BOLD_12);
g2d.drawString("CONFIRM", 10, 18);
}
};
button.addActionListener(e -> {
//GET THE INPUT OF JOPTIONPANE TEXTFIELD
//portNumber = getTextOfJOptionPane();
SwingUtilities.getWindowAncestor((Component) e.getSource()).setVisible(false);
SwingUtilities.getWindowAncestor((Component) e.getSource()).dispose();
});
final JOptionPane optionPane = new JOptionPane(label, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_OPTION, null, new JButton[] {button}, button);
optionPane.setWantsInput(true);
optionPane.setOpaque(true);
optionPane.setBackground(DARK_BLUE);
optionPane.getInputValue();
recursivePaint(optionPane);
final JDialog d = optionPane.createDialog(parent, "Open port required!");
d.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
d.setContentPane(optionPane);
d.pack();
d.setLocationRelativeTo(parent);
d.setVisible(true);
return portNumber;
}
Thanks in advance.
JOptionPane on Windows
Since JOptionPane doesn't expose ALL the functionality you would need to replicate this, you're going to have to take more control.
The "appropriate" path would be to supply your own custom look and feel delegate, but that seems like a lot of extra work just so you can control the JTextField.
Instead, you could pass both the JLabel and JTextField to the OptionPane via the message parameter, contained in a single JPanel, for example...
public static final Color WHITE = Color.WHITE;
public static final Color RED = Color.RED;
public static final Color LIGHTER_RED = new Color(255, 0, 0, 100);
public static final Color LIGHT_RED = new Color(255, 0, 0, 160);
public static final Color DARK_BLUE = new Color(22, 44, 66);
public static final Font GEORGIA_BOLD_12 = new Font("Georgia", Font.BOLD, 12);
public static final BasicStroke STROKE_0 = new BasicStroke(0);
public static int showInputDialog(final Container parent) {
int portNumber = 0;
final JLabel label = new JLabel("Enter an Open Port: ", SwingConstants.LEFT);
label.setForeground(WHITE);
JPanel panel = new JPanel(new GridLayout(2, 1));
panel.setOpaque(true);
panel.setBackground(DARK_BLUE);
JTextField inputField = new JTextField(10);
panel.add(label);
panel.add(inputField);
final JButton button = new JButton("OK") {
private static final long serialVersionUID = -4808194362293478299L;
#Override
public int getWidth() {
return 51;
}
#Override
public int getHeight() {
return 26;
}
#Override
public void paintComponent(final Graphics g) {
final Graphics2D g2d = (Graphics2D) g;
g2d.clearRect(0, 0, getWidth(), getHeight());
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setStroke(STROKE_0);
g2d.setColor(LIGHTER_RED);
if (this.getModel().isRollover()) {
g2d.setColor(LIGHT_RED);
}
if (this.getModel().isPressed()) {
g2d.setColor(RED);
}
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.setColor(RED);
g2d.drawRect(0, 0, getWidth(), getHeight());
g2d.setColor(WHITE);
g2d.setFont(GEORGIA_BOLD_12);
g2d.drawString("CONFIRM", 10, 18);
}
};
final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_OPTION, null, new JButton[]{button}, button);
button.addActionListener(e -> {
//GET THE INPUT OF JOPTIONPANE TEXTFIELD
optionPane.setInputValue(inputField.getText());
optionPane.setValue(JOptionPane.OK_OPTION);
});
optionPane.setOpaque(true);
optionPane.setBackground(DARK_BLUE);
final JDialog d = optionPane.createDialog(parent, "Open port required!");
d.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
d.setContentPane(optionPane);
d.pack();
d.setLocationRelativeTo(parent);
d.setVisible(true);
System.out.println(optionPane.getValue());
System.out.println(optionPane.getInputValue());
return portNumber;
}
So. In addition, I've made some additional changes. In the ActionListener, I've set the "value" of the operation to OK_OPTION and called setInputValue. It's important that you call setValue, otherwise the inputValue is not applied, because it thinks you've "cancelled" the dialog.
I don't what you're dialog looks like on your system, but this is what it looks like on mine....
This is why it's ill-advised to override things like getHeight and getWidth

AWT paints only last-added Canvas

I've a VERY simple AWT Painting. Just playing aound to make something bigger. But can't get it working ...
What happens is that only elypse2 is shown - regardless of repaint()ing it or not.
I also tried to use Swing components instead of AWT (JFrame, JComponent) but this also changes nothing.
Is using a Layout Manager necessary? But I want to draw only graphical components, like arcs, rectangles, line, poly-lines, aso ...
Here's the main():
public static void main(String[] args) {
Frame testFrame = new Frame("Grafx-Test");
testFrame.setSize(300, 200);
testFrame.setAlwaysOnTop(true);
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
testFrame.setVisible(true);
}
});
Elypse elypse = new Elypse(new Point(70, 80), 30, 30, Color.BLUE, false);
testFrame.add(elypse);
Elypse elypse2 = new Elypse(new Point(70, 50), 50, 30, Color.BLUE, true);
testFrame.add(elypse2);
}
and here the used class:
public class Elypse extends Canvas {
private Point start;
private int width;
private int height;
private Color c;
private boolean filled;
public Elypse(Point start, int width, int height, Color c, boolean filled) {
this.start = start;
this.width = width;
this.height = height;
this.c = c;
this.filled = filled;
}
#Override
public void paint(Graphics g) {
g.setColor(c);
if (filled) {
g.fillOval(start.x, start.y, width, height);
}
else {
g.drawOval(start.x, start.y, width, height);
}
}
}
You neglect to pack() the enclosing Window. Note the characteristic symptom in your original code: resizing the frame, which generates an update, causes elypse2 to appear.
Addendum: You can see both Elypse instances by using a layout such as GridLayout.
testFrame.setLayout(new GridLayout(0, 1));
As tested:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
public class Test {
public static void main(String[] args) {
Frame testFrame = new Frame("Grafx-Test");
testFrame.setAlwaysOnTop(true);
Elypse elypse = new Elypse(new Point(70, 80), 30, 30, Color.BLUE, false);
testFrame.add(elypse);
Elypse elypse2 = new Elypse(new Point(70, 50), 50, 30, Color.BLUE, true);
testFrame.add(elypse2);
testFrame.pack();
testFrame.setVisible(true);
}
private static class Elypse extends Canvas {
private Point start;
private int width;
private int height;
private Color c;
private boolean filled;
public Elypse(Point start, int width, int height, Color c, boolean filled) {
this.start = start;
this.width = width;
this.height = height;
this.c = c;
this.filled = filled;
}
#Override
public void paint(Graphics g) {
g.setColor(c);
if (filled) {
g.fillOval(start.x, start.y, width, height);
} else {
g.drawOval(start.x, start.y, width, height);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
}
}

How to "paint" on JLabels on a JPanel?

I have a set of JLabels, each containing a letter (via seText()), opaque and background set to white, on a JPanel with a GridLayout so the labels are forming a table.
I am doing a simple animation of highlighting certain rows and columns then there intersection. I can use the setBackground() of labels for this purpose, but thought I'd have more "choices" if a was able to use a Graphics object (maybe drawing a circle around intersection, then clearing it).
I tried to extend JLabel, or drawing on the JPanel directly(using getGraphics() in a method) but it didn't work, I think the drawing is behind the labels in this case. I can't figure out where should the "painting" code be placed in either case, nothing appeared on the screen.
in short, a method like the following, can be used to draw on top of labels?
should it be a JLabel or a JPanel method?
public void drawsomething() {
Graphics2D g2d = (Graphics2D) getGraphics();
g2d.fillRect(100, 100, 100, 100);
}
What if you override paintChildren() ?
protected void paintChildren(Graphics g) {
super.paintChildren(g);
//paint your lines here
}
You might want to try a JLayeredPane to paint your specific drawings on top of the existing JComponents
see example here http://docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html
I really don't know much about drawing stuff yet, but just created one small sample code for you to look at, hopefully you can get some information out of it. In order to paint on the JLabel you can use it's paintComponent(Graphics g) method.
A Sample Code :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DrawingOnJLabel extends JFrame
{
private CustomLabel label;
private int flag = 1;
private JPanel contentPane;
public DrawingOnJLabel()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
contentPane = new JPanel();
contentPane.setBackground(Color.WHITE);
label = new CustomLabel(200, 200);
label.setLabelText("A");
label.setValues(50, 50, 100, 100, 240, 60);
final JButton button = new JButton("CLEAR");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
if (flag == 1)
{
label.setFlag(flag);
flag = 0;
button.setText("REPAINT");
contentPane.revalidate();
contentPane.repaint();
}
else if (flag == 0)
{
label.setFlag(flag);
flag = 1;
button.setText("CLEAR");
contentPane.revalidate();
contentPane.repaint();
}
}
});
}
});
contentPane.add(label);
add(contentPane, BorderLayout.CENTER);
add(button, BorderLayout.PAGE_END);
setSize(300, 300);
setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new DrawingOnJLabel();
}
});
}
}
class CustomLabel extends JLabel
{
private int sizeX;
private int sizeY;
private int x, y, width, height, startAngle, arcAngle;
private int flag = 0;
private String text;
public CustomLabel(int sX, int sY)
{
sizeX = sX;
sizeY = sY;
}
// Simply call this or any set method to paint on JLabel.
public void setValues(int x, int y, int width, int height, int startAngle, int arcAngle)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.startAngle = startAngle;
this.arcAngle = arcAngle;
repaint();
}
public void setFlag(int value)
{
flag = value;
repaint();
}
public Dimension getPreferredSize()
{
return (new Dimension(sizeX, sizeY));
}
public void setLabelText(String text)
{
super.setText(text);
this.text = text;
flag = 0;
repaint();
}
public void paintComponent(Graphics g)
{
if (flag == 0)
{
g.setColor(Color.RED);
g.drawString(text, 20, 20);
g.setColor(Color.BLUE);
g.drawOval(x, y, width, height);
g.fillOval(x + 20, y + 20, 15, 15);
g.fillOval(x + 65, y + 20, 15, 15);
g.fillRect(x + 40, y + 40, 5, 20);
g.drawArc(x + 20, y + 30, 55, 55, startAngle, arcAngle);
}
else if (flag == 1)
{
g.clearRect(x, y, width, height);
}
}
}
Use paintComponent(Graphics g) instead of paint(Graphics g). That will paint over the GUI

Categories