While building my JavaFX desktop application's GUI I came across this amazing button design that I am trying to implement.
Is there any way of implementing this into a JavaFX desktop application?
I apologize for the lengthy background. For the guicy part please skip to the next section.
On my may to conquer this mission I ..
have read:
"Introduction to FXML" releases JavaFX11, JavaFX 10.0 JavaFX 8.0.
a couple more but only a brief reading.
have searched for:
- "Using JavaFX WebView in JavaFX desktop application" - nothing there.
- "Integrating HTML elements into JavaFX FXML files" - nothing there.
- "Initializing JavaFX FXML elements using JavaScript" - nothing there.
have been through these StackOverflow questions:
- javafx + javascript on desktop app
- What version of HTML and CSS does JavaFX support?
- JavaFx Include custom components in FXML
- Is It Possible To Import Classes into FXML <fx:script> block (JavaFX-2)
- FXML, script tag and initialize method
where I had hoped I have finally found my answer but jewelsea's answer contains a broken link. - javascript pass XML document object as argument
- Passing XML element to JavaScript function
- JavaScript script in a FXML
After this journey, what I actually know for sure (please correct me if I'm wrong):
- I can specify the FXML elements' event handlers using JavaScript.
- It is possible to call the JavaScript method from within Java (no idea how though).
- Seems like it is not possible to declare an HTML's element in JavaFX's FXML files.
- Hence, there is no way of applying these CSS classes to my JFXButton.
- Hence, (1) is worthless as the JS code manipulates the CSS class.
- Hence, there is no way of applying these CSS classes to my JFXButton.
Tobias Reich's button code:
HTML:
<a href="#" data-title="Awesome Button"></a>
CSS:
a {
position: relative;
display: inline-block;
padding: 1.2em 2em;
text-decoration: none;
text-align: center;
cursor: pointer;
user-select: none;
color: white;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: linear-gradient(135deg, #6e8efb, #a777e3);
border-radius: 4px;
transition: box-shadow .5s ease, transform .2s ease;
will-change: transform;
box-shadow: 0 2px 5px rgba(0, 0, 0, .2);
transform:
translateY(var(--ty, 0))
rotateX(var(--rx, 0))
rotateY(var(--ry, 0))
translateZ(var(--tz, -12px));
}
&:hover::before {
box-shadow: 0 5px 15px rgba(0, 0, 0, .3);
}
&::after {
position: relative;
display: inline-block;
content: attr(data-title);
transition: transform .2s ease;
font-weight: bold;
letter-spacing: .01em;
will-change: transform;
transform:
translateY(var(--ty, 0))
rotateX(var(--rx, 0))
rotateY(var(--ry, 0));
}
}
body {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
transform-style: preserve-3d;
transform: perspective(800px);
}
JavaScript:
const docStyle = document.documentElement.style
const aElem = document.querySelector('a')
const boundingClientRect = aElem.getBoundingClientRect()
aElem.onmousemove = function(e) {
const x = e.clientX - boundingClientRect.left
const y = e.clientY - boundingClientRect.top
const xc = boundingClientRect.width/2
const yc = boundingClientRect.height/2
const dx = x - xc
const dy = y - yc
docStyle.setProperty('--rx', `${ dy/-1 }deg`)
docStyle.setProperty('--ry', `${ dx/10 }deg`)
}
aElem.onmouseleave = function(e) {
docStyle.setProperty('--ty', '0')
docStyle.setProperty('--rx', '0')
docStyle.setProperty('--ry', '0')
}
aElem.onmousedown = function(e) {
docStyle.setProperty('--tz', '-25px')
}
document.body.onmouseup = function(e) {
docStyle.setProperty('--tz', '-12px')
}
What I have so far:
I can handle the various mouse events one by one. Which makes applying the CSS to my JFXButton the problem I am looking for a solution to.
My FXML:
<JFXButton fx:id="testBTN" onAction="handleTestAction(this)" onMouseEntered="mouseEntered(this)" text="TestButton"/>
<fx:script source="JStestBTN.js"/>
JStestBTN:
load("nashorn:mozilla_compat.js");
importClass(java.lang.System);
function handleTestAction(event) {
docStyle.setProperty('--tz', '-25px') //not tested, might not work.
}
OR
Since it is possible to do something like this: (based on JavaScript script in a FXML)
<Label fx:id="myLabel" />
<fx:script>
myLabel.text = "This is the text of my label.";
</fx:script>
I thought I could do something like this:
<JFXButton fx:id="testBTN" text="TestButton"/>
<fx:script>
testBTN.sendToExternalJS; //where it will apply all the "aElem.onmouseSomething"
</fx:script>
/*OR something like:*/
<JFXButton fx:id="testBTN" text="TestButton"/>
<fx:script source="JStestBTN.js" isItPossibleToPassTheJFXButtonHere?"/>
/*OR if neither is possible:*/
//I think my solution would be getting as close as possible to the button's
//design using the available JavaFX & CSS tools. Plus "translating" the
//functions from JavaScript to Java+JavaFX, using animations, etc..
So to sum up:
- Is it possible to apply this kind of CSS to a Button/JFXButton? (workaround?)
- Is it possible to "construct" or initialize the button from an external JavaScript file?
- If ((1&2)=="no"), could you point me in the right direction for translating the JS code to Java/JavaFX?
Thank you for bearing with me through this long essay.