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 / General / March 2008

Tip: Looking for answers? Try searching our database.

Graphics2D question

Thread view: 
RichT - 13 Mar 2008 21:05 GMT
Hello,

I want to build my application from three main classes.
1. A frame class to handle file operations.
2. A Drawing panel to render images to.
3. An engine to perform the actual rendering.

All the examples I have read so far for Image stuff in Java have
everything stuffed into one monolithic class, and the crux of the
rendering seems to be done in paint(Graphics g) or
paintComponent(Graphics g) using a g2d object cast againg the parameter g.

If I wanted to do calculations for rotations translations etc I can do
this with the AffineTransform class setX methods, but the drawImage
method of g2d seems to be handled in the paint/paintComponent methods.

This is fine until I want to specify x, y arguments in the drawImage
Method as neither Paint or PaintComponent take these parameters in their
method signature how can I do this, is there another way to draw apart
from the paint/paint component methods?

Any help appreciated.
Rich
Peter Duniho - 13 Mar 2008 21:24 GMT
> [...]
> If I wanted to do calculations for rotations translations etc I can do  
[quoted text clipped - 5 lines]
> method signature how can I do this, is there another way to draw apart  
> from the paint/paint component methods?

Can you rephrase the question?  As stated it's a little confusing.

You write "the drawImage method of g2d seems to be handled in...".  I  
assume you're actually talking about Graphics2D.drawImage(), but that's  
not _handled_ in paintComponent().  It might be _used_ there, but it  
wouldn't be handled there.

As far as specifying coordinates when using drawImage(), since you  
shouldn't call paintComponent() yourself, the parameter list for the  
method isn't relevant.  Instead, your component overrides the  
paintComponent() and draws what it needs to when called.  If an image you  
want to draw using drawImage() requires a specific location to be drawn  
(and it's natural that it would), then that location needs to be set prior  
to when paintComponent() is called.

A typical sequence of events would be for the location to be updated by  
some internal calculation in the component, or by some method called by a  
client of the component, and when the location is changed, the component  
would call repaint() to signal that it needs to be repainted.  Then the  
Java run-time will eventually call the paintComponent() method to have the  
actual painting done, at which time the location that was previously set  
would then be used to actually draw the image in question.

If that information doesn't clarify for you how to manage what you're  
trying to do, you should try to be more specific about what problem you're  
having.  A concise-but-complete code sample would be very helpful.  Try to  
show what it is you're trying to do and be clear about why the code  
doesn't work as you want it to.

Pete
RichT - 13 Mar 2008 22:40 GMT
> Can you rephrase the question?  As stated it's a little confusing.

Sorry that is me all over type faster than I think :)

> You write "the drawImage method of g2d seems to be handled in...".  I
> assume you're actually talking about Graphics2D.drawImage(), but that's
> not _handled_ in paintComponent().  It might be _used_ there, but it
> wouldn't be handled there.

Ok to simplify my question ;) I have nothing to show code wise, still
thinking about a/the design.

Yours and Knutes answers have clarified some things for me thanks :) but
I still have a problem getting my head around this.

My thoughts were to have something that extends a JPanel for rendering
images to, but I want the logic for doing this in another non gui class.

If for instance I have an image that I wanted to scale and centre in the
JPanel, I would want to calculate if enlarged images is bigger than the
JPanel and if so crop it to fit.

This would require as far as I know an AffineTransform.setSclale(x, y)
and also as far as I know a bufferedImage.getSubImages(x1,y1,x2,y2)
and would require some code to calculate all of this.

I would prefer to have all the above in my non gui logic class and
somehow have the JPanel class repaint all of this after.

While I could call repaint() in the JPanel, how would it know about the
changes to the image and what if I wanted to specify a different x, y
location for the image if it is smaller than the JPanel and needed to be
centred? how would I get this information to the g2d object in the
PaintComponent method?
Peter Duniho - 13 Mar 2008 23:09 GMT
> [...]
> Yours and Knutes answers have clarified some things for me thanks :) but  
> I still have a problem getting my head around this.

Please keep in mind that apparently you've multi-posted your question.  I  
haven't looked at his answer in the other newsgroup, so I don't know  
what's already been suggested, nor do I know anything you've posted  
there.  (This is a good example of why you shouldn't multi-post, by the  
way).

> My thoughts were to have something that extends a JPanel for rendering  
> images to, but I want the logic for doing this in another non gui class.

Any particular reason for extending JPanel?  Does your custom component  
actually need to act as a simple container for other components?  If not,  
perhaps you should simply be extending JComponent.

> If for instance I have an image that I wanted to scale and centre in the  
> JPanel, I would want to calculate if enlarged images is bigger than the  
> JPanel and if so crop it to fit.

Why would an image be "enlarged"?  How does that happen?  Hint: it's at  
whatever point the image display, including scaling, is configured that  
you'd set the necessary data that will be used later for drawing the image.

> This would require as far as I know an AffineTransform.setSclale(x, y)  
> and also as far as I know a bufferedImage.getSubImages(x1,y1,x2,y2)
> and would require some code to calculate all of this.

I doubt you need to use getSubImage().  Your component's drawing will be  
clipped to the boundary of the image, so all you really need to do is  
transform the Graphics2D correctly (scale and translate, if I understand  
your post correctly) and the image will be placed and draw appropriately.

The transformation will be based on whatever configuration was performed  
prior to the painting (as I mention above).

It's possible that calling getSubImage() might improve performance, by  
avoiding having the graphics subsystem drawing outside the clip area.  But  
since clipping is usually a highly optimized operation, and because most  
of the cost of drawing is in the actual moving of bits that are drawn (the  
area that's clipped won't be processed), I would be surprised if it's a  
necessary optimization, and it may not improve performance much, if at all  
(depending on the exact implementation, the cost of creating the new  
object and then collecting it later could in fact cause reduced  
performance).

> I would prefer to have all the above in my non gui logic class and  
> somehow have the JPanel class repaint all of this after.

I'm not really clear on what the "non gui logic class" is.  Anything that  
needs to know the size of your custom component and involves itself in the  
drawing of the component is, to my perception, a GUI class.  If you have  
in mind a class that doesn't know anything about the GUI, then perhaps you  
could be more explicit about that.  What interface does that class  
implement?  I don't mean what's the name of the interface; I mean, what  
methods, properties, and/or fields are exposed by that interface?  How  
does your custom component use this hypothetical "non gui logic class"?

> While I could call repaint() in the JPanel, how would it know about the  
> changes to the image

Well, typically the custom component would either itself be directly  
informed of changes to the image, or it would refer to some data structure  
that itself knows about the changes.  By the time repaint() is called,  
everything should already be set up to draw the custom component  
correctly.  The paintComponent() method itself would then simply use the  
current state of the data structures involved to draw the correct thing.

> and what if I wanted to specify a different x, y location for the image  
> if it is smaller than the JPanel and needed to be centred?

