Well, Here I have a screen which I want to get close after 2-3 Seconds. For that I am using setDate() method.
I am very new to this Blackberry Cascade QML programming. I want to attach 1 more splash screen, so for that reason I want to use timer to close and open the sheet according to seconds.
Any help will be appreciated.
Thanks in advance.
I have worked on the following code.
import bb.cascades 1.0
import bb.cascades.pickers 1.0
Page
{
Container
{
background: Color.Transparent
//Todo: fill me with QML
onCreationCompleted:
{
mysheet1.open();
new Date();
**Error is shown in for loop**
for(Date.setSeconds(1),Date.setSeconds()<=5 , Date.setSeconds()+1)
{
if(Date == 5)
{
mysheet1.closed();
mysheet2.open();
}
}
}
attachedObjects:
[
Sheet
{
id: mysheet1
peekEnabled: false
Page
{
Container
{
background: Color.Transparent
ImageView
{
horizontalAlignment: HorizontalAlignment.Fill
verticalAlignment: VerticalAlignment.Fill
imageSource: "asset:///splash1.png"
}
}
}
}
]
}
Context Invokable: Date Date(...)
The Date object is used to work with dates and times.
Date objects are created with the new Date() constructor.
There are four ways of initiating a date:
new Date() // current date and time (or)
new Date(milliseconds) //milliseconds since 1970/01/01 (or)
new Date(dateString) (or)
new Date(year, month, day, hours, minutes, seconds, milliseconds)
Invokable: number setSeconds(number sec)
Sets the seconds of a date object.
It will use a lot of process for some seconds. But there is no setInterval in QML.
The best solution is using a C++ class, TimeManager.cpp with a QTimer:
To expose the C++ method to QML you can register as a ContextProperty when the QML is instanciated:
QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(this);
qml->setContextProperty("TimeManager", new TimeManager());
And declare the method:
Q_INVOKABLE void callLater(int milliSeconds, QObject* sloter);
The implementation:
void TimeManager::callLater(int milliSeconds, QObject* sloter){
QTimer::singleShot(milliSeconds, sloter, SLOT(timerEnd()));
}
And the QML:
onCreationCompleted: {
TimeManager.callLater(2500, this);
}
onTimerEnd: {
mysheet1.closed();
}
Here is sample code of Timer.
import bb.cascades 1.0
import my.timer 1.0
Page {
Container {
layout: DockLayout {
}
onCreationCompleted: {
mTimer.start();
}
ImageView {
id: mImageViewIcon
horizontalAlignment: HorizontalAlignment.Fill
verticalAlignment: VerticalAlignment.Fill
imageSource: "asset:///images/splash.png"
}
attachedObjects: [
QTimer {
id: mTimer
interval: 2000
onTimeout: {
//Push New Page here
}
}
]
}
}
Don't forgot to add below line in main.cpp
qmlRegisterType<QTimer>("my.timer", 1, 0, "QTimer");
Related
The below code is for Jetbrains Desktop Compose. It shows a card with a button on it, right now if you click the card "clicked card" will be echoed to console. If you click the button it will echo "Clicked button"
However, I'm looking for a way for the card to detect the click on the button. I'd like to do this without changing the button so the button doesn't need to know about the card it's on. I wish to do this so the card knows something on it's surface is handled and for example show a differently colored border..
The desired result is that when you click on the button the log will echo both the "Card clicked" and "Button clicked" lines. I understand why mouseClickable isn't called, button declares the click handled. So I'm expecting that I'd need to use another mouse method than mouseClickable. But I can't for the life of me figure out what I should be using.
#OptIn(ExperimentalComposeUiApi::class, androidx.compose.foundation.ExperimentalDesktopApi::class)
#Composable
fun example() {
Card(
modifier = Modifier
.width(150.dp).height(64.dp)
.mouseClickable { println("Clicked card") }
) {
Column {
Button({ println("Clicked button")}) { Text("Click me") }
}
}
}
When button finds tap event, it marks it as consumed, which prevents other views from receiving it. This is done with consumeDownChange(), you can see detectTapAndPress method where this is done with Button here
To override the default behaviour, you had to reimplement some of gesture tracking. List of changes comparing to system detectTapAndPress:
I use awaitFirstDown(requireUnconsumed = false) instead of default requireUnconsumed = true to make sure we get even a consumed even
I use my own waitForUpOrCancellationInitial instead of waitForUpOrCancellation: here I use awaitPointerEvent(PointerEventPass.Initial) instead of awaitPointerEvent(PointerEventPass.Main), in order to get the event even if an other view will get it.
Remove up.consumeDownChange() to allow the button to process the touch.
Final code:
suspend fun PointerInputScope.detectTapAndPressUnconsumed(
onPress: suspend PressGestureScope.(Offset) -> Unit = NoPressGesture,
onTap: ((Offset) -> Unit)? = null
) {
val pressScope = PressGestureScopeImpl(this)
forEachGesture {
coroutineScope {
pressScope.reset()
awaitPointerEventScope {
val down = awaitFirstDown(requireUnconsumed = false).also { it.consumeDownChange() }
if (onPress !== NoPressGesture) {
launch { pressScope.onPress(down.position) }
}
val up = waitForUpOrCancellationInitial()
if (up == null) {
pressScope.cancel() // tap-up was canceled
} else {
pressScope.release()
onTap?.invoke(up.position)
}
}
}
}
}
suspend fun AwaitPointerEventScope.waitForUpOrCancellationInitial(): PointerInputChange? {
while (true) {
val event = awaitPointerEvent(PointerEventPass.Initial)
if (event.changes.fastAll { it.changedToUp() }) {
// All pointers are up
return event.changes[0]
}
if (event.changes.fastAny { it.consumed.downChange || it.isOutOfBounds(size) }) {
return null // Canceled
}
// Check for cancel by position consumption. We can look on the Final pass of the
// existing pointer event because it comes after the Main pass we checked above.
val consumeCheck = awaitPointerEvent(PointerEventPass.Final)
if (consumeCheck.changes.fastAny { it.positionChangeConsumed() }) {
return null
}
}
}
P.S. you need to add implementation("androidx.compose.ui:ui-util:$compose_version") for Android Compose or implementation(compose("org.jetbrains.compose.ui:ui-util")) for Desktop Compose into your build.gradle.kts to use fastAll/fastAny.
Usage:
Card(
modifier = Modifier
.width(150.dp).height(64.dp)
.clickable { }
.pointerInput(Unit) {
detectTapAndPressUnconsumed(onTap = {
println("tap")
})
}
) {
Column {
Button({ println("Clicked button") }) { Text("Click me") }
}
}
I would like to add toggle visibility on click to a node in a Highcharts Organisation chart (Highcharts).
Is there a built in support for this?
This feature is not available from regular Highcharts API, however I created an example/guideline how to implement it by yourself.
First, you need to hide points after initial load in the events.load callback:
Code:
events: {
load() {
//hide nodes after initial load
let chart = this,
nodes = chart.series[0].nodeLookup;
for (let i in nodes) {
if (nodes[i].column > 2) {
nodes[i].graphic.hide();
nodes[i].dataLabel.hide();
nodes[i].linksTo[0].graphic.hide();
nodes[i].visible = false;
}
}
}
}
API to load event: https://api.highcharts.com/highcharts/chart.events.load
Next, you need to implement logic to show wanted nodes after click event on point. You can improve this logic and code as an independent function which will be trigger inside the point.events.click callback.
Code:
events: {
click() {
//show nodes
let series = this.series,
nodes = series.nodeLookup;
for (let i in nodes) {
if (nodes[i].linksTo.length && nodes[i].linksTo[0].from === "CEO") {
if (nodes[i].visible) {
nodes[i].graphic.hide()
nodes[i].dataLabel.hide();
nodes[i].visible = false;
} else {
nodes[i].graphic.show()
nodes[i].dataLabel.show();
nodes[i].visible = true;
}
}
}
this.linksFrom.forEach(link => {
if (link.graphic.visibility == "visible") {
link.graphic.hide()
} else {
link.graphic.show()
}
})
}
}
API: https://api.highcharts.com/highcharts/series.organization.data.events.click
Demo: https://jsfiddle.net/BlackLabel/b5nxv6k9/ - click on the CEO point to see how it work.
To my great surprise Lightbox2(http://lokeshdhakar.com/projects/lightbox2/) does not support swipe gestures out of the box...
I was not able to find any add on in order to support this behavior. Anyone has any suggestions a side from changing the entire plugin? :)
To summary, you must hide the navigation buttons and implement swiping, moving and sliding effect on the image.
You will need :
jquery.event.move
jquery.event.swipe
jquery ui slide effect, you can package it in the jquery ui download builder
maybe there's a simplest way to get/implement all of these 3 small dependencies... but that way works for me.
in the lightbox script, add a new LightboxOptions enableSwipeOnTouchDevices and set it to true :
this.enableSwipeOnTouchDevices = true;
add the following blocks after the this.$lightbox.find('.lb-next').on('click'... block to create the swiping events:
this.$lightbox.find('.lb-image').on("swiperight",function() {
$('.lb-image').effect("slide", { "direction" : "right", "mode" : "hide"} ,function(){
if (self.currentImageIndex === 0) {
self.changeImage(self.album.length - 1);
} else {
self.changeImage(self.currentImageIndex - 1);
}
})
});
this.$lightbox.find('.lb-image').on("swipeleft",function() {
$('.lb-image').effect("slide", { "direction" : "left", "mode" : "hide"} ,function(){
if (self.currentImageIndex === self.album.length - 1) {
self.changeImage(0);
} else {
self.changeImage(self.currentImageIndex + 1);
}
})
});
and rewrite the updateNav function like this to hide the navigation buttons:
Lightbox.prototype.updateNav = function() {
// Check to see if the browser supports touch events. If so, we take the conservative approach
// and assume that mouse hover events are not supported and always show prev/next navigation
// arrows in image sets.
var alwaysShowNav = false;
var enableSwipe = false;
try {
document.createEvent("TouchEvent");
alwaysShowNav = (this.options.alwaysShowNavOnTouchDevices)? true: false;
enableSwipe = (this.options.enableSwipeOnTouchDevices)? true: false;
} catch (e) {}
//if swiping is enable, hide the two navigation buttons
if (! enableSwipe) {
this.$lightbox.find('.lb-nav').show();
if (this.album.length > 1) {
if (this.options.wrapAround) {
if (alwaysShowNav) {
this.$lightbox.find('.lb-prev, .lb-next').css('opacity', '1');
}
this.$lightbox.find('.lb-prev, .lb-next').show();
} else {
if (this.currentImageIndex > 0) {
this.$lightbox.find('.lb-prev').show();
if (alwaysShowNav) {
this.$lightbox.find('.lb-prev').css('opacity', '1');
}
}
if (this.currentImageIndex < this.album.length - 1) {
this.$lightbox.find('.lb-next').show();
if (alwaysShowNav) {
this.$lightbox.find('.lb-next').css('opacity', '1');
}
}
}
}
}
};
I've used jquery mobile to detect swipeleft and swiperight. Then bind them to click .lb-next and .lb-prev. It's working now.
Here is my codepen.
PEC's solution worked for me with one modification on a Jekyll site.
Instead of:
this.enableSwipeOnTouchDevices = true;
We added this to /_includes/scripts.html after the dependencies and lightbox.js:
<script>
lightbox.option({
'enableSwipeOnTouchDevices': true,
})
</script>
The PEC solution is good, but it doesn't work anymore with the current version of lightbox (2.11.2). The effect() method doesn't exists anymore.
So the swiping methods should be updated:
this.$lightbox.find('.lb-image').on("swiperight",function() {
if (self.currentImageIndex === 0) {
self.changeImage(self.album.length - 1);
} else {
self.changeImage(self.currentImageIndex - 1);
}
return false;
});
this.$lightbox.find('.lb-image').on("swipeleft",function() {
if (self.currentImageIndex === self.album.length - 1) {
self.changeImage(0);
} else {
self.changeImage(self.currentImageIndex + 1);
}
return false;
});
Less fancy, but shorter and works.
In short: 'catch' swipe gesture and then trigger 'click' on next/prev button based on swipe direction.
let touchstartX = 0;
let touchendX = 0;
function handleGesture() {
if (touchendX < touchstartX) $(".lb-prev").trigger("click");
if (touchendX > touchstartX) $(".lb-next").trigger("click");
}
$(document).on("touchstart", ".lb-nav", e => {
touchstartX = e.changedTouches[0].screenX;
});
$(document).on("touchend", ".lb-nav", e => {
touchendX = e.changedTouches[0].screenX;
handleGesture();
});
I am using JQPlot trying to draw a graph which contains dates. But I cant able to draw the graph, but i tried the sample application it is working fine. But whenever i pass my array it is not working, can anyone please help what i am doing wrong? Below is the code i am using.
$.get("${contextPath}/qos/graphJQPlot", $("#qosForm").serialize()).done(function(content) {
$.each(content, function (index1, value1) {
var innerArray = [];
$.each(value1, function (index2, value2) {
innerArray.push(value2, index2);
console.log(index2);
console.log(value2);
})
outerArray.push(innerArray);
})
var line1=[['2008-09-30 4:00PM',4], ['2008-10-30 4:00PM',6.5], ['2008-11-30 4:00PM',5.7], ['2008-12-30 4:00PM',9], ['2009-01-30 4:00PM',8.2]];
var plot3 = $.jqplot('chartdiv', [outerArray],
{
title:'Line Style Options',
axes:{
xaxis:{
renderer:$.jqplot.DateAxisRenderer,
tickOptions:{formatString:'%b %#d, %y'}/* ,
min:'2013-09-14',
max:'2013-09-21',
tickInterval:'1 day' */
/* ,
tickOptions:{formatString:'%b %#d, %Y'},
*/
}
}
}
);
});
If i pause an line1 to jqPlot it is working fine, but if i pass an outerArray it is not working.
Don't forget to include jqplot.dateAxisRenderer.js plugins
Is there a way to customize jQuery UI spinner, so that A-Z letters (or any custom range) is possible?
Yes, this is possible. Here's a simple example using A-Z, adapted from the provided time example:
$.widget("ui.alphaspinner", $.ui.spinner, {
options: {
min: 65,
max: 90
},
_parse: function(value) {
if (typeof value === "string") {
return value.charCodeAt(0);
}
return value;
},
_format: function(value) {
return String.fromCharCode(value);
}
});
Usage:
$("#my-input").alphaspinner();
Example: http://jsfiddle.net/4nwTc/1/
The above example creates a new widget called alphaspinner that inherits from spinner. You can do this for just one spinner with the following:
$(function() {
var spinner = $("#alpha-spinner").spinner({
min: 65,
max: 90
}).data("spinner");
spinner._parse = function (value) {
if (typeof value === "string") {
return value.charCodeAt(0);
}
return value;
};
spinner._format = function (value) {
return String.fromCharCode(value);
}
});
Example: http://jsfiddle.net/4nwTc/2/
I built up on Andrews code and built a spinner widget that takes a string array for input.
You can see the solution here.