Estou tentando criar uma propriedade de estilo CSS personalizada para meu componente, com vários valores de cor, como -fx-background-color. Mas estou travado, pois, apesar de definir minha propriedade CSS de forma semelhante à propriedade -fx-background-color, apenas o primeiro valor de cor é analisado da declaração CSS. Esta é a declaração CSS:
.default-chart-theme {
-jfc-default-paint-sequence: red,white,green,blue,yellow,orange,gray;
}
E esta é a declaração CssMetadata na classe java:
public final CssMetaData<StyleableChartViewer, Paint[]> DEFAULT_PAINT_SEQUENCE = new CssMetaData<>("-jfc-default-paint-sequence", PaintConverter.SequenceConverter.getInstance(), new Paint[] { Color.RED } )
{
@Override
public boolean isSettable(StyleableChartViewer styleable)
{
return !cssDefaultPaintSequence.isBound();
}
@Override
public StyleableProperty<Paint[]> getStyleableProperty(StyleableChartViewer styleable)
{
return cssDefaultPaintSequence;
}
};
public final SimpleStyleableObjectProperty<Paint[]> cssDefaultPaintSequence =
new SimpleStyleableObjectProperty<>(DEFAULT_PAINT_SEQUENCE, this, "cssDefaultPaintSequence", new Paint[] { Color.RED } );
no getCssMetaData eu também retorno essa propriedade e ela também é analisada, mas em vez de uma sequência de pintura, ela é analisada apenas como um único valor de cor.
Também recebo um aviso ao processar a propriedade css:
WARNING: Caught 'java.lang.ClassCastException: class javafx.scene.paint.Color cannot be cast to class [Ljavafx.css.ParsedValue; (javafx.scene.paint.Color and [Ljavafx.css.ParsedValue; are in unnamed module of loader 'app')' while converting value for '-jfc-default-paint-sequence' from rule '*.default-chart-theme' in stylesheet
Qualquer conselho sobre como criar uma propriedade CSS é bem-vindo. Tentei pesquisar no Google e também usar o Perplexity para obter informações sobre esse problema, mas não encontrei nada útil para resolvê-lo.
Obrigado!
Solução Parcial
Uma solução é criar sua própria
StyleConverter
implementação e citar a lista de cores no CSS. Ao citar a lista de cores, o conversor receberá o valor como uma única string, que poderá ser processada da maneira que você desejar. Infelizmente, uma desvantagem significativa dessa abordagem é que as variáveis (ou seja, as cores pesquisadas) não serão resolvidas e não há como resolvê-las dentro de um conversor de estilo.Pode haver uma abordagem melhor. Se houver, espero que outra pessoa publique uma resposta.
Exemplo
Este exemplo só é capaz de analisar
Color
, não qualquerPaint
. É por isso que esta é apenas uma "solução parcial", embora deva ser possível modificá-la para analisar gradientes e padrões de imagem de forma semelhante ao seu funcionamento nativo (o que não é necessariamente uma modificação trivial). Em outras palavras, deve ser possível tornar essa abordagem tão flexível quanto propriedades como-fx-background-color
, embora sem que nenhuma variável seja resolvida.Main.java
ColorSequenceConverter.java
ColorsRegion.java
Por que sua tentativa falhou
A
StyleConverter
é responsável por pegar aParsedValue
e convertê-lo para o tipo usado pela propriedade JavaFX. Mas aParsedValue
representa o valor como já foi analisado pelo analisador CSS. Em outras palavras, o valor já foi analisado em um objeto intermediário. Além disso, aParsedValue
pode ter seu próprioStyleConverter
conversor associado a ele. Esse conversor, se não me engano, sempre tem precedência sobre aquele associado ao . de uma propriedade estilizávelCssMetaData
.Não é possível personalizar em qual objeto intermediário o valor é analisado e qual conversor, se houver, está associado ao valor analisado. O comportamento é codificado no parser . Examinando o código vinculado, você pode ver o que está dando errado na sua tentativa.
Sua propriedade CSS,
-jfc-default-paint-sequence
, não é uma das propriedades especialmente tratadas.O valor da sua propriedade não é um número, duração, hash, função ou URL. Também não é uma constante conhecida ou uma variável previamente estabelecida. Isso significa que o valor é tratado como uma simples string/cor possível. No entanto, apenas o primeiro "termo" é considerado neste caso . No seu exemplo, o primeiro "termo" é
red
. Todos os outros "termos" (as outras cores) são ignorados.O primeiro "termo" do valor do seu exemplo é
red
, que pode ser analisado em aColor
(especificamente; não em qualquerPaint
tipo). Portanto, o valor é analisado em aColor
e retornado encapsulado em um únicoParsedValue<Color, Color>
. IssoParsedValue
não temStyleConverter
.O
PaintConverter.SequenceConverter
espera umParsedValue<ParsedValue<?, Paint>[], Paint[]>
. Então, aClassCastException
ocorre ao tentar obter o valor deParsedValue
porque ele espera um ,ParsedValue<?, Paint>[]
mas em vez disso obtém umColor
.Como esse comportamento é fixo no código, infelizmente você não pode alterá-lo. Nesse caso, não faria muita diferença se o analisador manipulasse matrizes de tintas, mas isso não acontece (curiosamente, o analisador manipula matrizes de números para tamanhos).
Agora, se o valor não puder ser analisado em a
Color
, você obterá aParsedValue<String, String>
semStyleConverter
. É disso que a "solução parcial" acima se aproveita. Ao colocar o valor entre aspas, o analisador CSS trata tudo como um único "termo". Esse "termo" não pode ser analisado em uma cor. Isso faz com que os metadados CSSStyleConverter
tenham basicamente controle total sobre como o valor é analisado.