📄 progressbarui.java
字号:
package com.digitprop.tonic;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.*;
import javax.swing.plaf.basic.*;
/** UI delegate for JProgressBars.
*
* @author Markus Fischer
*
* <p>This software is under the <a href="http://www.gnu.org/copyleft/lesser.html" target="_blank">GNU Lesser General Public License</a>
*/
/*
* ------------------------------------------------------------------------
* Copyright (C) 2004 Markus Fischer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* 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., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* You can contact the author at:
* Markus Fischer
* www.digitprop.com
* info@digitprop.com
* ------------------------------------------------------------------------
*/
public class ProgressBarUI extends BasicProgressBarUI
{
private static final Dimension PREFERRED_INNER_HORIZONTAL=new Dimension(146,
12);
private static final Dimension PREFERRED_INNER_VERTICAL=new Dimension(12, 146);
//performance stuff
private static boolean ADJUSTTIMER=true; //makes a BIG difference;
//make this false for
//performance tests
//debugging; PENDING (kwalrath): convert to logging API
private static boolean DEBUGALL=false; //severe performance impact
private static boolean DEBUGTIMER=false; //severe performance impact
private static boolean BASICDEBUG=false;
//performance data collection
private static boolean LOGSTATS=false;
private int cachedPercent;
private int cellLength;
private int cellSpacing;
// The "selectionForeground" is the color of the text when it is painted
// over a filled area of the progress bar. The "selectionBackground"
// is for the text over the unfilled progress bar area.
private Color selectionForeground;
// The "selectionForeground" is the color of the text when it is painted
// over a filled area of the progress bar. The "selectionBackground"
// is for the text over the unfilled progress bar area.
private Color selectionBackground;
private boolean isIndeterminate=false;
private Animator animator;
private PropertyChangeListener propertyListener;
protected JProgressBar progressBar;
protected ChangeListener changeListener;
/**
* The current state of the indeterminate animation's cycle.
* 0, the initial value, means paint the first frame.
* When the progress bar is indeterminate and showing,
* the default animation thread updates this variable
* by invoking incrementAnimationIndex()
* every repaintInterval milliseconds.
*/
private int animationIndex=0;
/**
* The number of frames per cycle. Under the default implementation,
* this depends on the cycleTime and repaintInterval. It
* must be an even number for the default painting algorithm. This
* value is set in the initIndeterminateValues method.
*/
private int numFrames; //0 1|numFrames-1 ... numFrames/2
/**
* Interval (in ms) between repaints of the indeterminate progress bar.
* The value of this method is set
* (every time the progress bar changes to indeterminate mode)
* using the
* "ProgressBar.repaintInterval" key in the defaults table.
*/
private int repaintInterval;
/**
* The number of milliseconds until the animation cycle repeats.
* The value of this method is set
* (every time the progress bar changes to indeterminate mode)
* using the
* "ProgressBar.cycleTime" key in the defaults table.
*/
private int cycleTime; //must be repaintInterval*2*aPositiveInteger
private long startTime=0;
private long lastLoopTime=0;
private int numLoops=0;
/**
* Used to hold the location and size of the bouncing box (returned
* by getBox) to be painted.
*/
private Rectangle boxRect;
/**
* The rectangle to be updated the next time the
* animation thread calls repaint. For bouncing-box
* animation this rect should include the union of
* the currently displayed box (which needs to be erased)
* and the box to be displayed next.
* This rectangle's values are set in
* the setAnimationIndex method.
*/
private Rectangle nextPaintRect;
//cache
/** The component's painting area, not including the border. */
private Rectangle componentInnards; //the current painting area
private Rectangle oldComponentInnards; //used to see if the size changed
/** For bouncing-box animation, the change in position per frame. */
private double delta=0.0;
private int maxPosition=0; //maximum X (horiz) or Y box location
/** Creates and returns a UI delegate for the specified component */
public static ComponentUI createUI(JComponent component)
{
return new ProgressBarUI();
}
/** Installs the UI settings for the specified component */
public void installUI(JComponent c)
{
progressBar=(JProgressBar)c;
installDefaults();
installListeners();
}
/** Uninstalls the UI settings for the specified component */
public void uninstallUI(JComponent c)
{
uninstallDefaults();
uninstallListeners();
stopAnimationTimer();
progressBar=null;
}
protected void installDefaults()
{
progressBar.setOpaque(true);
LookAndFeel.installBorder(progressBar, "ProgressBar.border");
LookAndFeel.installColorsAndFont(progressBar, "ProgressBar.background",
"ProgressBar.foreground",
"ProgressBar.font");
cellLength=UIManager.getInt("ProgressBar.cellLength");
cellSpacing=UIManager.getInt("ProgressBar.cellSpacing");
selectionForeground=UIManager.getColor("ProgressBar.selectionForeground");
selectionBackground=UIManager.getColor("ProgressBar.selectionBackground");
}
protected void uninstallDefaults()
{
LookAndFeel.uninstallBorder(progressBar);
}
protected void installListeners()
{
//Listen for changes in the progress bar's data.
changeListener=new ChangeHandler();
progressBar.addChangeListener(changeListener);
//Listen for changes between determinate and indeterminate state.
propertyListener=new PropertyChangeHandler();
progressBar.addPropertyChangeListener(propertyListener);
}
/**
* Starts the animation thread, creating and initializing
* it if necessary. This method is invoked when
* the progress bar changes to indeterminate mode.
* If you implement your own animation thread,
* you must override this method.
*
* @since 1.4
*/
protected void startAnimationTimer()
{
if(animator==null)
{
animator=new Animator();
}
animator.start(getRepaintInterval());
}
/**
* Stops the animation thread. This method is invoked when
* the progress bar changes from
* indeterminate to determinate mode
* and when this UI is uninstalled.
* If you implement your own animation thread,
* you must override this method.
*
* @since 1.4
*/
protected void stopAnimationTimer()
{
if(animator!=null)
{
animator.stop();
}
}
/**
* Removes all listeners installed by this object.
*/
protected void uninstallListeners()
{
progressBar.removeChangeListener(changeListener);
progressBar.removePropertyChangeListener(propertyListener);
}
// Many of the Basic*UI components have the following methods.
// This component does not have these methods because *ProgressBarUI
// is not a compound component and does not accept input.
//
// protected void installComponents()
// protected void uninstallComponents()
// protected void installKeyboardActions()
// protected void uninstallKeyboardActions()
protected Dimension getPreferredInnerHorizontal()
{
return PREFERRED_INNER_HORIZONTAL;
}
protected Dimension getPreferredInnerVertical()
{
return PREFERRED_INNER_VERTICAL;
}
/**
* The "selectionForeground" is the color of the text when it is painted
* over a filled area of the progress bar.
*/
protected Color getSelectionForeground()
{
return selectionForeground;
}
/**
* The "selectionBackground" is the color of the text when it is painted
* over an unfilled area of the progress bar.
*/
protected Color getSelectionBackground()
{
return selectionBackground;
}
private int getCachedPercent()
{
return cachedPercent;
}
private void setCachedPercent(int cachedPercent)
{
this.cachedPercent=cachedPercent;
}
/**
* Returns the width (if HORIZONTAL) or height (if VERTICAL)
* of each of the indivdual cells/units to be rendered in the
* progress bar. However, for text rendering simplification and
* aesthetic considerations, this function will return 1 when
* the progress string is being rendered.
*
* @return the value representing the spacing between cells
* @see #setCellLength
* @see JProgressBar#isStringPainted
*/
protected int getCellLength()
{
if(progressBar.isStringPainted())
{
return 1;
}
else
{
return cellLength;
}
}
protected void setCellLength(int cellLen)
{
this.cellLength=cellLen;
}
/**
* Returns the spacing between each of the cells/units in the
* progress bar. However, for text rendering simplification and
* aesthetic considerations, this function will return 0 when
* the progress string is being rendered.
*
* @return the value representing the spacing between cells
* @see #setCellSpacing
* @see JProgressBar#isStringPainted
*/
protected int getCellSpacing()
{
if(progressBar.isStringPainted())
{
return 0;
}
else
{
return cellSpacing;
}
}
protected void setCellSpacing(int cellSpace)
{
this.cellSpacing=cellSpace;
}
/**
* This determines the amount of the progress bar that should be filled
* based on the percent done gathered from the model. This is a common
* operation so it was abstracted out. It assumes that your progress bar
* is linear. That is, if you are making a circular progress indicator,
* you will want to override this method.
*/
protected int getAmountFull(Insets b, int width, int height)
{
int amountFull=0;
BoundedRangeModel model=progressBar.getModel();
if((model.getMaximum()-model.getMinimum())!=0)
{
if(progressBar.getOrientation()==JProgressBar.HORIZONTAL)
{
amountFull=(int)Math.round(width*progressBar.getPercentComplete());
}
else
{
amountFull=(int)Math.round(height*progressBar.getPercentComplete());
}
}
return amountFull;
}
/** Paints the specified component */
public void paint(Graphics g, JComponent c)
{
if(isIndeterminate)
{
paintIndeterminate(g, c);
}
else
{
paintDeterminate(g, c);
}
}
/**
* Stores the position and size of
* the bouncing box that would be painted for the current animation index
* in <code>r</code> and returns <code>r</code>.
* Subclasses that add to the painting performed
* in this class's implementation of <code>paintIndeterminate</code> --
* to draw an outline around the bouncing box, for example --
* can use this method to get the location of the bouncing
* box that was just painted.
* By overriding this method,
* you have complete control over the size and position
* of the bouncing box,
* without having to reimplement <code>paintIndeterminate</code>.
*
* @param r the Rectangle instance to be modified;
* may be <code>null</code>
* @return <code>null</code> if no box should be drawn;
* otherwise, returns the passed-in rectangle
* (if non-null)
* or a new rectangle
*
* @see #setAnimationIndex
* @since 1.4
*/
protected Rectangle getBox(Rectangle r)
{
int currentFrame=getAnimationIndex();
int middleFrame=numFrames/2;
if(DEBUGALL)
{
System.out.println("----begin getBox----");
System.out.println(" getBox argument: "+r);
System.out.println(" currentFrame = "+currentFrame);
System.out.println(" middleFrame = "+middleFrame);
}
if(sizeChanged() || delta==0.0 || maxPosition==0.0)
{
updateSizes();
}
r=getGenericBox(r);
if(r==null)
{
if(DEBUGALL)
{
System.out.println(" Exiting because r is null");
}
return null;
}
if(middleFrame<=0)
{
if(DEBUGALL)
{
System.out.println(" Exiting because middleFrame <= 0.");
}
return null;
}
//assert currentFrame >= 0 && currentFrame < numFrames
if(progressBar.getOrientation()==JProgressBar.HORIZONTAL)
{
if(currentFrame<middleFrame)
{
r.x=componentInnards.x+(int)Math.round(delta*(double)currentFrame);
}
else
{
r.x=maxPosition-(int)Math.round(delta*(currentFrame-middleFrame));
}
}
else
{ //VERTICAL indeterminate progress bar
if(currentFrame<middleFrame)
{
r.y=componentInnards.y+(int)Math.round(delta*currentFrame);
}
else
{
r.y=maxPosition-(int)Math.round(delta*(currentFrame-middleFrame));
}
}
if(DEBUGALL)
{
System.out.println(" getBox return value: "+r);
System.out.println("----end getBox----");
}
return r;
}
/**
* Updates delta, max position.
* Assumes componentInnards is correct (e.g. call after sizeChanged()).
*/
private void updateSizes()
{
if(DEBUGALL)
{
System.out.println("----begin updateSizes----");
}
int length=0;
if(progressBar.getOrientation()==JProgressBar.HORIZONTAL)
{
length=getBoxLength(componentInnards.width, componentInnards.height);
maxPosition=componentInnards.x+componentInnards.width-length;
}
else
{ //VERTICAL progress bar
length=getBoxLength(componentInnards.height, componentInnards.width);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -