RateIt Widget

Author: Alexei Sokolov 

RateIt widget similar to netflix.com, and amazon.com star ratings. You can use mouse and keyboard (left, right, and number keys) to select rating. 

It can look like this. Note, you need to create images for a single star, not the whole thing.

How to use it:

final RateItWidget rateIt = new RateItWidget(
  3.2/*current rating*/, 5 /*max rating */, 
  whiteStarImg, yellowStarImg, whiteDonutImg, redDonutImg, redStarImg);

rateIt.addChangeListener(new ChangeListener() {
  public void onChange(Widget sender) {
    // Do something here
    // Window.alert("User rating: " + rateIt.getUserRating());
  }
});
yourPanel.add(rateIt);

Or

Image[] ratingImages = new Image[] {
new Image("starfull.gif"), new Image("star10pct.gif"), new Image("star20pct.gif"),
new Image("star30pct.gif"), new Image("star40pct.gif"), new Image("star50pct.gif"),
new Image("star60pct.gif"), new Image("star70pct.gif"), new Image("star80pct.gif"),
new Image("star90pct.gif")
}; 
final RateItWidget rateIt = new RateItWidget(
  3.2 /*current rating*/, 5 /*max rating */, 
  whiteStarImg, yellowStarImg, whiteDonutImg, redDonutImg, ratingImages);

rateIt.addChangeListener(new ChangeListener() {
  public void onChange(Widget sender) {
    // Window.alert("User rating: " + rateIt.getUserRating());
  }
});
yourPanel.add(rateIt);

Please leave your questions or comments here.

Source Code:

RateItWidget.java:

