The Webkit Bridge Tutorial - Hybrid Client ApplicationIn this example, we will show how to write a hybrid application using QtWebKit Bridge, which distinguishes itself from a thin client in that it performs heavy calculations on the client side in C++, like a native application, but presents nothing more than a QWebView for its user interface, displaying web content written in HTML/JavaScript. The application uses QtConcurrent to distribute its work across as many CPU cores as are available from the system, so it can process each image in parallel. For the full reference documentation of QtWebKit hybrid development, see The QtWebKit Bridge. Initially, you will see a user interface with an empty list of images. Clicking on some of the images in the lower pane below adds them to the list view above, as shown in the screenshot below. [Missing image webkit-imageanalyzer-screenshot.png] Now, we can click on Analyze, and each image is analyzed using some computationally intensive C++ function, in parallel and on different cores. Progress is shown while the analysis is proceeding. [Missing image webkit-imageanalyzer-progress.png] and in the end, we will see something like this, where the average RGB values of each image are shown. [Missing image webkit-imageanalyzer-complete.png] The MainWindow is defined in C++, and creates a QNetworkDiskCache and a QWebView, and tells the QWebView to load the starting page, providing us with a user interface for the client. In this example, the sample content is addressed with the qrc:/index.html URL. qrc:/ indicates that the file is stored as a Qt resource (attached to the executable). In a real-world application, the content and images would likely be retrieved from the network rather than from resources. We wish to initialize an object reference in the JavaScript web page to point to our ImageAnalyzer before any other scripts are run. To do this, we connect the javaScriptWindowObjectCleared() signal to a slot which does the object creation and handoff to JavaScript. The ImageAnalyzer object is created and added to a JavaScript object on the web page's mainFrame with addToJavaScriptWindowObject(). The start page is resources/index.html. In one of its <div> regions, we have images, each with an onClick() handler that calls addImage(). Clicking an image adds it to an images list. The Analyze button at the bottom of the image list is clicked when we want to start the analysis: When the user clicks the Analyze button, analyzeImages() is called, another regular JavaScript method, shown below. Notice it assumes the imageAnalyzer object is already defined and initialized in JavaScript space, but we guaranteed that by connecting our setup slot to the appropriate signal, javaScriptWindowObjectCleared(). The only methods on ImageAnalyzer that we can or do call from JavaScript are those which are exposed through {The Meta-Object System}{Qt's MetaObject} system: property getter/setter methods, public signals and slots, and other Q_INVOKABLE functions. ... Most of the members are set up in the constructor: Back on the JavaScript side, we want to connect signals from this object to JavaScript functions on our web page, after the web page is loaded, but before the images are analyzed. From connectSlots(), we can see how to connect signals from the imageAnalyzer object to regular JavaScript functions, which can also behave like slots. We use this to monitor and display progress from the C++ side. The only public slot is startAnalysis(), called to place a list of URLs into the image analyzer's QtConcurrent processing queue from JavaScript space. The images need to be loaded again now, which is why fetchURLs first checks the cache to see if we can save an extra network get. For the images that were not in the cache, handleReply() will load them into a QImage when the data is ready. After the images are loaded, they are queued up in preparation to be sent in a batch for analysis to a QFutureWatcher, which will distribute the processing across multiple threads and cores, depending on how many are available. The function that gets performed on each image is averageRGB(), as specified in argument 2 to the QtConcurrent::mapped() function. Notice it repeats the same calculations 100 times on each pixel to keep the CPU very busy. This is done only for the purposes of the demo so that the analysis takes a noticeable time to complete. |