Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / GUI / July 2007

Tip: Looking for answers? Try searching our database.

Clipped image when g.drawImage(img, -3, -4, this)

Thread view: 
A. Farber - 19 Jul 2007 00:18 GMT
Hello,

I've created a class (full source code at the bottom)
which extends java.awt.Component and is supposed to
represent a playing card. If the card is being dragged,
I'd like to draw a shadow underneath it. And the card
itself should be drawn a little bit displaced - to make
the impression that it has been lifted:

    public void paint(Graphics g) {
        if (this == dragged) {
            g.drawImage(shadow, 0, 0, this);
            g.drawImage(cardImg, -3, -4, this);
        } else {
            g.drawImage(cardImg, 0, 0, this);
        }
    }

My problem is however that the cardImg is being
clipped. Does anybody please have an idea how
to workaround this?

Thank you
Alex

PS: Here is the full source code:

// $Id: Card.java,v 1.2 2007/07/18 10:10:33 afarber Exp $

import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;

class Card extends Component implements MouseListener,
MouseMotionListener
{
    public static final int        WIDTH = 70;
    public static final int        HEIGHT = 100;

    public static final int        SPADE   = 0;
    public static final int        CLUB    = 1;
    public static final int        DIAMOND = 2;
    public static final int        HEART   = 3;
    public static final int        NOTRUMP = 4;

    private static Card        dragged;

    private static Image[][]    faces;
    private static Image        back;
    private static Image        shadow;

    public byte            rank, suit;
    public boolean            opened;
    public int            whose;

    public Card(int rank, int suit) {
        setSize(WIDTH, HEIGHT);
        addMouseListener(this);
        addMouseMotionListener(this);

        this.rank = (byte) rank;
        this.suit = (byte) suit;
    }

    public Card(char ch) {
        setSize(WIDTH, HEIGHT);
        addMouseListener(this);
        addMouseMotionListener(this);

        rank = (byte) (ch >> 8);
        suit = (byte) ch;
    }

    public boolean equals(Card card) {
        return (rank == card.rank && suit == card.suit);
    }

    public char toChar() {
        return (char) ((rank << 8) | suit);
    }

    public void paint(Graphics g) {
        if (this == dragged) {
            g.drawImage(shadow, 0, 0, this);

                       // XXX the image below is clipped :-(
            g.drawImage(opened ? faces[rank][suit] : back,
               -3, -4, this);
        } else {
            g.drawImage(opened ? faces[rank][suit] : back,
               0, 0, this);
        }
    }

    public static void prepImages(Image big) {
        ImageProducer source = big.getSource();

        // create 32 card images
        faces = new Image[8][4];
        for (int rank = 0; rank < 8; rank++)
            for (int suit = SPADE; suit <= HEART; suit++) {
                ImageFilter filter =
                   new CropImageFilter(rank * WIDTH,
                   suit * HEIGHT, WIDTH, HEIGHT);
                ImageProducer producer = new
                   FilteredImageSource(source, filter);
                faces[rank][suit] = Toolkit.getDefaultToolkit()
                   .createImage(producer);
            }
        // create the image of a card's back
        ImageFilter filter =
           new CropImageFilter(560, 0, WIDTH, HEIGHT);
        ImageProducer producer =
           new FilteredImageSource(source, filter);
        back = Toolkit.getDefaultToolkit().createImage(producer);
        // use a card shape to create shadow
        int[] pixels = new int[WIDTH * HEIGHT];
        PixelGrabber grabber = new PixelGrabber(big, 0, 0,
           WIDTH, HEIGHT, pixels, 0, WIDTH);
        try {
            grabber.grabPixels();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        // turn non-transparent pixels to shadow
        for (int i = 0; i < pixels.length; i++)
            if (0 != (pixels[i] & 0xFF000000))
                pixels[i] = 0x60000000;
        shadow = Toolkit.getDefaultToolkit().createImage(
           new MemoryImageSource(WIDTH, HEIGHT, pixels, 0, WIDTH));
    }

    public void mouseExited(MouseEvent event) {
        System.out.println("mouseExited:" + event);
        dragged = null;
        getParent().repaint();
    }

    public void mouseReleased(MouseEvent event) {
        System.out.println("mouseReleased" + event);
        dragged = null;
        getParent().repaint();
    }

    public void mousePressed(MouseEvent event) {
        System.out.println("mousePressed" + event);
        dragged = this;
        getParent().repaint();
    }

    public void mouseEntered(MouseEvent event) {
        System.out.println("mouseEntered" + event);
    }

    public void mouseClicked(MouseEvent event) {
        System.out.println("mouseClicked" + event);
    }

    public void mouseMoved(MouseEvent event) {
        System.out.println("mouseMoved" + event);
    }

    public void mouseDragged(MouseEvent event) {
        System.out.println("mouseDragged" + event);
    }

    public static int randomRank() {
        return (int) Math.floor(8.0 * Math.random());
    }

    public static int randomSuit() {
        return (int) Math.floor(4.0 * Math.random());
    }

    public static void main(String args[]) {
        Frame frame = new Frame("Card Test");
        frame.setForeground(Color.white);
        frame.setBackground(Color.gray);
        frame.setLayout(null);

        final String PATH = "media/cards.gif";
        Image big = Toolkit.getDefaultToolkit().getImage(PATH);
        MediaTracker tracker = new MediaTracker(frame);
        tracker.addImage(big, 0);
        try {
            tracker.waitForAll();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        if (tracker.isErrorAny()) {
            System.err.println("Image " + PATH + " not found");
            return;
        }

        Card.prepImages(big);
        Card card = new Card(randomRank(), randomSuit());
        card.opened = true;
        frame.add(card);
        frame.validate();
        card.setLocation(200, 100);

        frame.setSize(400, 300);
        frame.setVisible(true);
    }
}
Roedy Green - 19 Jul 2007 04:38 GMT
On Wed, 18 Jul 2007 23:18:54 -0000, "A. Farber"
<Alexander.Farber@gmail.com> wrote, quoted or indirectly quoted
someone who said :

>frame.validate();
>        card.setLocation(200, 100);
>
>        frame.setSize(400, 300);
You need to force the size of the card.

Dimension d = new Dimension( width, height );
       this.setPreferredSize( d );
       this.setMinimumSize( d );
       this.setMaximumSize( d );
Signature

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com

A. Farber - 20 Jul 2007 10:02 GMT
On Jul 19, 5:38 am, Roedy Green <see_webs...@mindprod.com.invalid>
wrote:
> >frame.validate();
> >            card.setLocation(200, 100);
[quoted text clipped - 7 lines]
>         this.setMinimumSize( d );
>         this.setMaximumSize( d );

No, I'd like the parent frame to be bigger,
so that I can drag my Card Component around.

Or have I misunderstood you?

Regards
Alex
Ian Shef - 19 Jul 2007 20:16 GMT
> Hello,
>
[quoted text clipped - 20 lines]
> Thank you
> Alex
From the java docs on the update(...) method of Component:

The origin of the graphics context, its (0, 0) coordinate point, is the
top-left corner of this component. The clipping region of the graphics
context is the bounding rectangle of this component.

I believe that this is true for the paint(...) method as well.  Basically,
it says that any pixels with a negative x or y will not be drawn.

You may be able to use setClip(...) to change the clipping rectangle prior
to your attempt to draw the displaced card.

If setClip(...) doesn't work for you, there are other solutions, such as
defining your Card to be slightly larger than needed, and drawing the image
with the appropriate displacement within its bounding rectangle.

Write back and let us know what worked!

Signature

Ian Shef     805/F6      *    These are my personal opinions    
Raytheon Company         *    and not those of my employer.
PO Box 11337             *
Tucson, AZ 85734-1337    *

A. Farber - 20 Jul 2007 09:58 GMT
Hello Ian,

> > If the card is being dragged,
> > I'd like to draw a shadow underneath it. And the card
[quoted text clipped - 12 lines]
> > My problem is however that the cardImg is being
> > clipped.

> any pixels with a negative x or y will not be drawn.
>
[quoted text clipped - 4 lines]
> defining your Card to be slightly larger than needed, and drawing the image
> with the appropriate displacement within its bounding rectangle.

yes, setClip with negative x and y hasn't worked for me.

I've end up making my component a bit bigger:

class Card extends Component
{
       public static final int         WIDTH  = 70;
       public static final int         HEIGHT = 100;

       // shadow offsets
       public static final int         SHDX = 3;
       public static final int         SHDY = 4;

       private static Card             dragged;
.....
       protected Card() {
               // make the card bigger or the shadow will be clipped
               setSize(WIDTH + SHDX, HEIGHT + SHDY);

               enableEvents(AWTEvent.MOUSE_EVENT_MASK |
                   AWTEvent.MOUSE_MOTION_EVENT_MASK);
       }
....
       public void paint(Graphics g) {
               if (this == dragged)
                       g.drawImage(shadow, SHDX, SHDY, this);
               else
                       g.translate(SHDX, SHDY);
               g.drawImage(opened ? faces[rank][suit] : back, 0, 0,
this);
       }

This has the problem that when the card isn't being dragged,
then it is displaced a bit - it is located at SHDX, SHDY instead
of Component's 0, 0.  But I can live with it...

Now I'm struggling with 2 further problems -

1) my Card LW component flickers even though the Deck
   LW Container (represents playing table) to which I add
   it is double-buffered. (Yes I've read few docs about
   flickering LW  Components, but still can't fix it)

2) Defining a custom AWT event turned out to be such
   a pain! I wanted my Card to send an event to listeners
   after it has been dragged and released (i.e. the card
  has been played), but have ended up with this hack:

       protected void processMouseEvent(MouseEvent event) {
               if (event.getID() == MouseEvent.MOUSE_PRESSED) {
                       oldX = getLocation().x;
                       oldY = getLocation().y;

                       relX = event.getX();
                       relY = event.getY();

                       dragged = this;
               } else if (event.getID() == MouseEvent.MOUSE_RELEASED)
{
                       // pass the mouse released event to the
listeners,
                       // but only if this card has been dragged
around
                       if (dragged != null) {
                               super.processMouseEvent(event);

                               dragged = null;
                       }
               }
       }

Regards
Alex

PS: And here is my full source code:

// $Id: Card.java,v 1.5 2007/07/19 15:19:46 afarber Exp $

// Card lightweight component which sends a MouseEvent to the
// listeners when it has been dragged around and released

import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;

class Card extends Component
{
    public static final int        WIDTH  = 70;
    public static final int        HEIGHT = 100;

    // shadow offsets
    public static final int        SHDX = 3;
    public static final int        SHDY = 4;

    public static final int        SPADE   = 0;
    public static final int        CLUB    = 1;
    public static final int        DIAMOND = 2;
    public static final int        HEART   = 3;
    public static final int        NOTRUMP = 4;

    // which cards may be moved
    public static int        allowedOwner;
    public static int        allowedSuit = NOTRUMP;

    private static Card        dragged;
    private static Image[][]    faces;
    private static Image        back;
    private static Image        shadow;
    private int                    oldX, oldY;
    // position of the mouse pointer inside the card, when pressed
    private int                    relX, relY;

    public byte                rank, suit;
    public boolean            opened;
    // 0, 1, 2 = card belongs to a player; 3 = is on the table
    public int                 owner;

    public final static String[] SUIT = {
        " spades",
        " clubs",
        " diamonds",
        " hearts"
    };
    public final static String[] RANK4 = {
        "7",
        "8",
        "9",
        "10",
        "J",
        "Q",
        "K",
        "A"
    };

    protected Card() {
        // make the card bigger or the shadow will be clipped
        setSize(WIDTH + SHDX, HEIGHT + SHDY);

        enableEvents(AWTEvent.MOUSE_EVENT_MASK |
           AWTEvent.MOUSE_MOTION_EVENT_MASK);
    }

    public Card(int rank, int suit) {
        this();

        this.rank = (byte) rank;
        this.suit = (byte) suit;
    }

    public Card(char ch) {
        this();

        rank = (byte) (ch >> 8);
        suit = (byte) ch;
    }

    public boolean equals(Card card) {
        return (rank == card.rank && suit == card.suit);
    }

    public char toChar() {
        return (char) ((rank << 8) | suit);
    }

    public void update(Graphics g) {
    }

    public void paint(Graphics g) {
        if (this == dragged)
            g.drawImage(shadow, SHDX, SHDY, this);
        else
            g.translate(SHDX, SHDY);
        g.drawImage(opened ? faces[rank][suit] : back, 0, 0, this);
    }

    public static void prepImages(Image big) {
        ImageProducer source = big.getSource();

        // create 32 card images
        faces = new Image[8][4];
        for (int rank = 0; rank < 8; rank++)
            for (int suit = SPADE; suit <= HEART; suit++) {
                ImageFilter filter =
                   new CropImageFilter(rank * WIDTH,
                   suit * HEIGHT, WIDTH, HEIGHT);
                ImageProducer producer = new
                   FilteredImageSource(source, filter);
                faces[rank][suit] = Toolkit.getDefaultToolkit()
                   .createImage(producer);
            }
        // create the image of a card's back
        ImageFilter filter =
           new CropImageFilter(560, 0, WIDTH, HEIGHT);
        ImageProducer producer =
           new FilteredImageSource(source, filter);
        back = Toolkit.getDefaultToolkit().createImage(producer);
        // use a card shape to create shadow
        int[] pixels = new int[WIDTH * HEIGHT];
        PixelGrabber grabber = new PixelGrabber(big, 0, 0,
           WIDTH, HEIGHT, pixels, 0, WIDTH);
        try {
            grabber.grabPixels();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        // turn non-transparent pixels to shadow
        for (int i = 0; i < pixels.length; i++)
            if (0 != (pixels[i] & 0xFF000000))
                pixels[i] = 0x60000000;
        shadow = Toolkit.getDefaultToolkit().createImage(
           new MemoryImageSource(WIDTH, HEIGHT, pixels, 0, WIDTH));
    }

    protected void processMouseEvent(MouseEvent event) {
        if (event.getID() == MouseEvent.MOUSE_PRESSED) {
            oldX = getLocation().x;
            oldY = getLocation().y;

            relX = event.getX();
            relY = event.getY();

            dragged = this;
        } else if (event.getID() == MouseEvent.MOUSE_RELEASED) {
            // pass the mouse released event to the listeners,
            // but only if this card has been dragged around
            if (dragged != null) {
                super.processMouseEvent(event);

                dragged = null;
            }
        }
    }

    protected void processMouseMotionEvent(MouseEvent event) {
        if (event.getID() == MouseEvent.MOUSE_DRAGGED) {
            // XXX check allowedOwner + allowedSuit
            // XXX here and display a red glow

            Point loc = getLocation();
            event.translatePoint(loc.x, loc.y);
            setLocation(event.getX() - relX, event.getY() - relY);
        }
    }

    public void putBack() {
        setLocation(oldX, oldY);
    }

    public static int randomRank() {
        return (int) Math.floor(8.0 * Math.random());
    }

    public static int randomSuit() {
        return (int) Math.floor(4.0 * Math.random());
    }

    // FOR TESTING: gmake build/Card.class && java -cp build/ Card
    public static void main(String args[]) {
        Frame frame = new Frame("Card Test");
        frame.setForeground(Color.white);
        frame.setBackground(Color.gray);
        frame.setLayout(null);

        final String PATH = "media/cards.gif";
        Image big = Toolkit.getDefaultToolkit().getImage(PATH);
        MediaTracker tracker = new MediaTracker(frame);
        tracker.addImage(big, 0);
        try {
            tracker.waitForAll();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        if (tracker.isErrorAny()) {
            System.err.println("Image " + PATH + " not found");
            return;
        }

        Card.prepImages(big);
        Card card = new Card(randomRank(), randomSuit());
        card.opened = true;

        card.addMouseListener(new MouseAdapter() {
            public void mouseReleased(MouseEvent event) {
                //System.out.println("mouseReleased" + event);

                Card card = (Card) event.getSource();

                System.out.println("The card (" +
                    RANK4[card.rank] + ", " +
                    SUIT[card.suit] + ") has been played!");

                card.putBack();
            }
        });

        frame.add(card);
        frame.validate();
        card.setLocation(200, 100);

        frame.setSize(400, 300);
        frame.setVisible(true);
    }
}
Ian Shef - 24 Jul 2007 20:57 GMT
<SNIP>
> Now I'm struggling with 2 further problems -
>
> 1) my Card LW component flickers even though the Deck
>     LW Container (represents playing table) to which I add
>     it is double-buffered. (Yes I've read few docs about
>     flickering LW  Components, but still can't fix it)

I don't understand.  As far as I know, there is no double-buffering in AWT
except for the BufferStrategy stuff that was added in version 1.4.  Is this
what you are doing?
On the other hand, Swing has double buffering.  Are you mixing AWT and
Swing?

If it is either of these two cases above, I can't help you.  I haven't
worked with BufferStrategy, and I haven't mixed AWT and Swing.
I have performed double buffering in AWT by handling it myself, forcing
paint(...) and update(...) to perform writing on my own buffer, and then
copying the buffer to the screen myself.  I would have to really dig to
find the code where I did this.

> 2) Defining a custom AWT event turned out to be such
>     a pain! I wanted my Card to send an event to listeners
[quoted text clipped - 23 lines]
>                 }
>         }

I have never defined custom AWT events, so I can't help.  Typically (in
AWT) I have done something along the lines of what you did.

Perhaps it is not too late to switch to Swing?

> Regards
> Alex
[quoted text clipped - 228 lines]
>      }
> }

Signature

Ian Shef     805/F6      *    These are my personal opinions    
Raytheon Company         *    and not those of my employer.
PO Box 11337             *
Tucson, AZ 85734-1337    *



Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.