I have a very persistent problem with QTJambi and Webkit.
Here is what I want to do.
I want to load a web interface coded in an HTML file (it works), put some interactions between Javascript and Java (it works too), display the web interface with transparent background over another widget which displays images (a 2D game scenery) and it works too as long as the web interface is static.
Problems come when the web interface is changing (DOM and css manipulations). When it changes, the previous web view rendering is not cleared and the new rendering is painted over. So, I have such rendering :
I understand how it works : a rectangle with the background color is displayed to hide the previous rendering and display the new one over. But the background color is transparent. So it hides nothing.
I tried some solutions I found on the web with composition modes but it doesn't work. I have the same problem or a black screen.
Here is my code.
HTML file :
<html>
<head>
<meta charset="utf-8" />
<style>
#body
{
position: absolute;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
overflow: hidden;
}
#button
{
position: absolute;
left: 20px;
top: 20px;
background-color: rgba(255, 100, 100, 0.1);
padding: 10px;
box-shadow: 0px 2px 5px rgb(0, 0, 0);
border-radius: 5px;
}
#token
{
position: absolute;
left: 200px;
top: 20px;
background-color: rgba(100, 255, 100, 0.1);
padding: 10px;
box-shadow: 0px 2px 5px rgb(0, 0, 0);
border-radius: 5px;
}
#console
{
background-color: rgba(100, 100, 255, 0.1);
position: absolute;
left: 20px;
right: 20px;
top: 100px;
bottom: 20px;
padding: 10px;
overflow: auto;
}
</style>
</head>
<body>
<div id="button" >Appeler Java</div> <!-- Le bouton rouge qui appelle Java --> <!-- This red button calls Java -->
<div id="console" >Console. <br /></div> <!-- Le bloc bleu où on affiche les messages --> <!-- Messages are displayed in this blue block. -->
<div id="token" >Je bouge.</div> <!-- Le petit bloc vert qui bouge tout seul --> <!-- The moving green block. -->
<script type="text/javascript" >
// Fonction javascript appelée par Java au chargement de la page
// Java calls this Javascript function when the HTML file is loaded.
var fromJavaToJavascript = function()
{
document.getElementById("console").appendChild(document.createTextNode("J'ai été appelé par le Java. "));
document.getElementById("console").appendChild(document.createElement("br"));
};
// Mon image qui doit recevoir la QPixmap
//var qPixmap = new Image();
var readImage = function()
{
document.getElementById("console").appendChild(document.createTextNode("Je reçoit une image de java. " + qPixmap));
document.getElementById("console").appendChild(document.createElement("br"));
};
window.onload = function()
{
var count = 0;
// Fonction qui appelle Java et déclenchée par le bouton rouge
// When the red button is clicked, it calls this javascript function which calls a Java function.
document.getElementById("button").onclick = function()
{
count++;
// On affiche l'incrément dans le bouton rouge
// Text in red button is updated.
while (document.getElementById("button").firstChild)
document.getElementById("button").removeChild(document.getElementById("button").firstChild);
document.getElementById("button").appendChild(document.createTextNode("Appeler Java " + count));
// On affiche un message dans le bloc bleu
// New message is displayed in the blue block.
document.getElementById("console").appendChild(document.createTextNode("Je dois appeler le Java. " + javaObject));
document.getElementById("console").appendChild(document.createElement("br"));
// On appelle Java
// Call Java.
javaObject.submit();
};
var initPos = 20;
// Le bloc vert bouge tout seul.
// The green block is moving.
var timer = setInterval(function()
{
initPos = initPos + 5;
document.getElementById("token").style.top = initPos + "px";
}, 500);
};
</script>
</body>
</html>
Main frame :
public class WebBrowserTestFrame extends QMainWindow
{
protected QGraphicsView view;
protected QGraphicsScene scene;
protected WebBrowserTestQWebView browser;
protected QGridLayout gridLayout;
public WebBrowserTestFrame()
{
this.gridLayout = new QGridLayout();
// Le widget où on affiche une image
// This widget displays an image
this.scene = new QGraphicsScene();
QPixmap image = new QPixmap("resources/tests/Coin-coin.jpg");
this.scene.addPixmap(image);
this.view = new QGraphicsView(scene);
// Le widget qui charge le fichier HTML
// This widget loads an HTML file
this.browser = new WebBrowserTestQWebView(this.view);
QPalette palette = this.browser.palette();
palette.setBrush(QPalette.ColorRole.Base, new QBrush(new QColor(Qt.GlobalColor.transparent)));
this.browser.setPalette(palette);
this.browser.setAttribute(Qt.WidgetAttribute.WA_OpaquePaintEvent, false);
// On superpose les 2 widgets
// The 2 widgets are stacked
this.gridLayout.addWidget(this.view, 0, 0);
this.gridLayout.addWidget(this.browser, 0, 0);
// On attache le tout à la fenêtre principale
// Widgets are appended to the main frame
QWidget widget = new QWidget();
widget.setLayout(this.gridLayout);
this.setCentralWidget(widget);
this.setWindowTitle("Hello WebKit");
// Evénements de la Web view
// Web view events
this.browser.loadStarted.connect(this, "loadStarted()");
this.browser.loadProgress.connect(this, "loadProgress(int)");
this.browser.loadFinished.connect(this, "loadDone()");
this.browser.urlChanged.connect(this, "urlChanged(QUrl)");
// On charge la page
// Load the HTML file
QApplication.invokeLater(new Runnable()
{
@Override
public void run()
{
File htmlFile = new File("resources/interfaces/javascript/test.html");
if (htmlFile.exists())
browser.load(new QUrl("file://" + htmlFile.getAbsolutePath()));
else
System.out.println("Le fichier n'existe pas");
}
});
}
public void loadStarted()
{
System.out.println("Load started");
}
public void loadDone()
{
WebBrowserTestJavascript javascript = new WebBrowserTestJavascript();
this.browser.page().mainFrame().addToJavaScriptWindowObject("javaObject", javascript);
this.browser.page().mainFrame().evaluateJavaScript("fromJavaToJavascript()");
}
public void loadProgress(int x)
{
System.out.println("Loading: " + x + " %");
}
public void urlChanged(QUrl url)
{
System.out.println("Url changed : " + url);
}
}
Class inherited from QWebView :
public class WebBrowserTestQWebView extends QWebView
{
@Override
public void paintEvent(QPaintEvent event)
{
// On tente d'effacer l'ancien affichage de la web view et c'est là que ça coince.
// Clears the previous web view rendering and here is the problem
QPainter painter = new QPainter(this);
painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_Source);
painter.fillRect(event.rect(), Qt.GlobalColor.transparent);
painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_SourceOver);
super.paintEvent(event);
}
}
Thank you in advance. :)
I finally found the solution on my own. It was really simple. ^^'
I removed the code which set the web view background to transparent from the WebBrowserTestFrame class and put it in the paintEvent method of the WebBrowserTestQWebView class. Like this :
And it works for me ! :D
Here is finally the expected rendering