📄 progressbar.java
字号:
package org.j4me.ui.components;
import java.util.*;
import javax.microedition.lcdui.*;
import org.j4me.ui.*;
import org.j4me.util.*;
/**
* Displays a progress bar that indicates the state of a background
* process.
* <p>
* Progress bars come in two flavors. There is the standard progress
* bar which appears as a rectangle that fills from left-to-right as
* progress toward some known point occurs. There is also a spinner
* which is animated to show constant progress and is useful when it
* is unknown how long the operation will last. These are differentiated
* by <code>setMaxSize</code>; when 0 it is a spinner and when positive it
* is a progress bar.
*/
public class ProgressBar
extends Component
{
/**
* The millseconds between frames in the spinner animation. The
* number of frames for one complete spin is 12, one for each hour
* on the clock.
*/
private static final int ANIMATION_INTERVAL = 2000 / 12;
/**
* The percentage of the screen's width that a progress bar is.
*/
private static final double SCALE_WIDTH = 1.00; // 100%
/**
* The number of times the default font height that the progress bar
* should be.
*/
private static final double SCALE_HEIGHT = 2.0;
/**
* The label that appears right above the progress bar. For example it might
* say "Downloaded 567 of 10235 bytes". If this is <code>null</code> then no
* label will appear.
*/
private Label label;
/**
* The amount of the operation represented by this progress bar that
* has been completed. It should be between 0 and <code>max</code>.
*/
private int value;
/**
* The total amount the operation represented by this progress bar is
* working toward. When <code>current</code> equals <code>max</code> the progress
* bar will be full.
* <p>
* If this is 0, the component will draw itself as a spinner component
* because it doesn't know how long the operation will last.
*/
private int max;
/**
* One less than the current hour pointed to by the spinner component.
* As the spinner rotates, this is the leading edge (i.e. fully colored).
* It goes between 0-11 so the actual hour is 1 greater.
*/
private int spinnerHour;
/**
* A timer that triggers animation events every
* <code>ANIMATION_INTERVAL</code> milliseconds when this component is
* visible.
*/
private Timer timer;
/**
* Creates a progress bar component.
*/
public ProgressBar ()
{
}
/**
* @return The text that appears above the progess bar. If
* <code>null</code> there is no text.
*/
public String getLabel ()
{
if ( label == null )
{
return null;
}
else
{
return label.getLabel();
}
}
/**
* @param label is the text that appears above the progress bar.
* If <code>null</code> there will be no text.
*/
public void setLabel (String label)
{
if ( label == null )
{
this.label = null;
}
else
{
if ( this.label == null )
{
this.label = new Label();
}
this.label.setLabel( label );
}
}
/**
* @return The amount of completed progess.
*/
public int getValue ()
{
return value;
}
/**
* Sets the maximum amount of progress. If this is 0, the
* total progress is unknown and this component will be represented
* by a spinner animation.
*
* @param value is the amount of completed progess.
*/
public void setValue (int value)
{
if ( value < 0 )
{
this.value = 0;
}
else if ( value > max )
{
this.value = max;
}
else
{
this.value = value;
}
}
/**
* Returns the maximum amount of progress. If this is 0, the
* total progress is unknown and this component will be represented
* by a spinner animation.
*
* @return The maximum amount of progress.
*/
public int getMaxValue ()
{
return max;
}
/**
* @param max is the maximum amount of progress.
*/
public void setMaxValue (int max)
{
// Set the max.
if ( max < 0 )
{
this.max = 0;
}
else
{
// Stop the animation timer in case it was running.
stopTimer();
this.max = max;
}
// Make sure the current value isn't more than the new max.
if ( this.max < value )
{
value = this.max;
}
}
/**
* Paints the progress bar.
*
* @param g is the <code>Graphics</code> object to be used for rendering the item.
* @param theme is the application's theme. Use it to get fonts and colors.
* @param width is the width, in pixels, to paint the component.
* @param height is the height, in pixels, to paint the component.
* @param selected is <code>true</code> when this components is currently selected
* and <code>false</code> when it is not.
*
* @see org.j4me.ui.components.Component#paintComponent(Graphics, Theme, int, int, boolean)
*/
protected void paintComponent (Graphics g, Theme theme, int width, int height, boolean selected)
{
int y = 0;
// Paint the label above this component.
if ( label != null )
{
// Make the justification the same as for this component.
label.setHorizontalAlignment( this.getHorizontalAlignment() );
// Paint the label.
label.paint( g, theme, getScreen(), 0, 0, width, height, selected );
// The top of the progress bar is below the label.
int labelHeight = label.getHeight();
y = labelHeight;
height -= labelHeight;
}
if ( max == 0 )
{
startTimer();
paintSpinner( g, theme, 0, y, width, height, selected );
}
else
{
paintBar( g, theme, 0, y, width, height, selected );
}
}
/**
* Paints a progress bar that shows an operation with a known duration.
* The bar fills in left-to-right as progress occurs. The portion on the
* left indicating completed progress will take up <code>getCurrent / getMax</code>
* percent of the progress bar.
*
* @param g is the <code>Graphics</code> object to be used for rendering the item.
* @param theme is the application's theme. Use it to get fonts and colors.
* @param x is the left side of the component.
* @param y is the top side of the component.
* @param width is the width, in pixels, to paint the component.
* @param height is the height, in pixels, to paint the component.
* @param selected is <code>true</code> when this components is currently selected
* and <code>false</code> when it is not.
*/
protected void paintBar (Graphics g, Theme theme, int x, int y, int width, int height, boolean selected)
{
// Calculate the completed progress.
double percentageCompleted = (double)value / (double)max;
int completedWidth = (int)MathFunc.round( width * percentageCompleted );
// Paint the completed portion of the progress bar.
int complete = theme.getBorderColor();
int highlight = theme.getHighlightColor();
Theme.gradientFill( g, x, y, completedWidth, height, true, complete, highlight, 0.50 );
// Paint the uncompleted portion of the progress bar.
int incomplete = theme.getBackgroundColor();
g.setColor( incomplete );
g.fillRect( x + completedWidth, y, x + width - completedWidth, height );
// Paint a border around the progress bar.
int border = theme.getBorderColor();
g.setColor( border );
g.drawRect( x, y, width - 1, height - 1 );
}
/**
* Paints a spinner component used to show progress during an operation
* of an unknown duration.
*
* @param g is the <code>Graphics</code> object to be used for rendering the item.
* @param theme is the application's theme. Use it to get fonts and colors.
* @param x is the left side of the component.
* @param y is the top side of the component.
* @param width is the width, in pixels, to paint the component.
* @param height is the height, in pixels, to paint the component.
* @param selected is <code>true</code> when this components is currently selected
* and <code>false</code> when it is not.
*/
protected void paintSpinner (Graphics g, Theme theme, int x, int y, int width, int height, boolean selected)
{
// The component is square so get the size of a side.
int side = Math.min( width, height );
// Get the diameter of a circle that makes up the spinner.
int diameter = side / 6;
int radius = diameter / 2;
// The centers of all the circles are on the hour hands of a clock.
double toCenter = side / 3;
int temp = (side / 2) - radius;
int left = x + temp;
int top = y + temp;
// Adjust for the horizontal alignment.
int horizontalAlignment = getHorizontalAlignment();
if ( horizontalAlignment == Graphics.HCENTER )
{
left += (width - side) / 2;
}
else if ( horizontalAlignment == Graphics.RIGHT )
{
left += (width - side);
}
// The color of this circle is between the background and primary
// component color. (spinnerHour + 1) is at full color while one
// more is at the background color. This gives the illusion of
// it moving clockwise.
int background = theme.getBackgroundColor();
int foreground = theme.getBorderColor();
int redStart = (background & 0x00FF0000) >> 16;
int greenStart = (background & 0x0000FF00) >> 8;
int blueStart = (background & 0x000000FF);
int redDelta = (foreground & 0x00FF0000) >> 16;
int greenDelta = (foreground & 0x0000FF00) >> 8;
int blueDelta = (foreground & 0x000000FF);
redDelta = (redDelta - redStart) / 12;
greenDelta = (greenDelta - greenStart) / 12;
blueDelta = (blueDelta - blueStart) / 12;
// Draw each circle.
for ( int hour = 1; hour <= 12; hour++ )
{
// Each hour hand on a clock is spaced 30 degrees apart (360 degrees / 12 hours).
// They fall onto a 30-60-90 degree triangle.
// Calculate the center of this circle.
int angle = ((hour - 3) * -30 + 360) % 360; // 3 o'clock = 0 degrees, 12 = 90 degrees
double radians = Math.toRadians( angle );
int cx = (int)MathFunc.round( Math.cos(radians) * toCenter );
int cy = (int)MathFunc.round( Math.sin(radians) * toCenter ) * -1; // Y-coordinates flipped on screen
// Draw a circle for this spoke on the spinner.
int offset = ((hour - spinnerHour) + 12) % 12;
int red = redStart + (offset * redDelta);
int green = greenStart + (offset * greenDelta);
int blue = blueStart + (offset * blueDelta);
g.setColor( red, green, blue );
g.fillRoundRect( left + cx, top + cy,
diameter, diameter, diameter, diameter );
}
}
/**
* Returns the dimensions of the progress bar.
*
* @see org.j4me.ui.components.Component#getPreferredComponentSize(org.j4me.ui.Theme, int, int)
*/
protected int[] getPreferredComponentSize (Theme theme, int viewportWidth, int viewportHeight)
{
int width = (int)( viewportWidth * SCALE_WIDTH );
int fontHeight = theme.getFont().getHeight();
int height = (int)( fontHeight * SCALE_HEIGHT );
if ( max == 0 )
{
// Make sure height of spinners is divisible by 6.
height += (height % 6);
}
// Add the height of the label above the component.
if ( label != null )
{
int[] labelDimensions = label.getPreferredComponentSize( theme, viewportWidth, viewportHeight );
height += labelDimensions[1];
}
return new int[] { width, height };
}
/**
* Starts the animation timer for this spinner.
*/
private void startTimer ()
{
if ( timer == null )
{
timer = new Timer();
timer.schedule( new SpinnerTask(), 0, ANIMATION_INTERVAL );
}
}
/**
* Stops the animation timer for this spinner.
*/
private void stopTimer ()
{
if ( timer != null )
{
timer.cancel();
timer = null;
}
}
/**
* An event raised whenever the component is made visible on the screen.
* This is called before the <code>paintComponent</code> method.
*
* @see Component#showNotify()
*/
protected void showNotify ()
{
// Pass the event to contained components.
if ( label != null )
{
label.show( true );
}
// Continue processing the event.
super.showNotify();
}
/**
* An event raised whenever the component is removed from the screen.
*
* @see Component#hideNotify()
*/
protected void hideNotify ()
{
// Pass the event to contained components.
if ( label != null )
{
label.show( false );
}
// If this is a spinner, stop it.
stopTimer();
// Continue processing the event.
super.hideNotify();
}
/**
* A task executed at regularly scheduled intervals that forces
* the spinner animation to advance to the next frame.
*/
private final class SpinnerTask
extends TimerTask
{
public void run ()
{
// Increment the position of the lead spoke.
spinnerHour = (spinnerHour + 1) % 12;
// Repaint the spinner.
ProgressBar.this.repaint();
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -