This discussion is archived
1 2 3 Previous Next 38 Replies Latest reply: Oct 27, 2010 4:22 AM by 801338 RSS

conversion from awt to Swing, colored list widget, and awt update() method

801338 Newbie
Currently Being Moderated
Now that my Interactive Color Wheel program/applet is in Swing, I guess I should continue my previous thread in here from the AWT forum ("list widget with different colors for each list item?"):

* list widget with different colors for each list item?

My current issue involves two canvas (well, JPanel) refresh issues likely linked to double buffering. You can see them by running the following file with "java -jar SIHwheel.jar":

* http://r0k.us/rock/Junk/SIHwheel.jar

[edit add]
(Heh, I just noticed Firefox and Chrome under Windows 7 will allow you to run thie .jar directly from the link. Cool.)
[edit]

If you don't trust me and would rather run it as an applet, use:

* http://r0k.us/rock/Junk/SIHwheel.html

(For some reason the first issue doesn't manifest when running as applet.)

1) The canvas goes "wonky-white" when the user first clicks on the wheel. What is supposed to happen is simply the user sees another dot on the wheel for his new selected color. Forcing a complete redraw via any of the GUI buttons at the bottom sets things right. The canvas behaves itself from then on, at least until minimized or resized, at which point one needs to click a GUI button again. I'll be disabling resizing, but minimizing will still be allowed.

2) A button image, and sometimes toolTip text, from an entirely different JPanel will appear in the ULC (0,0) of my canvas.

Upon first running the new Swing version, I had thought everything was perfect. I soon realized though that my old AWT update() method was never getting called. The desired case when the user clicks somewhere on the wheel is that a new dot appears on his selected color. This usually allows them to see what colors have been viewed before. The old paint(), and now paintComponent(), clear the canvas, erasing all the previous dots.

I soon learned that Swing does not call update(). I had been using it to intercept refresh events where only one of the components on my canvas needing updating. Most usefully, don't redraw the wheel (and forget the dots) when you don't need to. The way I chose to handle this is to slightly modify the update() to a boolean method. I renamed it partialOnly() and call it
at the beginning of paintComponent(). If it returns true, paintComponent() itself returns, and no clearing of the canvas occurs.

Since I first posted about these two issues, I've kludged-in a fix to #1. (The linked .jar file does not contain this kludge, so you can see the issue.) The kludge is included in the following code snippet:
    public void paintComponent(Graphics g)
    {
        Rectangle ulc;

     if (font == null)  defineFont(g);

     // handle partial repaints of specific items
     if (partialOnly(g))  return;

        ...  // follow with the normal, full-canvas refresh
    }

    private boolean partialOnly(Graphics g)
    {
     boolean     imDone = true;
     if (resized > 0)  // this "if { }" clause is my kludge
     {   // should enter on 1 or 2
         imDone = false;
         resized += 1;     // clock thru two forced-full paints
         if (resized > 2)  resized = 0;
     }

        if (wedgeOnly)
        {
         putDotOnWheel(g);
            paintWedge(g);
         drawSnake(g);
         drawSatSnake(g);
         updateLumaBars(g);
            wedgeOnly = false;
        }
          else if (wheelOnly)
          {
            ...
            wheelOnly = false;
          }
          ...
          else
            imDone = false;  // was paint() when method was update() in the AWT version

        return(imDone);
    }
Forcing two initial full paintComponent()s does whatever magic the double-buffering infrastructure needs to avoid the "wonky-white" problem. This also happens on a minimize; I've disabled resizing other than minimization. Even though it works, I consider it a kludge.

The second issue is not solved. All I can figure is that the double buffers are shared between the two JPanels, and the artifact buttons and toolTips at (0,0) are the result. I tried simply clearing the top twenty lines of the canvas when partialOnly() returns true, but for some reason that causes other canvas artifacting further down. And that was just a second kludge anyway.

Sorry for being so long-winded. What is the right way to avoid these problems?

-- Rich

Edited by: RichF on Oct 15, 2010 8:43 PM
  • 1. Re: conversion from awt to Swing, colored list widget, and awt update() method
    DarrylBurke Guru Moderator
    Currently Being Moderated
    My current issue involves two canvas (well, JPanel) refresh issues likely linked to double buffering.
    Swing components are double buffered by default. Get rid of any custom double buffering.

    Have you started going through the Swing tutorials? It's time you went through the one on Performing Custom Painting, and it won't be long before you need to better understand Concurrency in Swing.

    db
  • 2. Re: conversion from awt to Swing, colored list widget, and awt update() method
    800025 Explorer
    Currently Being Moderated
    Hi Rich,

    Problem 1: I don't see the effect you describe (or I just don't understand the description)

    Problem 2: I have seen the behavior you describe on one of my own fancy attempts to explore the depths of swing. I never found out why it happened, but it disappeared after some changes. I never found what those changes were exactly. Obviously I was doing something wrong.

    The way you handle partial repaints:

    Are you aware that repaint() can have a rectangle argument? And are you aware that the Graphics object has a clip depicting the area that will be affected by painting? You might use these for your partial painting.

    In general, I don't think it is a good idea to not completely paint the clip area, in order to leave the results from previous paintings untouched. In contrast, you should keep state information that tells you how the requested clip must be painted.

    Remember, you don't know why the paintComponent() method is invoked. Somewhere in the system it is decided that the current painting is not valid any more. It may be you who decided that, but it may as well be something else.

    Piet
  • 3. Re: conversion from awt to Swing, colored list widget, and awt update() method
    801338 Newbie
    Currently Being Moderated
    Darryl, I'm not doing any custom double buffering. My goal was to simply replicate the functionality of awt's update() method. And yes, I have started with the Swing tutorial. I believe it was there that I learned update() is not part of the Swing infrastructure.
    Problem 1: I don't see the effect you describe (or I just don't understand the description)
    Piet, were you viewing the program (via the .jar) or the applet (via the .html)? For whatever reason, problem 1 does not manifest itself as an applet, only a program. FTR I'm running JDK/JRE 1.6 under Windows 7. As a program, just click anywhere in the wheel. The whole canvas goes wonky-white, and the wheel doesn't even show. If it happens, you'll understand. ;)
    Are you aware that repaint() can have a rectangle argument? And are you aware that the Graphics object has a clip depicting the area that will be affected by painting? You might use these for your partial painting.
    Yes and yes. Here is an enumeration of most of the update regions:
    enum AoI    // areas of interest
    {
        LUMA_SNAKE, GREY_SNAKE, HUEBORHOOD, BULB_LABEL, LUMA_WEDGE,
        LAST_COLOR, BRIGHTNESS_BOX, INFO_BOX, VERSION,
        COLOR_NAME, EXACT_COLOR, LUMA_BUTTON, LUMA_BARS, GUI_INTENSITY,
        QUANTIZATION_ERROR
    }
    That list doesn't even include the large color intensity wedge to the right, nor the color wheel itself. I have a method that will return a Rectangle for any of the AoI's. One problem is that the wheel is a circle, and a containing rectangle will overlap with some of the other AoI's. I could build an infrastructure to handle this mess one clip region at a time, but I think it would add a lot of unnecessary complexity.

    I think the bigger picture is that, though it is now updated to Swing, some of the original 1998 design decisions are no longer relevant. Back then I was running Windows 98 on a single-core processor clocked at significantly less than 1 GHz. You could actually watch the canvas update itself. The color wheel alone fills over 1000 arcs, and the color intensity wedge has over 75 update regions of its own. While kind of interesting to watch, it's not 1998 any more. My multi-core processor runs at over 2 GHz, and my graphic card is way, way beyond anything that existed last century. Full canvas updates probably take less than 0.1 sec, and that is with double-buffering!

    So, I think you're right. Let the silly paintComponent() do it's thing unhindered. If I want to track old dots on the wheel, keep an array of Points, remembering maybe the last 10. As a final step in the repainting process, decide how many of those old dots to display, and do it.

    Thanks, guys, for being a sounding board.

    Oh, I'm moving forward on implementing the color list widget. I've already added a 3rd JPanel, which is a column to the left of the main paint canvas. It will contain 3 GUI items:

    1) the color list widget itself, initially sorted by name
    2) 3 radio buttons allowing user to resort the list by name, hue, or hex
    3) a hex-entry JTextField (which is all that is there at this very moment), allowing exact color request

    The color list widget will fill most of the column from the top, followed by the radio buttons, with hex-entry at bottom.

    For weeks I had in mind that I wanted a pop-up color list widget. Then you shared your ColorList class, and it was so obvious the list should just be there all the time. :)

    -- Rich
  • 4. Re: conversion from awt to Swing, colored list widget, and awt update() method
    800025 Explorer
    Currently Being Moderated
    RichF wrote:
    Problem 1: I don't see the effect you describe (or I just don't understand the description)
    Piet, were you viewing the program (via the .jar) or the applet (via the .html)? For whatever reason, problem 1 does not manifest itself as an applet, only a program. FTR I'm running JDK/JRE 1.6 under Windows 7. As a program, just click anywhere in the wheel. The whole canvas goes wonky-white, and the wheel doesn't even show. If it happens, you'll understand. ;)
    I ran the jar file and did not see the effect. Windows XP and java 1.6 update 21
    So, I think you're right. Let the silly paintComponent() do it's thing unhindered. If I want to track old dots on the wheel, keep an array of Points, remembering maybe the last 10. As a final step in the repainting process, decide how many of those old dots to display, and do it.
    Good decision :-)

    Piet
  • 5. Re: conversion from awt to Swing, colored list widget, and awt update() method
    801338 Newbie
    Currently Being Moderated
    I ran the jar file and did not see the effect. Windows XP and java 1.6 update 21
    Hmm, I wonder if Java takes advantage of hardware double buffering on one's graphic board? If so, that would explain the difference. FTR I have an ATI Radeon HD-5700 series board with a GByte of its own memory.

    My CPU is a 2.6 GHz ATI Phenom II X6 1035T. I.e, it's fast and has 5 cores, and 8 GBytes RAM to boot. This likely puts it at least in the top 20% of current computers. But even most those folks who have computers ranking in the bottom 5% are ahead of where I was in 1998. (At 2 years per computer generation, that's 6 generations of computer power!)

    PS: how the heck do you quote in these forums? Obviously
    this
    does not work.
  • 6. Re: conversion from awt to Swing, colored list widget, and awt update() method
    801338 Newbie
    Currently Being Moderated
    Not that it matters any more, but:

    * http://r0k.us/rock/junk/wonkyWhite.png
  • 7. Re: conversion from awt to Swing, colored list widget, and awt update() method
    800025 Explorer
    Currently Being Moderated
    RichF wrote:
    PS: how the heck do you quote in these forums? Obviously
    this
    does not work.
    I click the quote button above

    And no, I didn't see anything like the picture in your last post.

    Piet
  • 8. Re: conversion from awt to Swing, colored list widget, and awt update() method
    801338 Newbie
    Currently Being Moderated
    Sorry to get this thread off track, but I must be officially blind and/or stupid. Here is an image of Piet's last post:

    * http://r0k.us/rock/junk/pietPost.png

    Where is the "quote button"? Neither the "Reply" text link, nor the icon link immediately to its left causes any quoting. They both bring up the same page with an empty reply pane.

    In the event that I'm not blind, and for some reason I'm not actually getting a quote button, what appears in the text pane to indicate a quoted passage? On most fora, you use the BBCode markup, . I'm assuming there must be something similar here.
  • 9. Re: conversion from awt to Swing, colored list widget, and awt update() method
    DarrylBurke Guru Moderator
    Currently Being Moderated
    <li> The quote button looks like this:
    <font face="Arial" size=6>&rdquo;</font>
    <li> Other formatting codes are listed in the FAQ.

    db
  • 10. Re: conversion from awt to Swing, colored list widget, and awt update() method
    801338 Newbie
    Currently Being Moderated
    Other forms are listed in the FAQ
    Ok! I plead stupid for not reading the FAQ. Use curly braces instead of square brackets, and the closing quote does not begin with slash. Got it, thanks! :) (Strange that square brackets work fine for the code /code markup, though.)

    And twice stupid for not realizing the quote button was not on the thread page, but on the post page. Here I don't feel quite so bad. On every other forum I've used, you enter the reply page via a quote link or button. It never occurred to me to look for it once I was already replying.
  • 11. Re: conversion from awt to Swing, colored list widget, and awt update() method
    801338 Newbie
    Currently Being Moderated
    Now that I've added the third JPanel, I am having trouble achieving my desired layout:
    L = colorList pane, c = paint canvas, G = primary GUI
    
            LLLccccccccc            LLLccccccccc
            LLLccccccccc            LLLccccccccc
            LLLccccccccc            LLLccccccccc
            LLLccccccccc            LLLccccccccc
    want:   LLLccccccccc    get:    LLLccccccccc
            LLLccccccccc            LLLccccccccc
            LLLccccccccc            LLLccccccccc
            LLLGGGGGGGGG            GGGGGGGGGGGG
            LLLGGGGGGGGG            GGGGGGGGGGGG
    The problem is in the lower left corner. I want the primary GUI items to center themselves beneath the paint canvas, as they always have. The colorList pane begins at the top with a long list widget, followed by 3 radio buttons, followed by a hex text-entry field. I'd like the text-entry to be at the bottom, directly to the left of the pre-existing GUI items. I've read the Swing tutorial on BorderLayout, but to this point I have only been able to achieve either the second layout shown above, or each JPanel in its own row.

    Here is my layout code:
    public class SIHwheel extends JApplet
    {
        public static SIHControls controls;
        public static SIHListPane colorList;
        public static SIHCanvas paintingCanvas;
    
        public void init()
        {
         paintingCanvas = new SIHCanvas(640, 640);
         setLayout(new BorderLayout());
            add(colorList = new SIHListPane(paintingCanvas), BorderLayout.WEST);
            add(controls = new SIHControls(paintingCanvas), BorderLayout.SOUTH);
            add(paintingCanvas, BorderLayout.CENTER);
    
         ntc.init();     // initialize name-that-color class
        }
    I've tried myriad permutations of order, as well as BorderLayout.EAST for paintingCanvas. I've also messed with the BorderLayout.PAGE_START type specifications. It doesn't seem to want to give me a west pane that spans the full height of the frame. Is there a way?
  • 12. Re: conversion from awt to Swing, colored list widget, and awt update() method
    801338 Newbie
    Currently Being Moderated
    Got it. Wheels within wheels:
    public class SIHwheel extends JApplet
    {
        public static SIHControls controls;
        public static SIHListPane colorList;
        public static SIHCanvas paintingCanvas;
        public static SIHGrouper grouper;
    
        public void init()
        {
         paintingCanvas = new SIHCanvas(640, 640);
         controls = new SIHControls(paintingCanvas);
         colorList = new SIHListPane(paintingCanvas);
         grouper = new SIHGrouper(paintingCanvas, controls);
    
         setLayout(new BorderLayout());
         add(colorList, BorderLayout.WEST);
         add(grouper, BorderLayout.EAST);
    
         ntc.init();     // initialize name-that-color class
        }
        ...
    }
    
    // a grouping class to allow colorList to span full west side of frame
    class SIHGrouper extends JPanel
    {
        public SIHGrouper(SIHCanvas canvas, SIHControls controls)
        {
         setLayout(new BorderLayout());
            add(canvas, BorderLayout.NORTH);
            add(controls, BorderLayout.SOUTH);
        }
    }
    Is there a more elegant way? The above works, but it seems somewhat tortured.
  • 13. Re: conversion from awt to Swing, colored list widget, and awt update() method
    801338 Newbie
    Currently Being Moderated
    ... and, what was probably obvious to most of you. Much cleaner nesting:
    public class SIHwheel extends JApplet
    {
        public  static SIHControls controls;
        public  static SIHListPane colorList;
        public  static SIHCanvas paintingCanvas;
    
        public void init()
        {
            paintingCanvas = new SIHCanvas(640, 640);
            controls = new SIHControls(paintingCanvas);
            colorList = new SIHListPane(paintingCanvas);
    
            // grouper allows colorList to span entire west of frame
            JPanel grouper = new JPanel(new BorderLayout());
            grouper.add(paintingCanvas, BorderLayout.NORTH);
            grouper.add(controls, BorderLayout.SOUTH);
    
            setLayout(new BorderLayout());
            add(colorList, BorderLayout.WEST);
            add(grouper, BorderLayout.EAST);
    
            ntc.init();    // initialize name-that-color class
        }
        ...
    }
    I'm slightly worried that the scope of grouper would seem to be within init() only. On the other hand, it's not used by me once the layout has occurred. As far as I'm concerned, it might as well auto-dissolve. Is there any reason to make grouper a class object?

    -- Rich

    Edited by: RichF on Oct 17, 2010 2:57 AM
  • 14. Re: conversion from awt to Swing, colored list widget, and awt update() method
    DarrylBurke Guru Moderator
    Currently Being Moderated
    Is there any reason to make grouper a class object?
    No. Nor is there a reason to make controls, colorList and paintingCanvas static. The only reason to make any field static is in order to share one value across all instances of the class.

    JApplet has a BorderLayout by default, there's no need to set another.

    Also consider building your GUI in a JPanel which can then be added or set as contentPane for an Applet or a top level window such as JFrame or JDialog. That gives you better flexibility. In this case -
    public class SIHwheel extends JApplet {
    
      private SIHControls controls;
      private SIHListPane colorList;
      private SIHCanvas paintingCanvas;
    
      public void init() {
        setContentPane(makeContent());
    
    
        ntc.init();    // initialize name-that-color class
      }
    
      public JPanel makeContent() {
        paintingCanvas = new SIHCanvas(640, 640);
        controls = new SIHControls(paintingCanvas);
        colorList = new SIHListPane(paintingCanvas);
    
        // inner allows colorList to span entire west of frame
        JPanel inner = new JPanel(new BorderLayout());
        inner.add(paintingCanvas, BorderLayout.NORTH);
        inner.add(controls, BorderLayout.SOUTH);
    
        JPanel outer = new JPanel(new BorderLayout());
        outer.add(colorList, BorderLayout.WEST);
        outer.add(inner, BorderLayout.EAST);
    
        return outer;
      }
      
      public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
          
          @Override
          public void run() {
            JFrame frame = new JFrame("Title goes here");
            frame.setContentPane(new SIHwheel().makeContent());
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
          }
        });
      }
    }
    db
1 2 3 Previous Next

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points