4

I'm building a Poker Odds Calc app in Java. I want to select a new card by clicking the card's placeholder which is basically an extended JPanel that I "draw" the card's face and has a mouseListener.

What I have imagined to do is that when I clicked the card, I would like a round menu to pop up around the mouse cursor having a circle in the middle cut in four with each suite in a quarter and a ring around it cut in thirteen for the value of the card. Then I will select suit and value and it would disappear. Do you know any way I could do this? I researched a bit and I think it can be done with JavaFX by making a transparent JDialog but I'm not sure.

Is there a way to draw a totally custom shaped JComponent like a JButton shaped for each quarter of the circle etc.? I have some experience in Java but not GUI building.

Thanks in advance for your time.

edit: Used your comment and have answered my question about the circular dialog (don't know if it's the best way to do it but works for now). Now, is there anyway I know in which area the click belongs (if the click was on a useful area) without hardcoding the coordinates?

Dimitrios K.
  • 1,008
  • 13
  • 36
  • @ "JPanel with an overridden paint method" by `paint` did you mean `paintComponent`? The last one is the one to use for custom painting in a `JPanel`. – Andrew Thompson May 13 '11 at 12:57
  • FAIL :P I had overidden the draw() at first but now I am not even doing that... Meh I'm confused :P Corrected that... – Dimitrios K. May 13 '11 at 13:54

2 Answers2

4

I would suggest doing custom graphics rather than trying to customize JButton and so on. When you click on the JPanel you can draw the circle and so on using the java.awt.Shape interfaces and its various implementations such as java.awt.geom.Ellipse2D.

These shapes come with contains() method that can tell you if a point is in the Shape or not. This way, when the user next clicks on the JPanel, you can determine which shape the user clicked on by going through all the shapes and checking.

Vincent Ramdhanie
  • 102,349
  • 23
  • 137
  • 192
  • 2
    Why JPanel and not simply JComponent? – Jens Schauder May 13 '11 at 12:25
  • I'll try doing that... I'm not very good at graphics but I'll see what I can do. I'll give some feedback. – Dimitrios K. May 13 '11 at 13:59
  • @Jens Schauder You are right or course, but the OP was talking about drawing on a JPAnel and I thought, one thing at a time. – Vincent Ramdhanie May 13 '11 at 14:50
  • I'm a bit stuck and I would like some more help if possible. I have a class named CardChooser and I want to paint any custom shape on my JFrame. So when I click a JPanel on my JFrame which represents a playing card, I take the coordinates of the mouse click and call the static method CardChooser.getCard(point);. Now how on earth should I paint what I want? Should my class extend JPanel or JDialog to override their paint() method? Should I pass the graphics of JFrame to my class? any ideas plz.. :) – Dimitrios K. May 16 '11 at 14:39
0

The code to create the graphics is this in case anyone needs it:

import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D.Double;
import javax.swing.JDialog;

/**
 *
 * @author Dimitris Klimis <dnklimis at gmail.com>
 */
public class CardChooser extends JDialog implements MouseListener {

    int sizeX = 140;
    int sizeY = sizeX; //in case I don't want it to be circle
    int x, y;
    Point point;

    public CardChooser(Point point) {
        x = point.x;
        y = point.y;
        this.point = point;
        this.initComponents();
    }

    public static int[] getCard(Point point) {
        int[] output = {0, 0};
        CardChooser chooser = new CardChooser(point);
        return output;
    }

    @Override
    public void paint(Graphics g) {
        if (g instanceof Graphics2D) {
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            //Drawing the transparent dialog
            g2.setPaint(new Color(0.0f, 0.0f, 0.0f, 0.0f));
            g2.fillRect(0, 0, getWidth(), getHeight());

            //Drawing the circles
            g2.setColor(Color.BLACK);
            drawCircle(g2, 100, new GradientPaint(0.0f, 0.0f, Color.darkGray, (float) getWidth(), (float) getHeight(), Color.lightGray, false));
            drawLines(g2, 13, 100);
            int smallCircle = 38;
            drawCircle(g2, smallCircle + 3, Color.GRAY);
            drawCircle(g2, smallCircle, new GradientPaint((float) (getWidth() * 0.25), (float) (getHeight() * 0.25), Color.lightGray, (float) (getWidth() * 0.75), (float) (getHeight() * 0.75), Color.darkGray, false));
            drawLines(g2, 4, smallCircle);
            drawCircle(g2, 10, Color.LIGHT_GRAY);
            drawSuiteLetters(g2);
            drawCardValues(g2);
            drawClosingX(g2);
        } else {
            super.paint(g);
        }
    }