/*
RateIt Widget for GWT
Copyright (C) 2006 Alexei Sokolov http://gwt.components.googlepages.com/

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ 

package com.gwt.components.client;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.ChangeListenerCollection;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.KeyboardListenerAdapter;
import com.google.gwt.user.client.ui.MouseListenerAdapter;
import com.google.gwt.user.client.ui.SourcesChangeEvents;
import com.google.gwt.user.client.ui.Widget;

public class RateItWidget extends Composite implements SourcesChangeEvents {

  private static class RatePanel extends Image {
    private int rating;

    public RatePanel(int rating, Image anotherImage) {
      super(anotherImage.getUrl());
      this.rating = rating;
    }

    public int getRating() {
      return rating;
    }

    public void replaceImage(Image newWidget) {
      this.setUrl(newWidget.getUrl());
    }
  }

  private static class CellMouseListener extends MouseListenerAdapter {
    private RateItWidget rateItWidget;

    public CellMouseListener(RateItWidget rateItWidget) {
      this.rateItWidget = rateItWidget;
    }

    public void onMouseEnter(Widget sender) {
      rateItWidget.drawRating(((RatePanel) sender).getRating());
    }
  }

  private static class CellClickListener implements ClickListener {

    private RateItWidget rateItWidget;

    public CellClickListener(RateItWidget rateItWidget) {
      this.rateItWidget = rateItWidget;
    }

    public void onClick(Widget sender) {
      rateItWidget.setUserRating(((RatePanel) sender).getRating(), true);
    }
  }

  private Grid grid;

  private Image normalImage;
  private Image normalZeroImage;
  private Image ratedImage;
  private Image ratedZeroImage;
  private Image[] ratingImages;

  private int userRating;

  private ChangeListenerCollection changeListeners;

  private boolean rated = false;

  private double rating;

  private CellMouseListener cellMouseListener = new CellMouseListener(this);
  private CellClickListener cellClickListener = new CellClickListener(this);

  public RateItWidget(double rating, int maxRating, Image normalImage,
      Image ratedImage, Image normalZeroImage, Image ratedZeroImage,
      Image ratingImage) {
    this(rating, maxRating, normalImage, ratedImage, normalZeroImage,
      ratedZeroImage, new Image[] { ratingImage });
  }

  public RateItWidget(double rating, int maxRating, Image normalImage,
      Image ratedImage, Image normalZeroImage, Image ratedZeroImage,
      Image[] ratingImages) {
    FocusPanel panel = new FocusPanel();
    panel.addMouseListener(new MouseListenerAdapter() {
      public void onMouseLeave(Widget sender) {
        if (isRated()) {
          drawRating(getUserRating());
        } else {
          setup();
        }
      }
    });
    panel.addKeyboardListener(new KeyboardListenerAdapter() {

      public void onKeyUp(Widget sender, char keyCode, int modifiers) {
        if (keyCode == KeyboardListener.KEY_RIGHT) {
          RateItWidget.this.setUserRating(
            RateItWidget.this.getUserRating() + 1, true);
        } else if (keyCode == KeyboardListener.KEY_LEFT) {
          RateItWidget.this.setUserRating(
            RateItWidget.this.getUserRating() - 1, true);
        } else if (keyCode >= '0' && keyCode <= '9') {
          RateItWidget.this.setUserRating(keyCode - '0', true);
        }
      }
    });
    grid = new Grid(1, maxRating + 1) {
      public boolean clearCell(int row, int column) {
        boolean retValue = super.clearCell(row, column);

        Element td = getCellFormatter().getElement(row, column);
        DOM.setInnerHTML(td, "");
        return retValue;
      }
    };
    grid.setCellSpacing(0);
    grid.setCellPadding(0);
    this.normalImage = normalImage;
    this.ratedImage = ratedImage;
    this.normalZeroImage = normalZeroImage;
    this.ratedZeroImage = ratedZeroImage;
    this.ratingImages = ratingImages;
    this.rating = rating;
    this.userRating = 0;
    setup();
    panel.add(grid);
    setWidget(panel);
    setStyleName("RateItWidget");
  }

  public void setUserRating(int rating) {
    setUserRating(rating, false);
  }

  public int getUserRating() {
    return userRating;
  }

  public boolean isRated() {
    return rated;
  }

  public double getRating() {
    return rating;
  }

  public void setRating(double rating) {
    this.rating = rating;
    if (!isRated()) {
      setup();
    }
  }

  public void addChangeListener(ChangeListener listener) {
    if (changeListeners == null) {
      changeListeners = new ChangeListenerCollection();
    }
    changeListeners.add(listener);
  }

  public void removeChangeListener(ChangeListener listener) {
    if (changeListeners != null) {
      changeListeners.remove(listener);
    }
  }

  protected void setUserRating(int rating, boolean fireEvents) {
    if (rating < 0 || rating >= grid.getColumnCount()) {
      return;
    }
    this.userRating = rating;
    drawRating(userRating);
    if (fireEvents) {
      this.rated = true;
      changeListeners.fireChange(this);
    }
  }

  protected void drawRating(int rating) {
    int colCount = grid.getColumnCount();
    int rateCount = Math.min(rating, colCount);
    if (rateCount == 0) {
      ((RatePanel) grid.getWidget(0, 0)).replaceImage(ratedZeroImage);
    } else {
      ((RatePanel) grid.getWidget(0, 0)).replaceImage(normalZeroImage);
    }
    int i;
    for (i = 1; i <= rateCount; i++) {
      ((RatePanel) grid.getWidget(0, i)).replaceImage(ratedImage);
    }
    for (; i < colCount; i++) {
      ((RatePanel) grid.getWidget(0, i)).replaceImage(normalImage);
    }
  }

  protected void setup() {
    final int colCount = grid.getColumnCount();
    boolean ratingImages10 = ratingImages != null && ratingImages.length == 10;
    Image ratingImage = (ratingImages != null && ratingImages.length > 0) ?
      ratingImages[0] : normalImage;
    for (int i = 0; i < colCount; i++) {
      Image img;
      if (i == 0) {
        img = normalZeroImage;
      } else if (i <= rating) {
        img = ratingImage;
      } else if (ratingImages10 && i < rating + 1) {
        int f = (int) ((rating - i + 1) * 10);
        if (f > 0) {
          img = ratingImages[f];
        } else {
          img = normalImage;
        }
      } else {
        img = normalImage;
      }
      final RatePanel panel = new RatePanel(i, img);
      panel.addMouseListener(cellMouseListener);
      panel.addClickListener(cellClickListener);
      grid.setWidget(0, i, panel);
    }
  }
}

RateItWidget.css:

.RateItWidget {
  cursor: pointer;
}

.RateItWidget img {
  width: 15px; 
  height: 15px;
}