It seems to me that if you want the image centered in the custom  
component, the you're not "specifying a different x, y location".  
Instead, that location is implied by the size of the image.  You could  
either compute the location in the paintComponent() method, or you could  
pre-compute and cache that information any time the image or component  
size changes (since either would affect the location of the image).

> how would I get this information to the g2d object in the PaintComponent  
> method?

Again, I'm not really sure what you mean here.  The Graphics2D instance  
doesn't have any state that specifically would know about your image.  
However, you can certainly set the transformation for the Graphics2D based  
on whatever scaling and translation is necessary.  In fact, creating this  
transformation could be part of the "pre-compute and cache" operation I  
mentioned earlier.  Then all that the paintComponent() method would have  
to do is call Graphics2D.transform() with the AffineTransform that you'd  
computed earlier.

Alternatively, you could just compute the necessary parameters that would  
be used later to call one of the many drawImage() overloads defined in  
Graphics and Graphics2D and rather than setting the transform, just call  
the appropriate overload directly.

Pete
RichT - 14 Mar 2008 17:49 GMT
> Please keep in mind that apparently you've multi-posted your question.
Yes sorry about that, I posted to comp.lang.java.gui first and then here
as I was unsure if this question belonged to the gui NG as it is more a
design thing?

> I haven't looked at his answer in the other newsgroup, so I don't know
> what's already been suggested, nor do I know anything you've posted
> there.  (This is a good example of why you shouldn't multi-post, by the
> way).
Yes sorry again I really didn't give it a thought at the time, what
Knute suggested has been extremely helpful and gives me part of my
answer, and that is that as long as I have a reference to the graphic of
the component I can draw to this and send a repaint call to the
component after?

> Any particular reason for extending JPanel?  Does your custom component
> actually need to act as a simple container for other components?  If
> not, perhaps you should simply be extending JComponent.

No particular reason, I chose JPanel as most of the examples I have seen
use this.

> Why would an image be "enlarged"?  How does that happen?  Hint: it's at
> whatever point the image display, including scaling, is configured that
> you'd set the necessary data that will be used later for drawing the image.

Int the graphic object and then call a repaint on the component to
refresh display?

> I doubt you need to use getSubImage().  Your component's drawing will be
> clipped to the boundary of the image, so all you really need to do is
> transform the Graphics2D correctly (scale and translate, if I understand
> your post correctly) and the image will be placed and draw appropriately.

Thanks, the more I learn about Java the more I realise how much it can
do for you.

> I'm not really clear on what the "non gui logic class" is.  Anything
> that needs to know the size of your custom component and involves itself
> in the drawing of the component is, to my perception, a GUI class.  
Ah my idea of a gui class is an extended JPanel stuffed with code :)

If you have in mind a class that doesn't know anything about the GUI, then
> perhaps you could be more explicit about that.  
This is exactly what I had in mind, if my understanding is correct then
passin a reference of tthe components graphic object will allow me to
draw to the graphic and then fire an event for the component to redraw
itself.

> What interface does that class implement?  
> I don't mean what's the name of the interface; I mean,
> what methods, properties, and/or fields are exposed by that interface?  
I would imagine methods something like
scale, translate, draw, update, origin, rotate, drawText, to name a few
> How does your custom component use this hypothetical "non gui logic class"?

I am guessing that the component class would create an instance of the
logic class and pass it's graphic object and an image in the constructor
and would implement property change listener.

Any buttons or menu item events would call the relevant method in the
logic class.

The logic class would calculate positions, scales and translations etc
and then using the graphic reference draw to this and then call repaint
on the component, possibly via an event, not 100% sure though

> Well, typically the custom component would either itself be directly
> informed of changes to the image, or it would refer to some data
> structure that itself knows about the changes.  By the time repaint() is
> called, everything should already be set up to draw the custom component
> correctly.  The paintComponent() method itself would then simply use the
> current state of the data structures involved to draw the correct thing.
This sounds interesting, how would this work? this sounds similar to the
Swing Model View pattern?

> Again, I'm not really sure what you mean here.  The Graphics2D instance
> doesn't have any state that specifically would know about your image.  
[quoted text clipped - 4 lines]
> paintComponent() method would have to do is call Graphics2D.transform()
> with the AffineTransform that you'd computed earlier.
By using the reference to the components graphic object ?

> Alternatively, you could just compute the necessary parameters that
> would be used later to call one of the many drawImage() overloads
> defined in Graphics and Graphics2D and rather than setting the
> transform, just call the appropriate overload directly.

Do you mean Graphics2D.DrawImage, DrawLine etc?

Thanks for you help and paitience
Rich
Peter Duniho - 14 Mar 2008 19:06 GMT
> [...]
> Yes sorry again I really didn't give it a thought at the time, what  
> Knute suggested has been extremely helpful and gives me part of my  
> answer, and that is that as long as I have a reference to the graphic of  
> the component I can draw to this and send a repaint call to the  
> component after?

The way I read the above: you've got a GUI component that only redraws  
itself using a referenced "graphic" (there's no such thing as a "graphic"  
in Java...do you mean an instance of Image, such as BufferedImage?), while  
some other code draws into the "graphic" and then tells the component that  
the "graphic" has changed.

Is that a correct understanding of what you wrote?  If so, then that seems  
fine to me.

>> Any particular reason for extending JPanel?  Does your custom component  
>> actually need to act as a simple container for other components?  If  
>> not, perhaps you should simply be extending JComponent.
>>
> No particular reason, I chose JPanel as most of the examples I have seen  
> use this.

Well, unless you have a specific reason for using JPanel, then don't.  
Extend JComponent instead, as it's the actual base class for Swing  
components.

>> Why would an image be "enlarged"?  How does that happen?  Hint: it's at  
>> whatever point the image display, including scaling, is configured that  
[quoted text clipped - 3 lines]
> Int the graphic object and then call a repaint on the component to  
> refresh display?

You're answering a question with a question (and one I don't really  
understand either...what does the word "int" mean here?  The usual meaning  
in this context, "integer", doesn't seem to apply).

> [...]
>> I'm not really clear on what the "non gui logic class" is.  Anything  
[quoted text clipped - 3 lines]
>
> Ah my idea of a gui class is an extended JPanel stuffed with code :)

Well, fine.  But that's not an explanation as to what a "non gui logic  
class" is.

> If you have in mind a class that doesn't know anything about the GUI,  
> then
[quoted text clipped - 4 lines]
> draw to the graphic and then fire an event for the component to redraw  
> itself.

See above.  If I understand this statement correctly, then it seems like a  
fine approach.  If I don't, then it might or might not be.  :)

>> What interface does that class implement?
>> I don't mean what's the name of the interface; I mean,
>> what methods, properties, and/or fields are exposed by that interface?
>
> I would imagine methods something like
> scale, translate, draw, update, origin, rotate, drawText, to name a few

