TL;DR: it s not possible directly, but can be done with a workaround like in Luca s answer, however his/her answer uses the incorrect gradient steps. The correct ones are listed below.
The way it works
In the Metal LAF there is a hardcoded exception. If the background
property is a subclass of UIResource
, it s ignored* and the button is instead painted with the (also hardcoded) gradient from the UI property Button.gradient
. Otherwise, if background
is not a UIResource
, that background is painted as-is.
*unless the button is disabled, in which case there is no gradient and the color inside the UIResource
is used for the background.
The gradient
按照<代码>MetalButtonUI的逻辑,我发现其使用过的梯度来自“ID”财产代码,其中载有。 ArrayList
:
0 = {Float} 0.3
1 = {Float} 0.0
2 = {ColorUIResource} "[221,232,243]"
3 = {ColorUIResource} "[255,255,255]"
4 = {ColorUIResource} "[184,207,229]"
Following the logic even further, I ended up in MetalUtils.GradientPainter.drawVerticalGradient()
. This implementation interprets the above data as*:
- Gradient from 0% to 30%: color1 to color2
- Gradient from 30% to 60%: color2 to color1
- Gradient from 60% to 100%: color1 to color3
*assuming the second float is 0.0, otherwise more gradients are drawn.
Since this is a multi-stage gradient, it can t be done with a simple GradientPaint
but can be done with a LinearGradientPaint
. However the background
property only accepts Color
. It cannot even be spoofed/hacked because the actual value is eventually given to Graphics.setColor()
and not Graphics2D.setPaint()
(even though Metal is Swing-based and not AWT) Dead End. The only solution seems to subclass JButton altogether.