    private void drawCircle(Graphics2D g2, int percentage, Paint fill) {
        double perc = (double) percentage / 100.0;
        Ellipse2D ellipse = new Ellipse2D.Double(((1 - perc) / 2) * sizeX, ((1 - perc) / 2) * sizeY, perc * sizeX, perc * sizeY);
        g2.setPaint(fill);
        g2.fill(ellipse);
        g2.setColor(Color.BLACK);
        g2.draw(ellipse);
    }

    private void drawLines(Graphics2D g2, int outOf, int percentage) {
        double rads = Math.toRadians(360.0 / outOf);
        double perc = (double) percentage / 100.0;
        Double zeroAxis = new Point.Double(sizeX / 2.0, sizeY / 2.0);
        for (int i = 0; i < outOf; i++) {
            g2.draw(new Line2D.Double(zeroAxis.x, zeroAxis.y, zeroAxis.x + (zeroAxis.x * perc * Math.sin(rads * i)), zeroAxis.y + (zeroAxis.y * perc * Math.cos(rads * i))));
        }
    }

    private void drawSuiteLetters(Graphics2D g2) {
        Double zeroAxis = new Point.Double(sizeX / 2.0, sizeY / 2.0);
        g2.setFont(new Font("Courier New", Font.BOLD, 25));
        g2.drawString("\u2660", (float) zeroAxis.x - 18, (float) zeroAxis.y - 5);//spades
        g2.drawString("\u2663", (float) zeroAxis.x + 3, (float) zeroAxis.y + 20);//clubs
        g2.setColor(Color.RED);
        g2.drawString("\u2665", (float) zeroAxis.x + 3, (float) zeroAxis.y - 3);//hearts
        g2.drawString("\u2666", (float) zeroAxis.x - 18, (float) zeroAxis.y + 19);//diamonds
        g2.setColor(Color.BLACK);
    }

    private void drawCardValues(Graphics2D g2) {
        Double zeroAxis = new Point.Double((sizeX / 2.0) - 8, 21);
        float xx = (float) zeroAxis.x;
        float yy = (float) zeroAxis.y;
        g2.setFont(new Font("Arial", Font.BOLD, 24));
        String[] letters = {"A", "K", "Q", "J", "T", "9", "8", "7", "6", "5", "4", "3", "2"};
        float[] xPosition = {0, 25, 46, 63, 58, 42, 15, -10, -37, -53, -58, -46, -25};
        float[] yPosition = {0, 7, 23, 50, 80, 102, 115, 115, 102, 80, 50, 23, 7};
        for (int i = 0; i < 13; i++) {
            g2.drawString(letters[i], xx + xPosition[i], yy + yPosition[i]);
        }
    }

    private void drawClosingX(Graphics2D g2) {
        Double zeroAxis = new Point.Double(sizeX / 2.0, sizeY / 2.0);
        g2.draw(new Line2D.Double(zeroAxis.x - 5, zeroAxis.y - 5, zeroAxis.x + 5, zeroAxis.y + 5));
        g2.draw(new Line2D.Double(zeroAxis.x - 5, zeroAxis.y + 5, zeroAxis.x + 5, zeroAxis.y - 5));
    }

    private void initComponents() {
        this.addMouseListener(this);
        this.setBounds(x - (sizeX / 2), y - (sizeY / 2), sizeX + 1, sizeX + 1);
        this.setUndecorated(true);
        this.setModal(true);
        this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);

        this.setVisible(true);
    }

    public void mouseClicked(MouseEvent e) {
        this.dispose();
    }

    public void mousePressed(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }
}

PS. I extended JDialog cause I couldn't get JPanel to show up...

Dimitrios K.
  • 1,008
  • 13
  • 36
  • Don't post another question as an answer to your own question. Edit existing question with any new information or post a comment. – Chris Dennett May 18 '11 at 23:35
  • `PS. I extended JDialog cause I couldn't get JPanel to show up...` -- not good as you lose all benefits of Swing graphics, you risk unwanted side effects, and you shouldn't draw directly on top-level windows. Instead do your drawing in a JPanel or JComponent as has already been suggested, and then try to figure out why the JPanel isn't showing up. – Hovercraft Full Of Eels May 22 '11 at 17:43