@@ -2,17 +2,20 @@ package com.axis.innovators.box.gui;
import javax.swing.* ;
import java.awt.* ;
import java.awt.event.* ;
import java.awt.geom.* ;
import java.util.HashMap ;
import java.util.Map ;
/**
* 启动窗口的任务系统
* @author tzdwindows 7
* 启动窗口的任务系统(已改造为现代流畅动画视觉效果)
* 注意: 保留了原有对外方法和签名( updateMainProgress/updateSubProgress/setTotalTasks/close)
* 作者: tzdwindows 7( UI 改造版)
*/
public class ProgressBarManager extends WindowsJDialog {
private JFrame loadingFrame ;
private J ProgressBar mainProgressBar ;
private J ProgressBar subProgressBar ;
private Smooth ProgressBar mainProgressBar ;
private Smooth ProgressBar subProgressBar ;
private JLabel statusLabel ;
private JLabel timeLabel ;
private long startTime ;
@@ -21,81 +24,208 @@ public class ProgressBarManager extends WindowsJDialog {
private int completedTasks ;
private Map < String , Integer > subTasks = new HashMap < > ( ) ;
// 动画计时器( 60FPS)
private Timer animationTimer ;
// 视觉参数
private Color accentColor = new Color ( 0x00C2FF ) ; // 科技感青蓝
private Font uiFont ;
public ProgressBarManager ( String title , int totalTasks ) {
this . totalTasks = totalTasks ;
this . totalTasks = Math . max ( 1 , totalTasks) ;
this . completedTasks = 0 ;
this . startTime = System . currentTimeMillis ( ) ;
// 尝试设置现代中文友好字体( Windows 常见)
try {
uiFont = new Font ( " Microsoft YaHei UI " , Font . PLAIN , 13 ) ;
// 若系统无该字体则 fallback
if ( ! uiFont . getFamily ( ) . toLowerCase ( ) . contains ( " microsoft " ) & &
! uiFont . getFamily ( ) . toLowerCase ( ) . contains ( " yahei " ) ) {
uiFont = new Font ( " Segoe UI " , Font . PLAIN , 13 ) ;
}
} catch ( Throwable t ) {
uiFont = new Font ( Font . SANS_SERIF , Font . PLAIN , 13 ) ;
}
loadingFrame = new JFrame ( title ) ;
loadingFrame . setUndecorated ( true ) ;
loadingFrame . setBackground ( new Color ( 0 , 0 , 0 , 0 ) ) ; // 允许圆角透明背景
loadingFrame . setDefaultCloseOperation ( JFrame . DO_NOTHING_ON_CLOSE ) ;
loadingFrame . setSize ( 40 0, 25 0) ;
loadingFrame . setSize ( 52 0, 30 0) ;
loadingFrame . setLocationRelativeTo ( null ) ;
loadingFrame . setIconImage ( LoadIcon . loadIcon ( " logo.png " , 64 ) . getImage ( ) ) ;
JPanel loadingPanel = new JPanel ( new BorderLayout ( ) ) ;
// 主容器(带动画背景和圆角卡片)
AnimatedBackgroundPanel root = new AnimatedBackgroundPanel ( ) ;
root . setLayout ( new GridBagLayout ( ) ) ;
root . setBorder ( BorderFactory . createEmptyBorder ( 18 , 18 , 18 , 18 ) ) ;
mainProgressBar = new JProgressBar ( 0 , 100 ) ;
mainProgressBar . setStringPainted ( true ) ;
// 卡片面板
JPanel card = new JPanel ( ) {
@Override
protected void paintComponent ( Graphics g ) {
Graphics2D g2 = ( Graphics2D ) g . create ( ) ;
g2 . setRenderingHint ( RenderingHints . KEY_ANTIALIASING , RenderingHints . VALUE_ANTIALIAS_ON ) ;
subProgressBar = new JProgressBar ( 0 , 100 ) ;
subProgressBar . setStringPainted ( true ) ;
subProgressBar . setString ( " Subtask Progress " ) ;
// 卡片阴影(简单外发光)
int arc = 18 ;
int w = getWidth ( ) ;
int h = getHeight ( ) ;
statusLabel = new JLabel ( " Initializing... " , SwingConstants . CENTER ) ;
timeLabel = new JLabel ( " Time elapsed: 0s " , SwingConstants . CENTER ) ;
// 背景渐变
GradientPaint gp = new GradientPaint ( 0 , 0 , new Color ( 20 , 22 , 25 , 230 ) ,
0 , h , new Color ( 14 , 16 , 19 , 230 ) ) ;
g2 . setPaint ( gp ) ;
JLabel logoLabel = new JLabel ( LoadIcon . loadIcon ( " logo.png " , 64 ) ) ;
// 圆角矩形
RoundRectangle2D rr = new RoundRectangle2D . Float ( 6 , 6 , w - 12 , h - 12 , arc , arc ) ;
g2 . fill ( rr ) ;
JPanel progressPanel = new JPanel ( new GridLayout ( 2 , 1 ) ) ;
progressPanel . add ( mainProgressBar ) ;
progressPanel . add ( subProgressBar ) ;
// 细微边框
g2 . setStroke ( new BasicStroke ( 1f ) ) ;
g2 . setColor ( new Color ( 255 , 255 , 255 , 10 ) ) ;
g2 . draw ( rr ) ;
loadingPanel . add ( logoLabel , BorderLayout . NORTH ) ;
loadingPanel . add ( progressPanel , BorderLayout . CENTER ) ;
loadingPanel . add ( statusLabel , BorderLayout . SOUTH ) ;
loadingPanel . add ( timeLabel , BorderLayout . SOUTH ) ;
g2 . dispose ( ) ;
super . paintComponent ( g ) ;
}
} ;
card . setOpaque ( false ) ;
card . setLayout ( new BorderLayout ( 12 , 12 ) ) ;
card . setPreferredSize ( new Dimension ( 480 , 240 ) ) ;
card . setBorder ( BorderFactory . createEmptyBorder ( 14 , 14 , 14 , 14 ) ) ;
// 顶部 logo + 标题
JPanel top = new JPanel ( new BorderLayout ( ) ) ;
top . setOpaque ( false ) ;
JLabel logoLabel = new JLabel ( LoadIcon . loadIcon ( " logo.png " , 48 ) ) ;
logoLabel . setBorder ( BorderFactory . createEmptyBorder ( 0 , 0 , 0 , 12 ) ) ;
JLabel titleLabel = new JLabel ( title ) ;
titleLabel . setFont ( uiFont . deriveFont ( Font . BOLD , 18f ) ) ;
titleLabel . setForeground ( Color . WHITE ) ;
top . add ( logoLabel , BorderLayout . WEST ) ;
top . add ( titleLabel , BorderLayout . CENTER ) ;
// 中间进度区
JPanel center = new JPanel ( new GridBagLayout ( ) ) ;
center . setOpaque ( false ) ;
GridBagConstraints c = new GridBagConstraints ( ) ;
c . gridx = 0 ;
c . gridy = 0 ;
c . weightx = 1 ;
c . fill = GridBagConstraints . HORIZONTAL ;
mainProgressBar = new SmoothProgressBar ( 0 ) ;
mainProgressBar . setPreferredSize ( new Dimension ( 420 , 26 ) ) ;
mainProgressBar . setAccentColor ( accentColor ) ;
subProgressBar = new SmoothProgressBar ( 0 ) ;
subProgressBar . setPreferredSize ( new Dimension ( 420 , 18 ) ) ;
subProgressBar . setAccentColor ( new Color ( 0x6EE7FF ) ) ;
subProgressBar . setShowStripe ( true ) ;
center . add ( mainProgressBar , c ) ;
c . gridy + + ;
c . insets = new Insets ( 8 , 0 , 0 , 0 ) ;
center . add ( subProgressBar , c ) ;
// 底部文本
JPanel bottom = new JPanel ( new BorderLayout ( ) ) ;
bottom . setOpaque ( false ) ;
statusLabel = new JLabel ( " Initializing... " , SwingConstants . LEFT ) ;
statusLabel . setFont ( uiFont . deriveFont ( Font . PLAIN , 12f ) ) ;
statusLabel . setForeground ( new Color ( 220 , 230 , 240 ) ) ;
timeLabel = new JLabel ( " Elapsed: 0s " , SwingConstants . RIGHT ) ;
timeLabel . setFont ( uiFont . deriveFont ( Font . PLAIN , 12f ) ) ;
timeLabel . setForeground ( new Color ( 180 , 200 , 215 ) ) ;
bottom . add ( statusLabel , BorderLayout . WEST ) ;
bottom . add ( timeLabel , BorderLayout . EAST ) ;
bottom . setBorder ( BorderFactory . createEmptyBorder ( 8 , 2 , 2 , 2 ) ) ;
card . add ( top , BorderLayout . NORTH ) ;
card . add ( center , BorderLayout . CENTER ) ;
card . add ( bottom , BorderLayout . SOUTH ) ;
root . add ( card ) ;
loadingFrame . setContentPane ( root ) ;
// 拖动窗口支持(在无边框下)
WindowDragger . makeDraggable ( loadingFrame , card ) ;
// 启动动画定时器
animationTimer = new Timer ( 1000 / 60 , e - > {
boolean repaintNeeded = false ;
if ( mainProgressBar . animateStep ( ) ) repaintNeeded = true ;
if ( subProgressBar . animateStep ( ) ) repaintNeeded = true ;
root . advanceAnimation ( ) ;
updateTimeLabel ( ) ;
if ( repaintNeeded ) {
root . repaint ( ) ;
} else {
// 仍需刷新背景动画
root . repaint ( ) ;
}
} ) ;
animationTimer . start ( ) ;
loadingFrame . add ( loadingPanel ) ;
loadingFrame . setVisible ( true ) ;
// 防止用户误操作关闭(保持原行为)
loadingFrame . addWindowListener ( new WindowAdapter ( ) {
@Override
public void windowClosing ( WindowEvent e ) {
// DO NOTHING
}
} ) ;
}
/**
* 更新主任务进度
* 更新主任务进度(对外接口保持不变)
* @param completedTasks 已完成的主任务数量
*/
public void updateMainProgress ( int completedTasks ) {
this . completedTasks = completedTasks ;
int progress = ( int ) ( ( completedTasks / ( double ) totalTasks ) * 100 ) ;
mainProgressBar . setValue ( progress ) ;
statusLabel . setText ( " Main Progress: " + progress + " % " ) ;
updateTimeLabel ( ) ;
double progress = ( completedTasks / ( double ) Math . max ( 1 , totalTasks) ) * 100 . 0 ;
if ( progress < 0 ) progress = 0 ;
if ( progress > 100 ) progress = 100 ;
mainProgressBar . setTarget ( ( int ) Math . round ( progress ) ) ;
statusLabel . setText ( " 主任务: " + completedTasks + " / " + totalTasks + " ( " + ( int ) progress + " %) " ) ;
}
/**
* 更新子任务进度
* 更新子任务进度(对外接口保持不变)
* @param subTaskName 子任务名称
* @param subTaskCompleted 已完成的子任务数量
* @param subTaskTotal 子任务总数
*/
public void updateSubProgress ( String subTaskName , int subTaskCompleted , int subTaskTotal ) {
if ( subTaskTotal < = 0 ) subTaskTotal = 1 ;
subTasks . put ( subTaskName , subTaskCompleted ) ;
int progress = ( int ) ( ( subTaskCompleted / ( double ) subTaskTotal ) * 100 ) ;
subProgressBar . setValue ( progress ) ;
subProgressBar . setString ( subTaskName + " : " + progress + " % " ) ;
updateTimeLabel ( ) ;
double progress = ( subTaskCompleted / ( double ) subTaskTotal ) * 100 . 0 ;
if ( progress < 0 ) progress = 0 ;
if ( progress > 100 ) progress = 100 ;
subProgressBar . setTarget ( ( int ) Math . round ( progress ) ) ;
subProgressBar . setLabel ( subTaskName ) ;
}
/**
* 更新总任务数
*/
public void setTotalTasks ( int totalTasks ) {
this . totalTasks = totalTasks ;
this . totalTasks = Math . max ( 1 , totalTasks) ;
}
/**
* 关闭加载窗口
*/
public void close ( ) {
if ( animationTimer ! = null & & animationTimer . isRunning ( ) ) {
animationTimer . stop ( ) ;
}
loadingFrame . dispose ( ) ;
}
@@ -104,6 +234,229 @@ public class ProgressBarManager extends WindowsJDialog {
*/
private void updateTimeLabel ( ) {
long elapsedTime = ( System . currentTimeMillis ( ) - startTime ) / 1000 ;
timeLabel . setText ( " Time elapsed: " + elapsedTime + " s " ) ;
long hours = elapsedTime / 3600 ;
long mins = ( elapsedTime % 3600 ) / 60 ;
long secs = elapsedTime % 60 ;
if ( hours > 0 ) {
timeLabel . setText ( String . format ( " Elapsed: %dh %02dm %02ds " , hours , mins , secs ) ) ;
} else if ( mins > 0 ) {
timeLabel . setText ( String . format ( " Elapsed: %dm %02ds " , mins , secs ) ) ;
} else {
timeLabel . setText ( String . format ( " Elapsed: %ds " , secs ) ) ;
}
}
}
// --------------------------
// 内部类:平滑进度条(支持插值动画、条纹、标签)
// --------------------------
private static class SmoothProgressBar extends JComponent {
private int target = 0 ;
private double displayed = 0 . 0 ;
private int height = 20 ;
private Color base = new Color ( 255 , 255 , 255 , 18 ) ;
private Color fill = new Color ( 0x00C2FF ) ;
private String label = " " ;
private boolean showStripe = false ;
private Color stripeColor = new Color ( 255 , 255 , 255 , 30 ) ;
private double stripeOffset = 0 . 0 ;
public SmoothProgressBar ( int initial ) {
this . target = Math . max ( 0 , Math . min ( 100 , initial ) ) ;
this . displayed = this . target ;
setOpaque ( false ) ;
setPreferredSize ( new Dimension ( 200 , height ) ) ;
}
public void setAccentColor ( Color c ) {
this . fill = c ;
}
public void setLabel ( String label ) {
this . label = label ;
}
public void setShowStripe ( boolean v ) {
this . showStripe = v ;
}
public void setTarget ( int t ) {
t = Math . max ( 0 , Math . min ( 100 , t ) ) ;
this . target = t ;
}
/**
* 每帧推进插值,返回是否需要重绘
*/
public boolean animateStep ( ) {
// 平滑插值(阻尼)
double diff = target - displayed ;
if ( Math . abs ( diff ) < 0 . 02 ) {
displayed = target ;
} else {
displayed + = diff * 0 . 18 ; // 阻尼因子(调整流畅度)
}
// 条纹动画
if ( showStripe ) {
stripeOffset + = 1 . 8 ;
if ( stripeOffset > 60 ) stripeOffset = 0 ;
}
// 是否需要重绘
return Math . abs ( diff ) > 0 . 001 | | showStripe ;
}
@Override
protected void paintComponent ( Graphics g ) {
int w = getWidth ( ) ;
int h = getHeight ( ) ;
Graphics2D g2 = ( Graphics2D ) g . create ( ) ;
g2 . setRenderingHint ( RenderingHints . KEY_ANTIALIASING , RenderingHints . VALUE_ANTIALIAS_ON ) ;
// 背景轨道
RoundRectangle2D bg = new RoundRectangle2D . Float ( 0 , 0 , w , h , h , h ) ;
g2 . setColor ( base ) ;
g2 . fill ( bg ) ;
// 阴影(内阴影模拟)
g2 . setColor ( new Color ( 0 , 0 , 0 , 30 ) ) ;
g2 . setStroke ( new BasicStroke ( 1f ) ) ;
g2 . draw ( bg ) ;
// 填充(渐变)
int fillW = ( int ) Math . round ( ( displayed / 100 . 0 ) * w ) ;
if ( fillW > 0 ) {
GradientPaint gp = new GradientPaint ( 0 , 0 , fill . brighter ( ) , w , 0 , fill . darker ( ) ) ;
RoundRectangle2D fg = new RoundRectangle2D . Float ( 0 , 0 , fillW , h , h , h ) ;
g2 . setPaint ( gp ) ;
g2 . fill ( fg ) ;
// 发光边缘
g2 . setComposite ( AlphaComposite . getInstance ( AlphaComposite . SRC_OVER , 0 . 25f ) ) ;
g2 . setColor ( fill ) ;
g2 . fill ( new RoundRectangle2D . Float ( 0 , - h / 3f , fillW , h + h / 3f , h , h ) ) ;
g2 . setComposite ( AlphaComposite . SrcOver ) ;
}
// 条纹效果
if ( showStripe & & fillW > 6 ) {
Shape clip = g2 . getClip ( ) ;
g2 . setClip ( new RoundRectangle2D . Float ( 0 , 0 , fillW , h , h , h ) ) ;
int stripeW = 18 ;
for ( int x = - stripeW * 2 ; x < w + stripeW * 2 ; x + = stripeW ) {
int sx = ( int ) ( x + stripeOffset ) ;
Polygon p = new Polygon ( ) ;
p . addPoint ( sx , 0 ) ;
p . addPoint ( sx + stripeW , 0 ) ;
p . addPoint ( sx + stripeW - 8 , h ) ;
p . addPoint ( sx - 8 , h ) ;
g2 . setColor ( stripeColor ) ;
g2 . fill ( p ) ;
}
g2 . setClip ( clip ) ;
}
// 文本显示(居中)
String text ;
if ( label ! = null & & ! label . isEmpty ( ) ) {
text = label + " " + Math . round ( displayed ) + " % " ;
} else {
text = Math . round ( displayed ) + " % " ;
}
g2 . setFont ( new Font ( Font . SANS_SERIF , Font . BOLD , Math . max ( 11 , h - 6 ) ) ) ;
FontMetrics fm = g2 . getFontMetrics ( ) ;
int tx = ( w - fm . stringWidth ( text ) ) / 2 ;
int ty = ( h + fm . getAscent ( ) - fm . getDescent ( ) ) / 2 ;
g2 . setColor ( new Color ( 255 , 255 , 255 , 210 ) ) ;
g2 . drawString ( text , tx , ty ) ;
g2 . dispose ( ) ;
}
}
// --------------------------
// 内部类:带动画效果的背景面板(流动扫描线 + 颗粒/渐变)
// --------------------------
private class AnimatedBackgroundPanel extends JPanel {
private double offset = 0 ;
private double particlePhase = 0 ;
public AnimatedBackgroundPanel ( ) {
setOpaque ( false ) ;
}
public void advanceAnimation ( ) {
offset + = 0 . 9 ;
if ( offset > 2000 ) offset = 0 ;
particlePhase + = 0 . 02 ;
}
@Override
protected void paintComponent ( Graphics g ) {
int w = getWidth ( ) ;
int h = getHeight ( ) ;
Graphics2D g2 = ( Graphics2D ) g . create ( ) ;
g2 . setRenderingHint ( RenderingHints . KEY_ANTIALIASING , RenderingHints . VALUE_ANTIALIAS_ON ) ;
// 背景渐变(深色)
Paint p = new GradientPaint ( 0 , 0 , new Color ( 8 , 10 , 12 ) , w , h , new Color ( 18 , 20 , 24 ) ) ;
g2 . setPaint ( p ) ;
g2 . fillRect ( 0 , 0 , w , h ) ;
// 斜向扫描线(细微)
g2 . setComposite ( AlphaComposite . getInstance ( AlphaComposite . SRC_OVER , 0 . 06f ) ) ;
g2 . setColor ( Color . WHITE ) ;
for ( int i = - 200 ; i < w + h ; i + = 40 ) {
int x1 = i + ( int ) offset ;
int y1 = 0 ;
int x2 = i - h + ( int ) offset ;
int y2 = h ;
g2 . setStroke ( new BasicStroke ( 2f ) ) ;
g2 . drawLine ( x1 , y1 , x2 , y2 ) ;
}
g2 . setComposite ( AlphaComposite . SrcOver ) ;
// 轻微颗粒(科技光斑)
g2 . setComposite ( AlphaComposite . getInstance ( AlphaComposite . SRC_OVER , 0 . 08f ) ) ;
for ( int i = 0 ; i < 10 ; i + + ) {
float px = ( float ) ( ( Math . sin ( particlePhase + i ) + 1 ) / 2 . 0 * w ) ;
float py = ( float ) ( ( Math . cos ( particlePhase * 0 . 7 + i * 0 . 3 ) + 1 ) / 2 . 0 * h ) ;
int size = 6 + ( i % 3 ) * 4 ;
g2 . fillOval ( ( int ) px , ( int ) py , size , size ) ;
}
g2 . setComposite ( AlphaComposite . SrcOver ) ;
g2 . dispose ( ) ;
super . paintComponent ( g ) ;
}
}
// --------------------------
// 工具:使无边框窗口可拖动
// --------------------------
private static class WindowDragger {
public static void makeDraggable ( Window wnd , Component dragRegion ) {
final Point [ ] mouseDown = { null } ;
dragRegion . addMouseListener ( new MouseAdapter ( ) {
@Override
public void mousePressed ( MouseEvent e ) {
mouseDown [ 0 ] = e . getPoint ( ) ;
}
@Override
public void mouseReleased ( MouseEvent e ) {
mouseDown [ 0 ] = null ;
}
} ) ;
dragRegion . addMouseMotionListener ( new MouseMotionAdapter ( ) {
@Override
public void mouseDragged ( MouseEvent e ) {
if ( mouseDown [ 0 ] ! = null ) {
Point curr = e . getLocationOnScreen ( ) ;
wnd . setLocation ( curr . x - mouseDown [ 0 ] . x , curr . y - mouseDown [ 0 ] . y ) ;
}
}
} ) ;
}
}
}