Are the transformation operations (scale, translate, rotate...and what's  
the difference between "translate" and "origin"?) independent of the  
similar operations that would be set for the custom Swing component?  That  
is, from your previous description, I have the impression that you want to  
be able to scale and center the image in the custom component, and now  
from this most recent description I have the impression that you also want  
to be able to do things like that and other operations on the non-GUI  
class.

>> How does your custom component use this hypothetical "non gui logic  
>> class"?
>
> I am guessing that the component class would create an instance of the  
> logic class and pass it's graphic object and an image in the constructor  
> and would implement property change listener.

What's the difference between "its graphic object" and "an image"?  At the  
outset of this message, I made the assumption that your ambiguous term  
"graphic" referred to some sort of Image instance.  But if you can have  
both a "graphic" and an "image", then I'm not so sure.

> Any buttons or menu item events would call the relevant method in the  
> logic class.
>
> The logic class would calculate positions, scales and translations etc  
> and then using the graphic reference draw to this and then call repaint  
> on the component, possibly via an event, not 100% sure though

I think it makes more sense to follow the "listener" idiom, where your  
"non-GUI" class defines a listener interface that the Swing component can  
implement and respond to.  Then when changes are made, the listener is  
notified.  In this case, the Swing component would call repaint() itself,  
but this allows for a more general-purpose "non-GUI" class.  After all, if  
it's "non-GUI" then why should it know about a JComponent that needs to  
have repaint() called?

Other than that, your description sounds fine.  Of course, that assumes I  
understand the rest of the model correctly, which may or may not be the  
case.

>> Well, typically the custom component would either itself be directly  
>> informed of changes to the image, or it would refer to some data  
[quoted text clipped - 6 lines]
> This sounds interesting, how would this work? this sounds similar to the  
> Swing Model View pattern?

Well, it's more like being "similar" to the event-driven GUI updating  
paradigm that practically all mainstream GUI's use.

Model/View is about separating the data from the model.  And it works well  
in an event-driven paradigm.  But it's not mandatory...you can easily have  
views (i.e. Swing components) that incorporate their own model, and that's  
not in line with the Model/View pattern.  Yet, they would still use this  
"change some data, call repaint() to ask to be repainted" paradigm.

In other words, what I'm describing really isn't optional, the way that  
Model/View is.  A correctly-written GUI application will always use this  
event-driven paradigm, whether or not it separates the model from the view.

>>  Again, I'm not really sure what you mean here.  The Graphics2D  
>> instance doesn't have any state that specifically would know about your  
[quoted text clipped - 6 lines]
>
> By using the reference to the components graphic object ?

Again, that depends on what you mean by "graphic object".  But sure, if  
that "graphic" object keeps track of the transform needed for drawing,  
that would be a natural place to get the AffineTransform instance.

Note that setting the Graphics2D transform is not the only approach.  You  
can also pass a transform to some of the Graphics2D.drawImage() overloads,  
and it would have the same effect as changing the Graphics2D's own  
transform.  This is what I'm talking about here:

>>  Alternatively, you could just compute the necessary parameters that  
>> would be used later to call one of the many drawImage() overloads  
>> defined in Graphics and Graphics2D and rather than setting the  
>> transform, just call the appropriate overload directly.
>
> Do you mean Graphics2D.DrawImage, DrawLine etc?

Those are not the names of any methods in the Graphics2D class.  But if  
you mean Graphics2D.drawImage(), yes.  For that method, you could just  
pass a precomputed transform.  For drawLine(), there's no such  
overload...you've have to explicitly transform integer coordinates  
yourself and then use the Graphics.drawLine() method, or create a Shape  
representing the line and either transform the Shape before drawing it  
(some Shape implementations include a transform() method) or set the  
Graphics2D transform itself.

It all depends on exactly what you want to do.

In the hopes that it might help you out a little, I've attached below an  
example of a simple custom Swing component that has image and scale  
properties that can be set, and which always draws the image centered in  
the component at the scale that's been set.  It doesn't demonstrate the  
additional layer that I think you've been talking about, where there's an  
intermediate class that actually manages things like holding on to the  
image, storing settings like scale factor, and implementing notification  
for listeners, but hopefully it gives you a better idea of how the Swing  
component side of things would work.

The custom Swing class is first, followed by some simple sample code that  
demonstrates the use of it.  (The demo code just opens image files, but  
the custom component can also just be assigned some arbitrary image; it  
would be simple enough to add a public method to notify the component that  
the image's changed so that the component knows to call repaint(), but as  
I mentioned before I think it would be better to implement a full-fledged  
"listener" API that the component can subscribe to if you're going to have  
anything more elaborate than just a simple reference to an Image instance  
as shown here).

Pete

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;

public class JImageBox extends JComponent
{
    private Image _image;
    private double _scale = 1.0;
    AffineTransform _transform;

    public JImageBox()
    {
        this.addComponentListener(new ComponentAdapter()
        {
            public void componentResized(ComponentEvent arg0)
            {
                _UpdateImage();
            }
        });
    }

    public void setImage(BufferedImage image)
    {
        _image = image;
        _UpdateImage();
    }

    public void setImage(File file)
    {
        try
        {
            _image = ImageIO.read(file);
        }
        catch (IOException e)
        {
            e.printStackTrace();
            _image = null;
        }
        _UpdateImage();
    }

    public void setScale(double scale)
    {
        _scale = scale;
        _UpdateImage();
    }

    protected void paintComponent(Graphics gfx)
    {
        if (_image != null)
        {
            Graphics2D gfx2 = (Graphics2D)gfx;

            gfx2.drawImage(_image, _transform, null);
        }
    }

    private void _UpdateImage()
    {
        _transform = null;

        if (_image != null)
        {
            Dimension size = getSize();
            double cxImage, cyImage;

            cxImage = _image.getWidth(null) * _scale;
            cyImage = _image.getHeight(null) * _scale;

            _transform = AffineTransform.getTranslateInstance(
                (size.getWidth() - cxImage) / 2,
                (size.getHeight() - cyImage) / 2);
            _transform.scale(_scale, _scale);
        }

        repaint();
    }
}

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;

public class TestImageComponentFrame extends JFrame
{
    private JImageBox _imagebox = new JImageBox();

    public TestImageComponentFrame(String arg0)
    {
        super(arg0);

        setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));

        Box box = Box.createHorizontalBox();

        JButton button = new JButton("Open File...");
        button.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent arg0)
            {
                _ChooseImage();
            }
        });
        box.add(button);

        final JTextField text = new JTextField("1.0", 8);
        text.setMaximumSize(text.getPreferredSize());
        button = new JButton("Set Scale");
        button.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent arg0)
            {
                try
                {
                    _imagebox.setScale(Double.parseDouble(text.getText()));
                }
                catch (NumberFormatException e)
                {
                    e.printStackTrace();
                }
            }
        });
        box.add(button);
        box.add(text);

        add(box);
        add(_imagebox);
    }

    private void _ChooseImage()
    {
        FileDialog filedlg = new FileDialog(this, "Please choose an image  
file to load:", FileDialog.LOAD);

        filedlg.setVisible(true);

        if (filedlg.getFile() != null)
        {
            _imagebox.setImage(new File(filedlg.getDirectory()  
+ filedlg.getFile()));
        }
    }
}

import java.awt.*;

public class TestImageComponent
{
    /**
     * @param args
     */
    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                TestImageComponentFrame frame = new  
TestImageComponentFrame("TestImageComponentFrame");

                frame.setSize(640, 480);
                frame.setVisible(true);
            }
        });
    }
}
RichT - 14 Mar 2008 21:05 GMT
> The way I read the above: you've got a GUI component that only redraws
> itself using a referenced "graphic" (there's no such thing as a
> "graphic" in Java...do you mean an instance of Image, such as
> BufferedImage?), while some other code draws into the "graphic" and then
> tells the component that the "graphic" has changed.

I am not sure, I was referring to Graphics2D or Graphics as the graphic
object, which appears to be an abstract class in the API, so I am
guessing rightly or wrongly that this would be the image/buffered image?

> Is that a correct understanding of what you wrote?  If so, then that
> seems fine to me.

If my understanding of your understanding (see above) is correct then yes :)

> Well, unless you have a specific reason for using JPanel, then don't.  
> Extend JComponent instead, as it's the actual base class for Swing
> components.
Ok thanks for the tip :)

> You're answering a question with a question (and one I don't really
> understand either...what does the word "int" mean here?  The usual
> meaning in this context, "integer", doesn't seem to apply).

Oh dear that was a mistake it seems that half the text vanished (more
likely I deleted it by mistake when editing ;))

I meant This would most likely be triggered by an event from the user,
in the gui logic class the calculations would be made in an
AffineTransform passed to the Grahics2D.DrawImage(img, affineTransform,
null) and then an event sent to the component to redraw itself.

> Well, fine.  But that's not an explanation as to what a "non gui logic
> class" is.

Ok I think I mean a class that handles the logic for the gui component :)

> See above.  If I understand this statement correctly, then it seems like
> a fine approach.  If I don't, then it might or might not be.  :)

Excellent :)

> Are the transformation operations (scale, translate, rotate...and what's
> the difference between "translate" and "origin"?)

Nothing :) they mean the same thing

> That is, from your previous description, I have the impression that you
> want to be able to scale and center the image in the custom component,

correct :)

> and now from this most recent description I have the impression that you
> also want to be able to do things like that and other operations on the
> non-GUI class.

Correct again :) including drawing test into the image (perhaps later
much later when I understand this better)

> What's the difference between "its graphic object" and "an image"?  

I am not entirely sure I thought Graphics2D was a reference to the
components graphical context?

At
> the outset of this message, I made the assumption that your ambiguous
> term "graphic" referred to some sort of Image instance.  But if you can
> have both a "graphic" and an "image", then I'm not so sure.

I am unsure now too :(

Thanks for all your help so far, I will answer the rest of this post
later :)

Rich
Peter Duniho - 14 Mar 2008 21:33 GMT
>> The way I read the above: you've got a GUI component that only redraws  
>> itself using a referenced "graphic" (there's no such thing as a  
[quoted text clipped - 5 lines]
> object, which appears to be an abstract class in the API, so I am  
> guessing rightly or wrongly that this would be the image/buffered image?

Not exactly.  There is a BufferedImage class.  That would be the actual  
image.  You can call BufferedImage.createGraphics() to get a Graphics2D  
that will allow you to draw into that image.  That's a "Graphics2D"  
instance, not a "graphic".

I apologize if it seems like I'm being picky, but the compiler will be at  
least as picky :) and I feel that since there are precise terms that refer  
to specific classes, those terms should be used.  Otherwise, it's  
impossible to know that we're really talking about the same thing.  It  
will be much more productive if you are careful to use the exact names for  
things, where those things have exact names.

So, anyway, the Graphics2D isn't the actual image per se, but it is a sort  
of portal that lets you get at the image with various drawing operations,  
allowing you to modify it according to your needs.

>> Is that a correct understanding of what you wrote?  If so, then that  
>> seems fine to me.
>
> If my understanding of your understanding (see above) is correct then  
> yes :)

See above.  I think I _almost_ understood what you were talking about.  :)

I don't know how expensive it is in Java to create a Graphics2D from a  
BufferedImage instance.  But assuming it's not overly expensive, then it  
seems to me that the object you really want to hang on to would be the  
BufferedImage instance only, creating a Graphics2D as necessary whenever  
you want to update the image.

You haven't been very specific about what sorts of updates you might do,  
but again there seems to be the assumption that there's some higher-level,  
user-defined class (where "user" is you) that encapsulates the behavior of  
the BufferedImage and Graphics2D, exposing it in a more general way.  If  
that's the correct assumption, then I think the "listener" mechanism I  
mentioned earlier is still appropriate for dealing with updates to the  
Swing component that displays this image.

> [...]
> I meant This would most likely be triggered by an event from the user,  
> in the gui logic class the calculations would be made in an  
> AffineTransform passed to the Grahics2D.DrawImage(img, affineTransform,  
> null) and then an event sent to the component to redraw itself.

That doesn't make much sense as I understand the previous discussion.  The  
only image that you've mentioned so far is the one that represents your  
non-GUI data structure.  The only time you'd draw that image would be in  
the paintComponent() method itself.

Are you saying that one of the operations you might have on this non-GUI  
data structure is to draw yet another image into it?  How does the "gui  
logic class" come into play here?  By "gui logic class", are you talking  
about your custom Swing component that's displaying your non-GUI data  
structure?  Or something else?

>> Well, fine.  But that's not an explanation as to what a "non gui logic  
>> class" is.
>
> Ok I think I mean a class that handles the logic for the gui component :)

Why are you using the phrase "non gui logic class" to description  
something that "handles the logic for the gui component"?  To me, "non  
gui" implies no connection with the GUI.  Conversely, "handles the logic  
for the gui component" implies a direct connection with the GUI.

The two seem mutually exclusive to me, and yet you seem to be using the  
phrases as being directly related to each other.  I'm obviously not  
understanding what you mean, and I hope that my explanation here makes it  
clear why so that you can clarify.

> [...]
>> That is, from your previous description, I have the impression that you  
>> want to be able to scale and center the image in the custom component,
>
> correct :)

Then hopefully the code I posted can help with that part of the problem.

>> and now from this most recent description I have the impression that  
>> you also want to be able to do things like that and other operations on  
>> the non-GUI class.
>
> Correct again :) including drawing test into the image (perhaps later  
> much later when I understand this better)

As I noted at the beginning of this message, you can draw into a  
BufferedImage by getting a Graphics2D from it (by calling  
createGraphics()).  With that Graphics2D instance you can draw whatever  
you like onto the BufferedImage, including text (I assume that's what you  
meant instead of "test" :) ).

>> What's the difference between "its graphic object" and "an image"?
>
> I am not entirely sure I thought Graphics2D was a reference to the  
> components graphical context?

The Graphics2D instance passed to paintComponent() is such a reference.  
It's used for drawing the representation of the custom Swing component.  
As such it has very little to do with a Graphics2D that you might obtain  
from an image data structure, such as a BufferedImage.  I mean, it's the  
same class, and so of course you can do all the same drawing operations  
regardless.  But in the former, those operations wind up shown on the  
screen, whereas in the latter, they wind up modifying the BufferedImage.

It kind of sounds like you really have at least two parts to this design  
question:

    * how to display an image in a custom Swing component
    * how to maintain that image in a class that isn't specific to the GUI

I think that mostly I've been answering the first question, though  
hopefully some of the things I've written above help address the second.  
If you disagree with the "two parts" assertion, please explain why so that  
I (and anyone else reading) can understand better what the actual question  
or questions are.

Pete
RichT - 15 Mar 2008 18:32 GMT
Hi again Peter :)

> I apologize if it seems like I'm being picky, but the compiler will be
> at least as picky :) and I feel that since there are precise terms that
> refer to specific classes, those terms should be used.  

No problem you are not being picky ;) I am just not being as clear and
concise with my questions as you have been with you answers :)

Otherwise, it's
> impossible to know that we're really talking about the same thing.  It
> will be much more productive if you are careful to use the exact names
> for things, where those things have exact names.

This makes sense and reduces the possibility of any ambiguity :)

> So, anyway, the Graphics2D isn't the actual image per se, but it is a
> sort of portal that lets you get at the image with various drawing
> operations, allowing you to modify it according to your needs.

This was my understanding too I think :)

>>> Is that a correct understanding of what you wrote?  If so, then that
>>> seems fine to me.
[quoted text clipped - 3 lines]
>
> See above.  I think I _almost_ understood what you were talking about.  :)

Yes you did :)

> I don't know how expensive it is in Java to create a Graphics2D from a
> BufferedImage instance.  But assuming it's not overly expensive, then it
> seems to me that the object you really want to hang on to would be the
> BufferedImage instance only, creating a Graphics2D as necessary whenever
> you want to update the image.

Ok to the  'Gui Componet class' = the swing component and 'Gui Component
Engine class' = the non Swing class which will hold a reference to the
image and perform changes to it.

Yes this is what I want :) So the 'Gui Component class' will create the
the 'Gui Component Engine class' and pass it the buffered image that
itself will display, itself being the 'Gui Component class'.

> You haven't been very specific about what sorts of updates you might do,
> but again there seems to be the assumption that there's some
[quoted text clipped - 3 lines]
> "listener" mechanism I mentioned earlier is still appropriate for
> dealing with updates to the Swing component that displays this image.

Spot on :)

> That doesn't make much sense as I understand the previous discussion.  
> The only image that you've mentioned so far is the one that represents
> your non-GUI data structure.  The only time you'd draw that image would
> be in the paintComponent() method itself.

No I am not sure it does either :), no my 'non-GUI' data structure as I
understand it is not the 'Gui Component class' but the 'Gui Component
Engine class' 'BufferedImage' reference.

> Are you saying that one of the operations you might have on this non-GUI
> data structure is to draw yet another image into it?  How does the "gui
> logic class" come into play here?  By "gui logic class", are you talking
> about your custom Swing component that's displaying your non-GUI data
> structure?  Or something else?

No :) not custome Swing component, the 'Gui Component Engine class'

> Why are you using the phrase "non gui logic class" to description
> something that "handles the logic for the gui component"?  To me, "non
> gui" implies no connection with the GUI.  Conversely, "handles the logic
> for the gui component" implies a direct connection with the GUI.

Yes sorry again ;) this is very ambiguous, I am not referring to the
'Gui Component class' but the 'Gui Component Engine class.

> The two seem mutually exclusive to me, and yet you seem to be using the
> phrases as being directly related to each other.  I'm obviously not
> understanding what you mean, and I hope that my explanation here makes
> it clear why so that you can clarify.

> Then hopefully the code I posted can help with that part of the problem.
It has :)

> As I noted at the beginning of this message, you can draw into a
> BufferedImage by getting a Graphics2D from it (by calling
> createGraphics()).  With that Graphics2D instance you can draw whatever
> you like onto the BufferedImage, including text (I assume that's what
> you meant instead of "test" :) ).

Yes I did mean text :) and of course spell check did not pick this up
because test is a legitimate word in the English Dictionary as is text :)

> The Graphics2D instance passed to paintComponent() is such a reference.  
> It's used for drawing the representation of the custom Swing component.  
[quoted text clipped - 3 lines]
> regardless.  But in the former, those operations wind up shown on the
> screen, whereas in the latter, they wind up modifying the BufferedImage.

I understand this now, Graphics2D is more an interface than a class, so
that any class which implements it is able to implement its methods in a
way that makes sense to that particular class, but anything that accepts
a Graphics2D can call this interfaces methods and they will just work?
have I understood this bit correctly :)

> It kind of sounds like you really have at least two parts to this design
> question:
>
>     * how to display an image in a custom Swing component
>     * how to maintain that image in a class that isn't specific to the GUI

Yes this is correct :) I know how to display the image in the component
now, and I also believe I now understand how to maintain and manipulate
this image in the 'Gui Component Engine class' using the 'BufferedImage'
Graphics2D object applying an AffineTransform to it and then sending an
event to the 'Gui Component class' informing it that the image has been
modified and this class could then call its repaint() method which would
then call its paintComponent(Graphics g) method :)

> I think that mostly I've been answering the first question, though
> hopefully some of the things I've written above help address the
> second.  

Indeed they have :)

If you disagree with the "two parts" assertion, please explain
> why so that I (and anyone else reading) can understand better what the
> actual question or questions are.

I don't ;)

Rich
Peter Duniho - 15 Mar 2008 18:48 GMT
> [...]
>> The Graphics2D instance passed to paintComponent() is such a  
[quoted text clipped - 11 lines]
> a Graphics2D can call this interfaces methods and they will just work?  
> have I understood this bit correctly :)

Yes, basically.  I mean, technically the Graphics2D class is a class, but  
since it's an abstract class with pretty much all abstract methods, it  
operates very much like an interface.  I think there are good reasons for  
it being an abstract class rather than an interface, but from the client  
point of view, it is basically just an interface, in the sense that it's a  
contract that is implemented by various graphical objects to allow a  
uniform way to draw to those graphical objects.

>>  It kind of sounds like you really have at least two parts to this  
>> design question:
[quoted text clipped - 9 lines]
> modified and this class could then call its repaint() method which would  
> then call its paintComponent(Graphics g) method :)

Please see my other post.  In particular, where you write "using the  
'BufferedImage' Graphics2D object applying an AffineTransform to it", I  
believe you've misunderstood what setting a transform on that particular  
Graphics2D object will do.

I have the impression that this spur of the thread is basically dealt  
with, and so for simplicity's sake I'll try to keep my replies in the  
other main trunk of the thread.

Pete
RichT - 15 Mar 2008 23:37 GMT
> Please see my other post.  In particular, where you write "using the
> 'BufferedImage' Graphics2D object applying an AffineTransform to it", I
[quoted text clipped - 6 lines]
>
> Pete

Thank you for your help :)
RichT - 15 Mar 2008 17:36 GMT
Hi Peter,

> I think it makes more sense to follow the "listener" idiom, where your
> "non-GUI" class defines a listener interface that the Swing component
> can implement and respond to.  

Yes this was indeed my initial thought :) the two classes which I shall
now refer to as the 'Gui Component class' and the 'Gui Component Engine
class'

When the Gui Component Engine makes a change to the image in some may
perhaps to scale the image, this will send the Gui Component class an
event which will call repaint().

I understand now that the overridden paintComponent(Graphics g) method
is not called directly but will be called by the repaint() method of the
component indirectly ? :)

Now if my understanding of the rest of the post is correct I would place
in the overridden paintComponent method something like
g2d.drawImage(bufferedImage, affineTransform, null) as per your code?

Then when changes are made, the listener
> is notified.  In this case, the Swing component would call repaint()
> itself, but this allows for a more general-purpose "non-GUI" class.  
> After all, if it's "non-GUI" then why should it know about a JComponent
> that needs to have repaint() called?

Yes this is true :)

> Model/View is about separating the data from the model.  And it works
> well in an event-driven paradigm.  But it's not mandatory...you can
> easily have views (i.e. Swing components) that incorporate their own
> model, and that's not in line with the Model/View pattern.  Yet, they
> would still use this "change some data, call repaint() to ask to be
> repainted" paradigm.

I see, I think this is what I want for my design ?

> In other words, what I'm describing really isn't optional, the way that
> Model/View is.  A correctly-written GUI application will always use this
> event-driven paradigm, whether or not it separates the model from the view.

I think I understand now :)

> Again, that depends on what you mean by "graphic object".  But sure, if
> that "graphic" object keeps track of the transform needed for drawing,
[quoted text clipped - 4 lines]
> overloads, and it would have the same effect as changing the
> Graphics2D's own transform.  This is what I'm talking about here:

Ok I understand now I think, from your other post to reply part I, I can
get the graphic object of the Image and do calculations on this and then
send an event to the listener i.e. the Gui Component Class which will
then call its repaint() and anything else it wants to method?

> It all depends on exactly what you want to do.
>
> In the hopes that it might help you out a little, I've attached below an
> example of a simple custom Swing component that has image and scale
> properties that can be set, and which always draws the image centered in
> the component at the scale that's been set.  

Thank you for this code it has been very helpful, I possibly would not
always want the image scaled up or down but certainly want it centred.

It doesn't demonstrate the
> additional layer that I think you've been talking about, where there's
> an intermediate class that actually manages things like holding on to
> the image, storing settings like scale factor, and implementing

Yes I believe this is the additional layer I am looking for, but if my
understanding is correct, just having a reference to the image will
allow me to do all this by getting a reference to its graphic and apply
a transform to this and then send an event to the component informing of
a change to the image, where more than likely the component would call
its own repaint() method?

> notification for listeners, but hopefully it gives you a better idea of
> how the Swing component side of things would work.

Indeed it does  thanks :)

> The custom Swing class is first, followed by some simple sample code
> that demonstrates the use of it.  (The demo code just opens image files,
[quoted text clipped - 5 lines]
> you're going to have anything more elaborate than just a simple
> reference to an Image instance as shown here).

Thank you for all your patience, your answers have been clear and
concise, unlike some of my questions, sorry about that, a mix of not
understanding certain concepts myself and a wireless keyboard which
intermittently misses key stroke (or perhaps I just type too fast ;)) :)

Rich
Lew - 15 Mar 2008 18:13 GMT
> a wireless keyboard which
> intermittently misses key stroke (or perhaps I just type too fast ;)) :)

I have a wireless keyboard/mouse combination that feeds through an A/B USB
switch, and it used to miss keystrokes abominably.

When I changed the batteries in the mouse, the keyboard behaved better, in
fact, flawlessly since then.  Even at speeds in the vicinity of 50 wpm, at times.

It is true that the kb and the mouse share a USB port with this model
(Microsoft Wireless Optical Desktop 4000).  It may also be that weak or
scrambled radio transmissions from the mouse were harming the receiver's
ability to decode the keyboard's transmissions.

I use rechargeable batteries, incidentally.  The life of the charge in these
units seems to be months, three to sixish.

Signature

Lew

Peter Duniho - 15 Mar 2008 18:30 GMT
> [...]
> I understand now that the overridden paintComponent(Graphics g) method  
> is not called directly but will be called by the repaint() method of the  
> component indirectly ? :)

Yes.  And by "indirectly", this means that the paintComponent() method  
does not generally get called until some time _after_ repaint() has  
returned to its caller.  That is, it's not even that repaint() itself  
winds up calling paintComponent() or something that calls it.  Instead, it  
simply signals to the Java system that the component needs to be redrawn  
and returns.  Later on, Java then gets around to calling paintComponent()  
to have the component redrawn (in fact, if you look you'll notice that  
there are some overloads of repaint() that give you some degree of control  
regarding the definition of "later on").

> Now if my understanding of the rest of the post is correct I would place  
> in the overridden paintComponent method something like  
> g2d.drawImage(bufferedImage, affineTransform, null) as per your code?

Well, I obviously think so.  :)  That's why I wrote the code that way.

> [...]
>> Again, that depends on what you mean by "graphic object".  But sure, if  
[quoted text clipped - 9 lines]
> send an event to the listener i.e. the Gui Component Class which will  
> then call its repaint() and anything else it wants to method?

I'll ask you again to be more specific about your terminology.  You've  
already written that you're going to describe your Swing component as "Gui  
Component class" and "Gui Component Engine class", neither of which are  
"graphic".  So do you mean something else by "graphic"?  Perhaps you mean  
to write "Graphics2D"?

It's difficult to make sure that your question is answered correctly and  
precisely if you yourself aren't using correct and/or precise terminology.

Now, assuming that you mean "Graphics2D", I would say that the answer is  
"no".  You don't "do calculations" on a Graphics2D instance, at least not  
as I am in the habit of using the phrase "do calculations".  You use it to  
draw into some image presentation object (for example, an Image object, or  
the on-screen representation of a JComponent).

You can do two things with a Graphics2D: you can change its own state, and  
you can perform a drawing operation (which changes the state of something  
the Graphics2D refers to, like a BufferedImage).  Only the drawing  
operations persist and affect later users of the underyling image object.  
Changing state of the Graphics2D object, such as setting a transformation,  
setting a stroke, a color, etc. these things only affect subsequent  
drawing operations using _that_ Graphics2D object.

So, for example, you can't have a BufferedImage, get a Graphics2D object  
from it, set the scaling for that Graphics2D, and then expect that to  
change how the BufferedImage is drawn when used later by being drawn into  
a _different_ Graphics2D object passed to a control's paintComponent()  
method.

Again, because your question is somewhat vague it's hard for me to know  
whether this is what you expect or not.  But it sort of sounds like you  
expect to be able to set the transformation for the Graphics2D, doing  
nothing else, and then have that have some effect when the underlying  
image object is drawn later.  If you do, then that expectation isn't going  
to work.

> [...]
> It doesn't demonstrate the
[quoted text clipped - 8 lines]
> a change to the image, where more than likely the component would call  
> its own repaint() method?

See above.  Most of what you wrote seems fine, except for the part where  
you write "apply a transform to this and then send an event to the  
component informing of a change to the image".  Applying a transform to a  
Graphics2D that you've obtained from an Image object doesn't change the  
image itself.  It only affects drawing operations _to_ that Image done  
later through the Graphics2D object that you set a new transform for.

Again, I don't know whether this is what you meant, because you're not  
using precise terminology.  But previously in this thread you seem to be  
using the word "graphic" (incorrectly) to refer to a Graphics2D object.  
If that's the case here, then my reply is accurate.

It seems to me that if you want to be able to apply scaling, translation,  
or rotation changes to the image itself (as opposed to things being drawn  
into the image), then those are things that should be stored as state in  
your "Gui Component Engine class".

You might even just maintain a single AffineTransform instance, updated  
any time those things are changed, and then used to draw the image later.  
You could do this by having your "Gui Component Engine class" have a  
property that returns this transform as well as the Image that the class  
stores.  Or you could have your "Gui Component Engine class" have a method  
that takes as a parameter a Graphics2D instance, and then itself draws the  
Image into that Graphics2D using the transform that's been set.

In either case, note that the transform in this situation is used for  
_presenting_ the underlying image object that your "Gui Component Engine  
class" is storing.  It doesn't affect the image directly, but rather  
affects how the image is displayed at some later point.

At least based on what you've written so far, it seems to me that you  
should be careful to keep in mind that you have two different places where  
"drawing" happens.  There is drawing into your "Gui Component Engine  
class"'s image object, and then there is the drawing _of_ the "Gui  
Component Engine class"'s image object.  Each will use its own Graphics2D  
object to handle drawing, and you'll need to be careful to make sure  
you're changing the state you care about in the appropriate place  
depending on what effect you want it to have.

Pete
RichT - 15 Mar 2008 23:58 GMT
Hi Peter,

> Well, I obviously think so.  :)  That's why I wrote the code that way.

Doh ;)

> I'll ask you again to be more specific about your terminology.  You've
> already written that you're going to describe your Swing component as
> "Gui Component class" and "Gui Component Engine class", neither of which
> are "graphic".  So do you mean something else by "graphic"?  Perhaps you
> mean to write "Graphics2D"?

Yes I do mean Graphic2D :)

> It's difficult to make sure that your question is answered correctly and
> precisely if you yourself aren't using correct and/or precise terminology.
Sorry :(

> Now, assuming that you mean "Graphics2D",
I do :)
I would say that the answer is
> "no".  You don't "do calculations" on a Graphics2D instance, at least
> not as I am in the habit of using the phrase "do calculations".  You use
[quoted text clipped - 14 lines]
> into a _different_ Graphics2D object passed to a control's
> paintComponent() method.
Ah Now I really do think I understand now :)

> Again, because your question is somewhat vague it's hard for me to know
> whether this is what you expect or not.  But it sort of sounds like you
> expect to be able to set the transformation for the Graphics2D, doing
> nothing else, and then have that have some effect when the underlying
> image object is drawn later.  If you do, then that expectation isn't
> going to work.

The Grpahics2D of the Image affects drawing to the image, the Graphics2D
 in the 'Gui Component class' affects drawing of the component, so to
display the image correctly in the component will require that the 'Gui
Components class' Grpahics2D to be updated too ?

> Again, I don't know whether this is what you meant, because you're not
> using precise terminology.  But previously in this thread you seem to be
> using the word "graphic" (incorrectly) to refer to a Graphics2D object.  
> If that's the case here, then my reply is accurate.
Yes it is what I meant :)

> It seems to me that if you want to be able to apply scaling,
> translation, or rotation changes to the image itself (as opposed to
> things being drawn into the image), then those are things that should be
> stored as state in your "Gui Component Engine class".
using fields perhaps an AffineTransform?

> You might even just maintain a single AffineTransform instance, updated
> any time those things are changed, and then used to draw the image
[quoted text clipped - 4 lines]
> itself draws the Image into that Graphics2D using the transform that's
> been set.

Which way would you suggest? I guess the 'Gui Component class' should
draw its own Graphics2D?

> In either case, note that the transform in this situation is used for
> _presenting_ the underlying image object that your "Gui Component Engine
> class" is storing.  It doesn't affect the image directly, but rather
> affects how the image is displayed at some later point.

I think I get this now :) I hope

> At least based on what you've written so far, it seems to me that you
> should be careful to keep in mind that you have two different places
[quoted text clipped - 4 lines]
> make sure you're changing the state you care about in the appropriate
> place depending on what effect you want it to have.

Thank you for all your help, I really do believe I understand this now
thanks to your patience.

I think it makes more sense for the 'Gui Component class' to handle its
own drawing so providing a method in the 'Gui Component Engine class' to
return the AffineTransform is possibly better?

I may not have acces to internet for a couple of days, but I am going to
 prototype some of these ideas and will post back the results to check
my understanding

Thanks for everything
Rich
Peter Duniho - 16 Mar 2008 00:58 GMT
> [...]
>>  Again, because your question is somewhat vague it's hard for me to  
[quoted text clipped - 8 lines]
> display the image correctly in the component will require that the 'Gui  
> Components class' Grpahics2D to be updated too ?

Sort of.  At the time that you want to adjust how the image is displayed,  
there is no Graphics2D to update.  You only get one of those when the  
component actually needs to be repainted and that Graphics2D is only  
around long enough for you to repaint the component.

But you can (and should) store data that can be used at that point in  
time, applying the data (an AffineTransform, for example) to the  
Graphics2D passed to you when the paintComponent() method is called by  
Java.

