正如我之前在评论中所说,我最终决定重写 JSlider 和 MetalSliderUI 类。
至少这与 Java-8 兼容,因为我开始的代码是 oracle JDK-8 的代码。
新类的使用示例代码如下。
新界面:
public interface ZoomInterface
{
public void setZoomFactor( double zoomFactor );
public double getZoomFactor();
}
新的覆盖类:
ZoomMetalSliderUI:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JSlider;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.metal.MetalSliderUI;
/**
*
* @author Francisco Javier Rojas Garrido <frojasg1@hotmail.com>
*/
public class ZoomMetalSliderUI extends MetalSliderUI implements ZoomInterface
{
protected double _zoomFactor = 1.0D;
public ZoomMetalSliderUI()
{
super();
}
@Override
public Dimension getThumbSize()
{
Dimension result = ViewFunctions.instance().getNewDimension( super.getThumbSize(), null, _zoomFactor );
return( result );
}
@Override
public void setZoomFactor(double zoomFactor)
{
_zoomFactor = zoomFactor;
}
@Override
public double getZoomFactor()
{
return( _zoomFactor );
}
@Override
public void paint( Graphics g, JComponent c )
{
calculateGeometry();
super.paint(g, c);
}
@Override
public void paintThumb(Graphics g) {
Rectangle knobBounds = thumbRect;
// g.translate( knobBounds.x, knobBounds.y );
Icon icon = null;
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
icon = horizThumbIcon;
}
else {
icon = vertThumbIcon;
}
BufferedImage bi = new BufferedImage( icon.getIconWidth(), icon.getIconHeight(),
BufferedImage.TYPE_INT_ARGB );
Graphics g1 = bi.getGraphics();
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
horizThumbIcon.paintIcon( slider, bi.getGraphics(), 0, 0 );
}
else {
vertThumbIcon.paintIcon( slider, bi.getGraphics(), 0, 0 );
}
Rectangle tr = new Rectangle( 0, 0, icon.getIconWidth(), icon.getIconHeight() );
Rectangle newRectangle = ViewFunctions.instance().getNewRectangle(tr, null, _zoomFactor );
BufferedImage bi_tx = ImageFunctions.resizeImage(bi, (int)newRectangle.getWidth(),
(int)newRectangle.getHeight(),
null, null, null );
Point center = ViewFunctions.instance().getCenter(knobBounds);
g.drawImage( bi_tx, center.x - newRectangle.width / 2,
center.y - newRectangle.height / 2,
center.x + newRectangle.width / 2,
center.y + newRectangle.height / 2,
0,
0,
bi_tx.getWidth(),
bi_tx.getHeight(),
null );
// g.translate( -knobBounds.x, -knobBounds.y );
}
public void paintTrack(Graphics g) {
/* if (MetalLookAndFeel.usingOcean()) {
oceanPaintTrack(g);
return;
}
*/
Color trackColor = !slider.isEnabled() ? MetalLookAndFeel.getControlShadow() :
slider.getForeground();
// boolean leftToRight = MetalUtils.isLeftToRight(slider);
boolean leftToRight = isLeftToRight(slider);
g.translate( trackRect.x, trackRect.y );
int trackLeft = 0;
int trackTop = 0;
int trackRight;
int trackBottom;
// Draw the track
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
trackBottom = (trackRect.height - 1) - getThumbOverhang();
trackTop = trackBottom - (getTrackWidth() - 1);
trackRight = trackRect.width - 1;
}
else {
if (leftToRight) {
trackLeft = (trackRect.width - getThumbOverhang()) -
getTrackWidth();
trackRight = (trackRect.width - getThumbOverhang()) - 1;
}
else {
trackLeft = getThumbOverhang();
trackRight = getThumbOverhang() + getTrackWidth() - 1;
}
trackBottom = trackRect.height - 1;
}
if ( slider.isEnabled() ) {
g.setColor( MetalLookAndFeel.getControlDarkShadow() );
g.drawRect( trackLeft, trackTop,
(trackRight - trackLeft) - 1, (trackBottom - trackTop) - 1 );
g.setColor( MetalLookAndFeel.getControlHighlight() );
g.drawLine( trackLeft + 1, trackBottom, trackRight, trackBottom );
g.drawLine( trackRight, trackTop + 1, trackRight, trackBottom );
g.setColor( MetalLookAndFeel.getControlShadow() );
g.drawLine( trackLeft + 1, trackTop + 1, trackRight - 2, trackTop + 1 );
g.drawLine( trackLeft + 1, trackTop + 1, trackLeft + 1, trackBottom - 2 );
}
else {
g.setColor( MetalLookAndFeel.getControlShadow() );
g.drawRect( trackLeft, trackTop,
(trackRight - trackLeft) - 1, (trackBottom - trackTop) - 1 );
}
// Draw the fill
if ( filledSlider ) {
int middleOfThumb;
int fillTop;
int fillLeft;
int fillBottom;
int fillRight;
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
middleOfThumb = thumbRect.x + (thumbRect.width / 2);
middleOfThumb -= trackRect.x; // To compensate for the g.translate()
fillTop = !slider.isEnabled() ? trackTop : trackTop + 1;
fillBottom = !slider.isEnabled() ? trackBottom - 1 : trackBottom - 2;
if ( !drawInverted() ) {
fillLeft = !slider.isEnabled() ? trackLeft : trackLeft + 1;
fillRight = middleOfThumb;
}
else {
fillLeft = middleOfThumb;
fillRight = !slider.isEnabled() ? trackRight - 1 : trackRight - 2;
}
}
else {
middleOfThumb = thumbRect.y + (thumbRect.height / 2);
middleOfThumb -= trackRect.y; // To compensate for the g.translate()
fillLeft = !slider.isEnabled() ? trackLeft : trackLeft + 1;
fillRight = !slider.isEnabled() ? trackRight - 1 : trackRight - 2;
if ( !drawInverted() ) {
fillTop = middleOfThumb;
fillBottom = !slider.isEnabled() ? trackBottom - 1 : trackBottom - 2;
}
else {
fillTop = !slider.isEnabled() ? trackTop : trackTop + 1;
fillBottom = middleOfThumb;
}
}
if ( slider.isEnabled() ) {
g.setColor( slider.getBackground() );
g.drawLine( fillLeft, fillTop, fillRight, fillTop );
g.drawLine( fillLeft, fillTop, fillLeft, fillBottom );
g.setColor( MetalLookAndFeel.getControlShadow() );
g.fillRect( fillLeft + 1, fillTop + 1,
fillRight - fillLeft, fillBottom - fillTop );
}
else {
g.setColor( MetalLookAndFeel.getControlShadow() );
g.fillRect(fillLeft, fillTop, fillRight - fillLeft, fillBottom - fillTop);
}
}
g.translate( -trackRect.x, -trackRect.y );
}
static boolean isLeftToRight( Component c ) {
return c.getComponentOrientation().isLeftToRight();
}
}
ZoomJSlider:
import javax.swing.BoundedRangeModel;
import javax.swing.JSlider;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.metal.MetalSliderUI;
/**
*
* @author Francisco Javier Rojas Garrido <frojasg1@hotmail.com>
*/
public class ZoomJSlider extends JSlider implements ZoomInterface
{
protected double _zoomFactor = 1.0D;
public ZoomJSlider() {
super();
}
public ZoomJSlider(int orientation) {
super(orientation);
}
public ZoomJSlider(int min, int max) {
super(min, max);
}
public ZoomJSlider(int min, int max, int value) {
super(min, max, value);
}
public ZoomJSlider(int orientation, int min, int max, int value)
{
super(orientation, min, max, value);
}
public ZoomJSlider(BoundedRangeModel brm)
{
super( brm );
}
public void switchToZoomUI()
{
ComponentUI compUi = getUI();
ComponentUI newUi = null;
if( ( compUi instanceof MetalSliderUI ) &&
!( compUi instanceof ZoomMetalSliderUI ) )
{
newUi = new ZoomMetalSliderUI();
}
if( newUi != null )
{
setUI(newUi);
( (ZoomInterface) newUi ).setZoomFactor(_zoomFactor);
}
}
@Override
public void setZoomFactor( double zoomFactor )
{
_zoomFactor = zoomFactor;
ComponentUI compUi = getUI();
if( compUi instanceof ZoomInterface )
{
ZoomInterface zi = (ZoomInterface) compUi;
zi.setZoomFactor(zoomFactor);
}
repaint();
}
@Override
public double getZoomFactor()
{
return( _zoomFactor );
}
}
主类:
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.metal.MetalLookAndFeel;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* @author Francisco Javier Rojas Garrido <frojasg1@hotmail.com>
*/
public class Main
{
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
javax.swing.UIManager.setLookAndFeel(MetalLookAndFeel.class.getName());
} catch (ClassNotFoundException ex) {
Logger.getLogger(MetalLookAndFeel.class.getName()).log(Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
Logger.getLogger(MetalLookAndFeel.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(MetalLookAndFeel.class.getName()).log(Level.SEVERE, null, ex);
} catch (UnsupportedLookAndFeelException ex) {
Logger.getLogger(MetalLookAndFeel.class.getName()).log(Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
try
{
new Window().setVisible(true);
}
catch( Throwable th )
{
th.printStackTrace();
}
}
});
}
}
窗口类:
导入 java.awt.Component;
导入 java.awt.Dimension;
导入 java.awt.Point;
导入 javax.swing.JFrame;
导入 javax.swing.event.ChangeEvent;
导入 javax.swing.event.ChangeListener;
/*
* 要更改此许可标头,请在项目属性中选择许可标头。
* 要更改此模板文件,请选择工具 |模板
* 并在编辑器中打开模板。
*/
/**
*
* @作者弗朗西斯科·哈维尔·罗哈斯·加里多
*/
公共类 Window 扩展 JFrame 实现 ChangeListener
{
受保护的维度 _dimen = 新维度(250, 30);
受保护的 ZoomJSlider _jSlider = null;
受保护的 javax.swing.JPanel _jPanel1;
公共窗口()
{
极好的( );
初始化组件();
setListeners();
}
受保护的 void initComponents()
{
_jPanel1 = 新 javax.swing.JPanel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
getContentPane().setLayout(null);
_jPanel1.setLayout(null);
_jSlider = 新 ZoomJSlider( 50, 200, 100 );
_jPanel1.add(_jSlider);
_jSlider.switchToZoomUI();
_jSlider.setBounds( 20, 30, (int) _dimen.getWidth(), (int) _dimen.getHeight() );
getContentPane().add(_jPanel1);
_jPanel1.setBounds(0, 0, 600, 120);
设置尺寸(650、170);
setLocation(getCenteredLocationForComponent(this));
}
受保护的无效 setListeners()
{
_jSlider.addChangeListener(这个);
}
@覆盖
公共无效状态更改(更改事件 ce)
{
双缩放因子 = _jSlider.getValue() / 100.0D;
_jSlider.setZoomFactor(zoomFactor);
维度大小 = ViewFunctions.instance().getNewDimension(_dimen, null, zoomFactor);
_jSlider.setBounds(_jSlider.getX(), _jSlider.getY(),
(int) size.getWidth(), (int) size.getHeight());
}
公共静态点getCenteredLocationForComponent(组件comp)
{
int 宽度 = java.awt.Toolkit.getDefaultToolkit().getScreenSize().width;
int height = java.awt.Toolkit.getDefaultToolkit().getScreenSize().height;
点结果 = new Point(width/2 - comp.getWidth()/2, height/2 - comp.getHeight()/2);
返回(结果);
}
}
其他类:
导入 java.awt.image.BufferedImage;
导入 java.awt.image.ColorModel;
导入 java.awt.image.DataBuffer;
导入 java.awt.image.Raster;
/**
*
* @作者乌苏里奥
*/
公共类 ImageFunctions
{
public static BufferedImage resizeImage( BufferedImage original, int width, int height, Integer switchColorFrom,
整数 switchColorTo,整数 alphaForPixelsDifferentFromColorFrom )抛出 IllegalArgumentException
{
整数阿尔法= 0xFF000000;
if( alphaForPixelsDifferentFromColorFrom != null )
alpha = ( (alphaForPixelsDifferentFromColorFrom) & 0xFF ) 颜色模型。只有 8 位精度
* 当返回数据中的每个颜色分量
* 使用这种方法。在指定坐标 (x, y) 中
* 图像,ARGB 像素可以这样访问:
*
*
*
* 像素 = rgbArray[offset + (y-startY)*scansize + (x-startX)];
*
*
*
* 可能会抛出 ArrayOutOfBoundsException
* 如果区域不在范围内。
* 但是,不能保证明确的边界检查。
*
* @param startX 起始X坐标
* @param startY 起始 Y 坐标
* @param w 区域宽度
* @param h 区域高度
* @param rgbArray 如果不是 null,则 rgb 像素为
* 写在这里
* @param offset 偏移到 rgbArray
* @param scansize rgbArray 的扫描线步幅
* @return RGB 像素数组。
* @see #setRGB(int, int, int)
* @see #setRGB(int, int, int, int, int[], int, int)
*/
公共静态int [] getRGB(int startX,int startY,int w,int h,
缓冲图像双)
{
ColorModel colorModel = bi.getColorModel();
光栅 raster = bi.getRaster();
// WritableRaster raster = colorModel.createCompatibleWritableRaster(bi.getWidth(), bi.getHeight() );
int 扫描尺寸 = w;
整数偏移=0;
int yoff = 偏移量;
关闭;
对象数据;
int nbands = raster.getNumBands();
int dataType = raster.getDataBuffer().getDataType();
开关(数据类型)
{
案例 DataBuffer.TYPE_BYTE:
数据=新字节[nbands];
休息;
案例 DataBuffer.TYPE_USHORT:
数据=新的短[nbands];
休息;
案例 DataBuffer.TYPE_INT:
数据 = 新的 int[nbands];
休息;
案例 DataBuffer.TYPE_FLOAT:
数据=新浮动[nbands];
休息;
案例 DataBuffer.TYPE_DOUBLE:
数据=新双[nbands];
休息;
默认:
throw new IllegalArgumentException("未知数据缓冲区类型:"+
数据类型);
}
int[] rgbArray = new int[offset+h*scansize];
for (int y = startY; y =0) && (x=0) && (y
公共类 IntegerFunctions
{
公共静态 int 最大值(int i1,int i2)
{
返回(i1>i2?i1:i2);
}
公共静态int min(int i1,int i2)
{
返回( i1=0 ? ii : -ii );
}
公共静态 int sgn( int ii )
{
返回( ii>0 ? 1 : ( ii
导入 java.awt.Dimension;
导入 java.awt.Insets;
导入 java.awt.Point;
导入 java.awt.Rectangle;
/**
*
* @作者乌苏里奥
*/
公共类 ViewFunctions
{
受保护的静态 ViewFunctions _instance;
公共静态 ViewFunctions 实例()
{
如果(_instance == null)
_instance = new ViewFunctions();
返回(_instance);
}
public Dimension getNewDimension( Dimension dim, Insets insets, double zoomFactor )
{
维度结果 = null;
如果(暗淡!=空)
{
如果(插图 == 空)
插图 = 新插图(0,0,0,0);
int insetsWidth = insets.left + insets.right;
int insetsHeight = insets.top + insets.bottom;
结果 = new Dimension( (int) ( zoomFactor * ( dim.getWidth() - insetsWidth ) + insetsWidth ),
(int) ( zoomFactor * ( dim.getHeight() - insetsHeight ) + insetsHeight ) );
}
返回(结果);
}
public Rectangle getNewRectangle( Rectangle rect, Insets insets, double zoomFactor )
{
矩形结果 = null;
如果(矩形!=空)
{
如果(插图 == 空)
插图 = 新插图(0,0,0,0);
int insetsWidth = insets.left + insets.right;
int insetsHeight = insets.top + insets.bottom;
结果 = new Rectangle( (int) ( zoomFactor * ( rect.getX() + insets.left ) - insets.left ),
(int) ( zoomFactor * ( rect.getY() + insets.top ) - insets.top ),
(int) ( zoomFactor * ( rect.getWidth() - insetsWidth ) + insetsWidth ),
(int) ( zoomFactor * ( rect.getHeight() - insetsHeight ) + insetsHeight ) );
}
返回(结果);
}
public Insets getNewInsets( Insets insets, double zoomFactor )
{
插入结果 = null;
如果(插入!= null)
{
结果 = new Insets( (int) ( insets.top * zoomFactor ),
(int) ( insets.left * zoomFactor ),
(int) ( insets.bottom * zoomFactor ),
(int) ( insets.right * zoomFactor ) );
}
返回(结果);
}
公共点getCenter(矩形矩形)
{
点结果 = null;
如果(矩形!=空)
{
结果 = 新点 ( (int) ( rect.getX() + rect.getWidth() / 2 ),
(int) ( rect.getY() + rect.getHeight() / 2 ) );
}
返回(结果);
}
public Rectangle calculateNewBounds( Rectangle originalBounds, Insets insets, Point center, double zoomFactor )
{
矩形结果 = null;
如果(原始边界!= null)
{
如果(插图 == 空)
插图 = 新插图(0, 0, 0, 0);
int newX = (int) originalBounds.getX();
int newY = (int) originalBounds.getY();
如果(中心!=空)
{
newX = (int) ( center.getX() - insets.left + ( originalBounds.getX() - center.getX() + insets.left ) * zoomFactor );
newY = (int) ( center.getY() - insets.top + ( originalBounds.getY() - center.getY() + insets.top ) * zoomFactor );
}
结果=新矩形(新X,
新Y,
(int) ( ( originalBounds.getWidth() - insets.left - insets.right ) * zoomFactor + insets.left + insets.right ),
(int) ( ( originalBounds.getHeight() - insets.top - insets.bottom ) * zoomFactor + insets.top + insets.bottom )
);
}
返回(结果);
}
}