Transparent background in the WebView in JavaFX - webview

I need to show my webview content over parent background pattern. Is there a straightforward way to do it?

This might be useful
final com.sun.webkit.WebPage webPage = com.sun.javafx.webkit.Accessor.getPageFor(engine);
webPage.setBackgroundColor(0);

Webview transparent I get a good solution here : https://javafx-jira.kenai.com/browse/RT-29186 read comments Harry Hur
import java.lang.reflect.Field;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import org.w3c.dom.Document; `
public class TestTranparentApps extends Application {
#Override
public void start(Stage primaryStage) {
new WebPage(primaryStage);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
class WebPage{
WebView webview;
WebEngine webengine;
public WebPage(Stage mainstage){
webview = new WebView();
webengine = webview.getEngine();
Scene scene = new Scene(webview);
scene.setFill(null);
mainstage.setScene(scene);
mainstage.initStyle(StageStyle.TRANSPARENT);
mainstage.setWidth(700);
mainstage.setHeight(100);
webengine.documentProperty().addListener(new DocListener());
webengine.loadContent("<body style='background : rgba(0,0,0,0);font-size: 70px;text-align:center;'>Test Transparent</body>");
}
class DocListener implements ChangeListener<Document>{
#Override
public void changed(ObservableValue<? extends Document> observable, Document oldValue, Document newValue) {
try {
// Use reflection to retrieve the WebEngine's private 'page' field.
Field f = webengine.getClass().getDeclaredField("page");
f.setAccessible(true);
com.sun.webkit.WebPage page = (com.sun.webkit.WebPage) f.get(webengine);
page.setBackgroundColor((new java.awt.Color(0, 0, 0, 0)).getRGB());
} catch (Exception e) {
}
}
}
}
}

If u have a bright background use
webView.setBlendMode(BlendMode.DARKEN);
and when dark background, then
webView.setBlendMode(BlendMode.LIGHTEN);
This will probably be fixed in some time, this feature is requested on the JavaFX bug tracker #RT-25004

You can Chroma Key your WebView over your content using Blend effects.
Update
I tried this out and implementing a true Chroma Key with the built-in Blend effects of JavaFX 2.2 in JavaFX is actually pretty difficult (and surpassed my capabilities of implementing). I managed to make the technique work with pre-chroma keyed flv video formats, but not with arbitrary nodes such as WebView.
Still, for now, you can achieve something somewhat similar in a simple way using the darken and lighten effects as martini suggests in his answer. It's not perfect, but will probably need to suffice until RT-25004 is implemented or the JavaFX platform provides a more comprehensive set of alpha compositing operations.

Since JavaFX 18, transparent WebView backgrounds are finally supported (see JDK-8090547):
WebEngine engine = webView.getEngine();
webView.setPageFill(Color.TRANSPARENT);

You need to set the Web Page Background to 0. But you might need to do some other stuff to not make it break on scrolling. The following GitHub Gist is a java agent that can be added to our app and that manipulates WebPages to be transparent. https://gist.github.com/riccardobl/18603f9de508b1ab6c9e or more up to date version https://github.com/FAForever/downlords-faf-client/blob/develop/webview-patch/src/main/java/com/faforever/client/webviewpatcher/TransparentWebViewPatch.java
Only solution that I found and was fully working.

I'm resurrecting this because I found a better solution for the problem of having a WebView over a gradient. Suppose you have a gradient like this and want to display an HTML string over it in white color that looks something like this:
<p>Integer semper, est imperdiet mattis porttitor, massa vulputate ipsum</p>
The trick is to convert your gradient to Base64 string:
iVBORw0KGgoAAAANSUhEUgAAAAEAAAHDCAYAAADlQnCCAAAAq0lEQVRIib2VwRWAMAhDaSdwCtd1No8uUzzp0ydBgjwvnmhCPrTKtKxbb73NXcaQLiL5j/olyhQH5JXu4H4sUGyWHAIa9VWjU9qtyAh6JGicIMJno2HcGSX3gJsCKH5EfUfHJUed+qFzekrpuVzM/oq4uFKGr/pI4B7wiP2Vgno0F/uCUQ9ZXWg4vM/JL1Hpt10Nt+hZjhCDKepxV8H3soZGWOqHP3ZSGYDdATTkg3iGU3JnAAAAAElFTkSuQmCC
Since WebView loads any HTML string, this can involve <body> that has a background. In my instance, the WebView was not occupying the whole space with the gradient, so I had to position the background as well. Following is the HTML I added to the HTML string above at the beggining:
<html>
<head>
</head>
<body style="margin: 0px; padding: 0px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAHDCAYAAADlQnCCAAAAq0lEQVRIib2VwRWAMAhDaSdwCtd1No8uUzzp0ydBgjwvnmhCPrTKtKxbb73NXcaQLiL5j/olyhQH5JXu4H4sUGyWHAIa9VWjU9qtyAh6JGicIMJno2HcGSX3gJsCKH5EfUfHJUed+qFzekrpuVzM/oq4uFKGr/pI4B7wiP2Vgno0F/uCUQ9ZXWg4vM/JL1Hpt10Nt+hZjhCDKepxV8H3soZGWOqHP3ZSGYDdATTkg3iGU3JnAAAAAElFTkSuQmCC); background-repeat: repeat-x; background-position: 0 -152px;">
<span style="font-family: Arial; font-size: 12px; color: white; display: block; margin:0px;">
And at the end:
</span></body></html>
Therefore producing such code:
String desc = "<html><head></head><body style=\"margin: 0px; padding: 0px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAHDCAYAAADlQnCCAAAAq0lEQVRIib2VwRWAMAhDaSdwCtd1No8uUzzp0ydBgjwvnmhCPrTKtKxbb73NXcaQLiL5j/olyhQH5JXu4H4sUGyWHAIa9VWjU9qtyAh6JGicIMJno2HcGSX3gJsCKH5EfUfHJUed+qFzekrpuVzM/oq4uFKGr/pI4B7wiP2Vgno0F/uCUQ9ZXWg4vM/JL1Hpt10Nt+hZjhCDKepxV8H3soZGWOqHP3ZSGYDdATTkg3iGU3JnAAAAAElFTkSuQmCC); background-repeat: repeat-x; background-position: 0 -152px;\"><span style=\"font-family: Arial; font-size: 12px; color: white; display: block; margin:0px;\">" + description + "</span></body></html>";
wv_desc.getEngine().loadContent(desc);
You could probably put the styles in the <head> or load them some other way for clarity I suppose, but this is a much better work-around to anything else I found on the net for this issue.

Related

Cannot get #CssImport to apply only to component scope

I have been wasted hours and days trying to style the Vaadin Upload component. The goal is simple:
sometimes I need the component to show the uploaded file using its built-in file list with allows delete.
other times, I want to hide this list because I have another component such as Grid to show the file details.
Now comes the problem, I can never get it to consistently work using #CssImport with themeFor=vaadin-upload and themeFor=vaadin-upload-file. Vaadin seems to compile the shadow dom and the final result varies, it mixes up the two options and whichever comes last gets applied.
I then thought maybe because the #CssImport is in the #Route component. So, I created two custom upload components that extended the vaadin-upload component with the difference being the different #CssImport (see below). That (frustratingly) still doesn't work. I inspect the document and found that the inside the shadow-dom contains both even though I never use both on the same page.
#CssImport(value = "./css/vaadin-upload-show.css", themeFor = "vaadin-upload")
public class UploadShowFiles extends Upload {
private static final long serialVersionUID = -9198630843136885092L;
public UploadShowFiles(Receiver receiver) {
super(receiver);
}
}
#CssImport(value = "./css/vaadin-upload-hidefile.css", themeFor = "vaadin-upload")
public class UploadHideFiles extends Upload {
private static final long serialVersionUID = 2344860066834705807L;
public UploadHideFiles(Receiver receiver) {
super(receiver);
setClassName("hide-upload");
}
}
The css below will appear in the shadow dom. I expect only display: none or otherwise, not both.
[name="file-list"] {
display: none !important;
height: 0px !important;
}
[name="file-list"] div[part="file-list"] {
display: none !important;
}
[name="file-list"] {
display: block !important;
height: 1.5rem !important;
}
[name="file-list"] div[part="file-list"] {
display: block !important;
}
p/s: This is my first experience using Vaadin in a project and I probably never going to use it again. Customizing anything in Vaadin is so time-consuming and painful.
Styling in the shadow DOM can indeed be tricky. The simplified theming in Vaadin 19 helps a bit.
Where the #CssImport annotation is placed affects if the CSS should be included in the document, but not which components it affects. With themeFor, it will always be applied to all matching components.
What you can do is to use the :host selector to limit which upload components it applies to. Here I am using a class-based approach:
:host(.no-file-list) [name="file-list"] {
display: none !important;
height: 0px !important;
}
:host(.no-file-list) [name="file-list"] div[part="file-list"] {
display: none !important;
}
I can then hide the file list in an upload component by adding a class:
#Route
#CssImport(value = "./styles/upload-style.css", themeFor = "vaadin-upload")
public class FileUploadTest extends VerticalLayout {
public FileUploadTest() {
Upload uploadWithFileList = new Upload();
Upload uploadWithoutFileList = new Upload();
uploadWithoutFileList.addClassName("no-file-list");
add(uploadWithFileList, uploadWithoutFileList);
}
}

Can I style the top-level form in Designer preview?

In Qt Designer, I've set a default print/preview stylesheet in the Preferences, to match the stylesheet of the application that will contain my UIs. When previewing, all of the contained widgets are styled correctly, but my top-level form isn't. Why? And what can I do?
For example, using this stylesheet:
MyFormBase
{ background: black; color: white; }
QLabel
{ background: transparent; color: yellow; }
and a UI structure like
MyForm form (subclass of MyFormBase)
QLabel label
The label has yellow text, but it's displayed on Designer's default (grey) background.
When the Designer creates a preview, it constructs a plain QWidget as the top level window. So any style applied using the class name of the top-level form doesn't match.
Examination of Designer's internals shows that it applies a property to mark the top-level window; we can select using that to style the top-level form:
[_q_custom_style_disabled="true"], /* for preview in Designer */
MyFormBase
{ background: black; color: white; }
QLabel
{ background: transparent; color: yellow; }
Note that the _q_custom_style_disabled property is not a documented feature of Designer, so it may be subject to change without warning.
If you have many selectors that depend on top widget (e.g. if you have MyFormBase > QLabel), or if you're concerned about the hack above, you might want to apply a custom property:
[role~=Page"]
{ background: black; color: white; }
[role~=Page"] > QLabel
{ background: transparent; color: yellow; }
Obviously, you then have to remember to apply the property to the topmost widget on each of your forms!

How to use extra space after tabs in tabsheet

i am new to vaadin , i created tabsheet with two tabs one with graphs and another with some info, my problem was how to add components(combobox, labels) at right corner(same row) of the tabs.
final TabSheet tabSheet = new TabSheet();
tabSheet.setSizeFull();
tabSheet.addTab(rightAndLowerPanels, "Graphs");
tabSheet.addTab(new Label("<b>Haiiiiiiiiiiiii</b>", ContentMode.HTML), "Message");
Ex;
tab1|tab2
I want to add here
i am not able to post image for this problem.
Thanks in advance
While the component itself doesn't support this, it is possible to accomplish this with setting the components absolute position with css so it hovers over the tabsheet in the correct position.
The div(layout) that contains the tabseet and the hovering component should be set position: relative; so that the absolute position is set from the corner of the component not the browser and then set the combobox's position to something like this: position:absolute; right: 3px; top: 3px;.
You can even use Vaadin's AbsoluteLayout or CssLayout if you want to add some checks for determining the components position.
AbsoluteLayout al = new AbsoluteLayout();
al.addStyleName("tab-sheet-layout"); // position: relative;
al.addComponent(new TabSheet(new Label("1"),new Label("2")));
al.addComponent(new ComboBox(), "right: 5px; top: 5px;");
or with CssLayout:
public static class TabSheetLayout extends CssLayout {
public TabSheetLayout() {
addStyleName("tab-sheet-layout"); // position: relative;
addComponent(new TabSheet(new Label("1"),new Label("2")));
addComponent(new ComboBox());
}
#Override
protected String getCss(Component c) {
if (c instanceof ComboBox) { // do some check here
return "position:absolute; right: 3px; top: 3px;";
}
return null;
}
}
You should note however that if you resize the screen small enough, the combobox will be hovering over the tabs, so you need to stop this by fixing the layout width or by some other method.

jquery mobile - forcing panel open on wider screens

I've been trying to test my jquery mobile app on multiple devices. I currently have a panel that is opened via swipe or clicking on a 'menu' button.
However, on wide screens, the app just looks funky. WAY too wide. I understand this is meant for mobile, but, why not format it for ipads/surface/androids as well?
To do this, I'd like to shorten the width by requiring the panel to be open at all times when the width exceeds a specific value.
I've dug through the documentation, and the closest thing I found was:
class="ui-responsive-panel" from the following link: http://view.jquerymobile.com/master/docs/widgets/panels/panel-fixed.php
After adding it to my page header, I noticed that I can't 'swipe' the menu away when the window is wide. When I shrink the window (either on a pc browser, or by rotating the device), it can be swiped.
Is anyone familiar with this, and willing to shed some light?
I'm facing the same problem. I want the panel to stay open when the user turns the device in landscape mode (tablets) or if the window is wider than a specific width at the very beginning.
Unfortunately I did not find any solutions and the jQuery Mobilele example for responsive panels in this case.
So I found a way by using some javascript but I'm not happy with this solutions since a pure CSS solution with media queries would be nicer.
However, here is my "workaround" solution.
<script type="text/javascript">
window.onresize = function (event) {
if (window.innerWidth > 800) {
window.setTimeout(openPanel, 1);
}
if (window.innerWidth < 800) {
window.setTimeout(closePanel, 1);
}
};
function closePanel() {
$("#mypanel").panel("close");
}
function openPanel() {
$("#mypanel").panel("open");
}
$( "#mypanel" ).on( "panelcreate", function( event, ui ) {
if (window.innerWidth > 800) {
openPanel();
}
if (window.innerWidth < 800) {
closePanel();
}
});
</script>
So if the window inner width is higher than 800, the panel opens; if it is lower than 800 it closes. Furthermore the window.onresize function is required to provide the same functionality in case the user turns the device from portrait mode to landscape mode.
Hope it helped. But I'm still looking for a better solution ;)
I found a css-only solution for that issue that is much simpler.
In the media query for your responsive panel #media (min-width:55em){...} add/overwrite the following css classes:
.ui-panel-closed { width: 17em; }
.ui-panel-content-wrap.ui-body-c.ui-panel-animate.ui-panel-content-wrap-closed{ margin-left:17em; }
The second class might be different to yours depending on the swatch you are using; in this case it is "C". However, just take the content wrap class that wraps all your header,content, footer area.
In my example I used a panel with data-display="reveal" data-position="left" If you want it appearing on the right hand side just change margin-left:17em to margin-right:17em
If you want the panel to behave like "overlay", just forget about the second class i posted...
Best regards
I am facing the problem right now and I found the solution of mJay really useful. However it would be great to use media queries instead, something like this perhaps:
#media (min-width:35em){
.ui-panel{
width:30em;
}
.ui-panel-close { width:30em; }
}
Below is my "CSS" solution. What you need to know: mnuMenu is the id of the panel that I want to always have visible on the left side of the screen and lnkMenu is the id of the a tag for the button which normally shows the panel on smaller screen widths.
#media all and (min-width: 900px)
{
#mnuMenu
{
visibility: visible;
position: fixed;
left: 0;
float: left;
width: 300px;
height: 100vh;
background: none;
-webkit-transition: none !important;
-moz-transition: none !important;
transition: none !important;
-webkit-transform: none !important;
-moz-transform: none !important;
transform: none !important;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
#lnkMenu
{
display: none;
}
.ui-content
{
margin-left: 325px;
}
}

jquery mobile how remove the grey round circle on icon

I build my first phonegap Jquery Appl
Im changing my icon using this class
.ui-icon-myapp-email {
background-image: url("app-icon-email.png");
}
This custom icon is for a list view , and i try to remove the round grey background load
Also my picture is a bit big for the shape
I was playing with the .ui-icon but doesnt work
Cant find the class
I just wanna my custom arrow picture full size on a white background list no round no circle box shape
Maybe there is an attribute or via css to make that
thanks
If you are using jQuery v 1.4.0 + then you just need to add the class .ui-nodisc-icon to your link element to remove that annoying circle. You will not need to edit any css or write any overrides.
Late to the party here, but a simple answer is to add
background-color: transparent;
box-shadow: none;
to your custom class name, so:
.ui-icon-myapp-email {
background-color: transparent;
box-shadow: none;
}
is all you need.
With JQuery Mobile 1.3, now all you have to do is add the class "ui-nodisc-icon", no need to mess around with the CSS.
from JQuery Website:
"If you don’t need the dark circle behind the icons, simply add the ui-nodisc-icon to the element or its container to remove the icon background."
This should work.
.ui-icon-myapp-email {
background:transparent; /* or none */
background-image: url("app-icon-email.png");
/* The following border radius rules will override the circle around your icon */
-moz-border-radius: 0px;
-webkit-border-radius:0px;
border-radius:0px;
}
/* To fix the size issue override the .ui-icon height */
.ui-icon{
width:14px;
height:20px;
}
Overrides the icon disc color to white.
.ui-icon,
.ui-icon-searchfield:after {
background: #fff /*{global-icon-color}*/;
background: rgba(255,255,255,1) /*{global-icon-disc}*/;
background-image: url(images/icons-18-white.png) /*{global-icon-set}*/;
background-repeat: no-repeat;
-moz-border-radius: 9px;
-webkit-border-radius: 9px;
border-radius: 9px;
}
Icon size is specified in ui-icon class which defaults to 18px.
.ui-icon {
width: 19px;
height: 19px;
}
For those of you looking to have just an icon for the button - I found this article to be very useful! I followed the "Reset the button theme" and "Icon-only buttons" sections to get the effect that I needed.
http://appcropolis.com/blog/advanced-customization-jquery-mobile-buttons/
I solved this issue, using:
background-color:transparent;
if you want to add color in background you can use:
background: url(yourimage.png) repeat;

Resources