> [...]
>>  You might even just maintain a single AffineTransform instance,  
[quoted text clipped - 7 lines]
>
> Which way would you suggest?

It depends on how exactly you're using the "engine".

Part of the lack of a clearly superior choice is that it seems as though  
you want to include in your engine properties that affect how the image is  
drawn.  You mentioned scaling, translation, and rotation for example.  
These things can all be defined relative to the image itself, independent  
of wherever it might actually be drawn.

At the same time, you've also said that the image should be drawn centered  
in the component, which implies a contributor to the translation that's  
relative to the component itself.  This cannot be defined relative to the  
image; it only would make sense in the context of a component.

So, on the one hand, it'd be nice to have the "engine" draw itself into  
some arbitrary Graphics2D.  That way if you want to reuse the "engine" in  
a different context, it doesn't require you duplicating a bunch of code  
that gets the properties from the "engine" and uses them to draw the image.

On the other hand, doing it that way means you necessarily have to pass  
_some_ kind of contextual information in addition to the Graphics2D  
instance.  That's not terrible -- after all, the Graphics2D is itself  
contextual information -- but it does complicate things a bit.

I guess I sort of lean toward the latter suggestion I offered.  As I  
describe here, the fact is that there's a good argument for doing it the  
other way.  But I think in the long run, the more reusable technique is  
preferable, even if it does mean that your "engine" winds up a little more  
complicated.

> I guess the 'Gui Component class' should draw its own Graphics2D?

Not only should it, it has to.  That's the only way that the Swing  
component can repaint itself.  And as I mentioned, it will only have that  
Graphics2D long enough to repaint itself once.  When it's done, so is that  
Graphics2D.  You'll get (effectively) a fresh one the next time it needs  
to be repainted.

> [...]
> Thank you for all your help, I really do believe I understand this now  
> thanks to your patience.

You're welcome.  :)

> I think it makes more sense for the 'Gui Component class' to handle its  
> own drawing so providing a method in the 'Gui Component Engine class' to  
> return the AffineTransform is possibly better?

As I mentioned above, I think the other way is marginally more desirable.  
But if you feel differently, I have to say that it's not a terrible choice  
either way.  IMHO, having the Swing component handle all of the drawing  
itself definitely has the edge in simplicity, even if it would require  
more code later on if you want to reuse the "engine" class.

Pete
RichT - 21 Mar 2008 22:43 GMT
Hi Peter :)
Internet online once again

> Sort of.  At the time that you want to adjust how the image is
> displayed, there is no Graphics2D to update.  You only get one of those
[quoted text clipped - 5 lines]
> Graphics2D passed to you when the paintComponent() method is called by
> Java.
I do believe the penny has dropped, must have been the aroma of coffee
or was that Java ;)

>> Which way would you suggest?
>
[quoted text clipped - 4 lines]
> is drawn.  You mentioned scaling, translation, and rotation for
> example.  
True :)
These things can all be defined relative to the image itself,
> independent of wherever it might actually be drawn.
With you so far...

> At the same time, you've also said that the image should be drawn
> centered in the component, which implies a contributor to the
> translation that's relative to the component itself.  This cannot be
> defined relative to the image; it only would make sense in the context
> of a component.
This is the tricky part :) if the engine will do the drawing, then to
centre the image it will require the dimensions of the component it is
drawing the image on to.

> So, on the one hand, it'd be nice to have the "engine" draw itself into
> some arbitrary Graphics2D.  That way if you want to reuse the "engine"
> in a different context, it doesn't require you duplicating a bunch of
> code that gets the properties from the "engine" and uses them to draw
> the image.
True...

> On the other hand, doing it that way means you necessarily have to pass
> _some_ kind of contextual information in addition to the Graphics2D
> instance.  That's not terrible -- after all, the Graphics2D is itself
> contextual information -- but it does complicate things a bit.
When you say contextual are you referring to the dimension of the 'Gui
Component class' object? If so I guess it will be easy enough to store
this info either directly in the 'Gui Component Engine class' object as
fields and have the 'Gui Component class' set the dimensions when it
resizes, or store this in another class which the 'Gui Component class'
can update as it resizes and the 'Gui Component Engine class' can read
when it needs the dimension information of the 'Gui Component class'?

> I guess I sort of lean toward the latter suggestion I offered.  As I
> describe here, the fact is that there's a good argument for doing it the
> other way.  But I think in the long run, the more reusable technique is
> preferable, even if it does mean that your "engine" winds up a little
> more complicated.

Yes I am leaning that way too, I do believe this was my original
intention, which at the time I did not fully understand enough to
realise this :)

> As I mentioned above, I think the other way is marginally more
> desirable.  

I also agree, after reading your explanation it is true that the
centring of the image is a minor complication, but I also understand
that having the 'Gui Component Engine class' handle the drawing
operations will enable better reuse.

But if you feel differently,

I do not :)

IMHO, having the Swing component handle all
> of the drawing itself definitely has the edge in simplicity, even if it
> would require more code later on if you want to reuse the "engine" class.

I guess it is the choice of more work now or more work later, I have
always been taught 'Don't put off till tomorrow what you can do today!' :)

Thanks again for you help :)
Rich
Peter Duniho - 21 Mar 2008 23:21 GMT
> [...]
>>  On the other hand, doing it that way means you necessarily have to  
[quoted text clipped - 4 lines]
> When you say contextual are you referring to the dimension of the 'Gui  
> Component class' object?

Yes.  And any other information that might be required (that's all I'm  
aware of, but you never know what else you might want to add later).

> If so I guess it will be easy enough to store this info either directly  
> in the 'Gui Component Engine class' object as fields and have the 'Gui  
> Component class' set the dimensions when it resizes, or store this in  
> another class which the 'Gui Component class' can update as it resizes  
> and the 'Gui Component Engine class' can read when it needs the  
> dimension information of the 'Gui Component class'?

I think that actually, the easiest thing to do is just pass it when you  
ask the "engine" to draw itself.  You have to pass the component's  
Graphics2D then anyway, since that's the only time you'll have it, so you  
might as well include the other information needed as well.

There's nothing wrong per se with the other options you describe, and  
there are even other alternatives beyond those (for example, implementing  
some sort of "listener" connection between the two classes).  But since  
the "engine" isn't going to need the information except when drawing, why  
add all that overhead?

I have the impression that otherwise you feel you've got a handle on the  
question.  Have fun!  :)

Pete
RichT - 21 Mar 2008 23:39 GMT
> I have the impression that otherwise you feel you've got a handle on the
> question.  Have fun!  :)
>
> Pete

I sure hope so :)
Thanks for everything Peter, you really are a star
Rich
Knute Johnson - 13 Mar 2008 21:26 GMT
> Hello,
>
[quoted text clipped - 19 lines]
> Any help appreciated.
> Rich

See my response in comp.lang.gui.

Signature

Knute Johnson
email s/nospam/linux/



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.