Pass data from QML WorkerScript.sendMessage call through message signal - qml

I want to create a QML WorkerScript object dynamically and read the output from its function in my JavaScript code. Here's what I'm trying in my QML file:
import QtQuick 2.0
Rectangle {
id: root
width: 200
height: 300
Component.onCompleted: {
var worker = Qt.createQmlObject('import QtQuick 2.0; WorkerScript { source: "dataloader.js"; }', root)
worker.sendMessage();
worker.message.connect(function (msg) { console.log(msg); });
}
}
And here's the source of the dataloader.js file:
WorkerScript.onMessage = function(msg) {
WorkerScript.sendMessage('test');
}
I would like the code to output "test" to the console but it outputs "QVariant(QQmlV4Handle)" instead. I see in some examples on the Qt site (http://doc.qt.io/qt-5/qml-workerscript.html and http://doc.qt.io/qt-5/qtquick-threading-example.html#workerscript) that there is a messageObject property but that doesn't seem to be accessible from the connect function when I try to access it with worker.messageObject. Can anyone point me in the right direction here?

I don't know why it works this way but I got the functionality I wanted by catching the message signal in the WorkerScript object and emitting the messageObject to a new signal that I added to the object. Here's a code sample (dataloader.js stays the same):
var worker = Qt.createQmlObject('import QtQuick 2.0;
WorkerScript {
signal loaded(var value);
source: "dataloader.js";
onMessage: { loaded(messageObject); }
}', root)
worker.loaded.connect(function (value) { console.log(value); });
worker.sendMessage();

Related

Error in callback for watcher “get_settings”: “TypeError: Cannot read property ‘general’ of undefined”

Please help me out, how to handle this error i cant seem to handle this out as i am new to vue.
what im doing is getting data from server in store vuex with action. Now in component im accessing that data with getter in computed property and trying to watch that property but on component mount i get that error in console but functionality works fine.
data: function() {
return {
settings_flags :{
general: 0,
privacy: 0,
layouts: 0,
message: 0
}
}
}
1: mounting
mounted() {
let self = this;
self.userid = this.getUserId();
this.$store.dispatch('getGallerySettings',self.req);
self.initial_settings();
}
2: computed
computed: {
get_settings() {
return this.$store.getters.getGallerySettings;
}
}
3: watch
watch: {
'get_settings': {
deep: true,
handler() {
let self =this;
if (this.$_.isMatch(self.get_settings.gallery_settings.general,self.initialSettings.gallery_settings.general) == false) {
self.settings_flags.general = 1;
} else {
self.settings_flags.general = 0;
}
}
}
}
It seems to me that your watcher is looking for a property 'general' that is a child of gallery_settings.
get_settings.gallery_settings.general
In the meantime in data you have a property general that is a child of 'settings_flags'. Those two don't line up. So make sure that either your watcher is looking for something that exists when the component starts up, or tell your watcher to only start watching ' get_settings.gallery_settings.general' when 'get_settings.gallery_settings' actually exists.
if (get_settings.gallery_settings) { do something } #pseudocode
I'm not sure that's your problem, but it might be.

How to implement minDimensions in Uploadcare Widget

Settings can be added to Uploadcare as follows:
var myDialog = uploadcare.openDialog(null, {
imagesOnly: true,
multiple: true,
multipleMin: 1
multipleMax: 7
});
Now how is minDimensions being set? The documentation shows minDimensions(800x600) but that notation doesn't work. The below attempt does not work:
var myDialog = uploadcare.openDialog(null, {
imagesOnly: true,
multiple: true,
multipleMin: 1
multipleMax: 7,
minDimensions: '800,600'
});
Following doesn't work either:
var myDialog = uploadcare.openDialog(null, {
imagesOnly: true,
multiple: true,
multipleMin: 1
multipleMax: 7,
minWidth: 800,
minHeight: 600
});
Additionally, it's unclear what happens if an uploaded image dimenions is less than these settings. Does the Widget show an error?
minDimensions, as well as minWidth and minHeight, are not widget options. The link refers to file validation docs. File validation is a function that invokes before the file is completely uploaded, and have access to the fileInfo object so that you can check file parameters (size, name, image dimensions, etc.) and abort uploading if some parameter doesn't match your requirements.
To set an image dimension validator, you'd need to define a validation function first
function minDimensions(width, height) {
return function(fileInfo) {
var imageInfo = fileInfo.originalImageInfo;
if (imageInfo !== null) {
if (imageInfo.width < width || imageInfo.height < height) {
throw new Error('dimensions');
}
}
}
}
Then, when you open a dialog, you add the validation function to the validators array in the dialog settings
var myDialog = uploadcare.openDialog(null, {
imagesOnly: true,
multiple: true,
multipleMin: 1,
multipleMax: 7,
validators: [minDimensions(800, 600)]
});
If a file doesn't pass the validation, the widget will show the default error message - "Can't upload", but you can customize the error message using the UPLOADCARE_LOCALE_TRANSLATIONS option
UPLOADCARE_LOCALE_TRANSLATIONS = {
// messages for widget
errors: {
'dimensions': 'The image has to be 800x600px or larger.'
},
// messages for dialog’s error page
dialog: { tabs: { preview: { error: {
'dimensions': {
title: 'Error.',
text: 'The image is too small. Try to upload another one.',
back: 'Back'
}
} } } }
};
You need to define your own validator functions and add them to widget/dialog.
So, write minDimensions function with signature and logic of your choice.
The docs have example implementation for imagesOnly and maxDimenstions validation functions. You can use them for inspiration.
When your validation function rejects a file for some reason, you should throw Error, e.g. throw new Error('dimensions');
The 'dimensions' string will be used to look for a user friendly message in your custom localisation map:
UPLOADCARE_LOCALE_TRANSLATIONS = {
errors: {
'dimensions': 'File dimension check failed',
...
},
...
}
You can find more elaborate examples here.

Application crashing on creating a new object instance of ComponentDefinition Blackberry 10 Native

I am creating a new object instance of a ComponentDefinition using createObject() and then adding it to a container. My application crashes when it reaches the said line of code in QML.
Here is my code:
import bb.cascades 1.0
import Data.UpdateReservationView 1.0 //a custom C++ qmlRegisterType
Page {
property alias resDetails: updateRes.resDetails
attachedObjects: [
ComponentDefinition {
id: enhLabel
Label {
textStyle.fontSize: FontSize.PointValue
textStyle.fontSizeValue: 5.5
textStyle.color: Color.Black
}
},
UpdateReservationView {
id: updateRes
}
]
onResDetailsChanged: {
// some code
var newLabel = enhLabel.createObject(); //the app crashes upon reaching this line
newLabel.text = resDetails[i]["roomName"];
labelsContainer.add(newLabel);
}
ScrollView {
topMargin: 30.0
horizontalAlignment: HorizontalAlignment.Fill
Container{
leftPadding: 20.0
rightPadding: leftPadding
bottomPadding: 50.0
horizontalAlignment: HorizontalAlignment.Fill
Container {
id: labelsContainer
horizontalAlignment: HorizontalAlignment.Left
verticalAlignment: VerticalAlignment.Center
}
}
} //ScrollView ends
} //Page ends
I have tried using .load() instead of .createObject() but get the same result as the ComponentDefinition (enhLabel) is being instantiated elswhere in the code too, and according to my understanding .load() simply loads the control once whereas I require a new instance of it to be created multiple times dynamically.
The queer thing is that the code was running perfectly the day before and I've made no changes in this particular QML file.
What could be the reason for the application to crash. I am sure that it crashes upon reaching the var newLabel = enhLabel.createObject() line by using the old school console.debug() method.
Not sure what has changed on your side but according to the code sample on the BB developer site from what I can see your code looks ok:
Container {
Button {
text: "Click to create bordered text"
onClicked: {
// Creates borderedTextComponent control and appends it
// to the container
var createdControl = borderedTextComponent.createObject();
container.add(createdControl);
createdControl.textString = "Hello Component";
createdControl.padding = 30;
createdControl.textColor = Color.DarkGray;
}
}
Container {
id: container
}
attachedObjects: [
ComponentDefinition {
id: borderedTextComponent
Container {
property variant borderColor: Color.Red
property variant fillColor: Color.White
property variant textColor: Color.Black
property string textString
property real padding: 10;
background: borderColor
leftPadding: padding
rightPadding: padding
topPadding: padding
bottomPadding: padding
Container {
background: fillColor
Label {
text: textString
textStyle.color: textColor
}
}
}
}
]
}
Maybe try this sample to see whether you've got an environmental problem, this one worked for me inside a standard empty Cascades project and paste the code inside the Page{}.
Unfortunately too many things from your code are missing to reproduce the crash on my end.

How to access the outer components from listitemcomponents in listview bb10 qml?

I am not able to access the Datasource id from inside of the ListItemComponent. Can anyone help me in regards to this?
ListItemComponent {
type: "item"
Container {
id: listviewcontainer
Container {
preferredWidth: 768
layout: StackLayout {
orientation: LayoutOrientation.LeftToRight
}
CustomImageView {
leftPadding: 10
rightPadding: 10
url: ListItemData.from_image
horizontalAlignment: HorizontalAlignment.Left
verticalAlignment: VerticalAlignment.Center
}
Container {
preferredWidth: 538
layout: StackLayout {
orientation: LayoutOrientation.TopToBottom
}
Container {
layout: StackLayout {
orientation: LayoutOrientation.LeftToRight
}
Label {
text: ListItemData.from
textStyle {
base: SystemDefaults.TextStyles.TitleText
color: Color.create("#2db6ff")
}
}
ImageView {
imageSource: "asset:///Home/img.png"
verticalAlignment: VerticalAlignment.Center
}
}//Container
Label {
text: ListItemData.message
multiline: true
textStyle {
base: SystemDefaults.TextStyles.SubtitleText
}
content {
flags: TextContentFlag.Emoticons
}
}
Label {
id: time
text: ListItemData.time
textStyle {
base: SystemDefaults.TextStyles.SmallText
color: Color.create("#666666")
}
}
}//Container
ImageButton {
id: delete_btn
defaultImageSource: "asset:///Icon/delete.png"
pressedImageSource: "asset:///Icon/delete.png"
verticalAlignment: VerticalAlignment.Center
horizontalAlignment: HorizontalAlignment.Right
onClicked: {
deleteMessage(ListItemData.tid, ListItemData.uid);
}
function deleteMessage(tid, uid) {
var request = new XMLHttpRequest()
request.onreadystatechange = function() {
if (request.readyState == 4) {
var mResponse = request.responseText
mResponse = JSON.parse(mResponse)
var mResponseStatus = mResponse.response[0].receive.status;
var mMsg = mResponse.response[0].receive.message;
if (mResponseStatus == 1) {
msg_DataSource.source = "newurl.com" // This line not works here..
msg_DataSource.load(); // This line not works here..
} else if (mResponseStatus == 0) {
}
}
}// end function
request.open("GET", "myurl.com", true);
request.send();
}// deleteMessage
}//ImageButton
}//Container
}//Container
}//ListItemComponent
Here am not able to work out the following two lines
msg_DataSource.source = "newurl.com"
msg_DataSource.load();
I have tried like below but this also not working
listviewcontainer.ListItem.view.dataModel.message_DataSource.source = "myurl.com";
listviewcontainer.ListItem.view.dataModel.message_DataSource.load();
or this
listviewcontainer.ListItem.view.dataModel.source = "myurl.com";
listviewcontainer.ListItem.view.dataModel.load();
Another simplest way to store the object to global variable using the following code which works fine with me.
onCreationCompleted: {
Qt.tabbedPane = tabbedPane;
Qt.homeTab = homeTab;
}
Here I stored tabbedPane in global variable Qt.tabbedPane on page creation Completed.Now I able to access it from ListItemComponent using Qt.tabbedPane.
Hope it helps.
The simplest way to make the data model accessible would be to declare a property alias to your data model wherever it is defined, for example in your ListView QML file. This would make your data model accessible to the top level component in QML from this property alias. In effect, it gives you a global reference to your data model from anywhere else in QML.
For example, if you data model is called msg_DataSource, then in the QML file where it is defined you can create the property alias like this:
property alias myDataModel: msg_DataSource
Then in your ListItemComponent deleteMessage function, you can use myDataModel like this:
myDataModel.source = "newurl.com"
myDataModel.load();
Note: I am sure you could also do this in a more elegant way using signals and slots, but this way should be quicker and easier to understand.

3.5 Wordpress media uploader manual implementation

I'm having problems to understand how to implement new WP media uploader into my theme options page. Is there a documentation on how to do this or some explanation what-so-ever? I have seen couple of samples of how to do this but none of them has any good explanation about their code. Is there list of options how to customize media uploader frame? I mean wouldn't it be good if you can do something like this (See // Create the media frame.):
// Uploading files
var file_frame;
jQuery('.upload_image_button').live('click', function() {
// If the media frame already exists, reopen it.
if ( file_frame ) {
file_frame.open();
return;
}
// Create the media frame.
file_frame = wp.media.frames.file_frame = wp.media({
title: 'My frame title',
button: {
text: 'My button text',
},
id: 'logo-frame',
multiple: false,
editing_sidebar: false, // Just added for example
default_tab: 'upload', // Just added for example
tabs: 'upload, library', // Just added for example
returned_image_size: 'thumbnail' // Just added for example
});
// When an image is selected, run a callback.
file_frame.on( 'select', function() {
var attachment;
// We set multiple to false so only get one image from the uploader
attachment = file_frame.state().get('selection').first().toJSON();
// Do something with attachment.id and/or attachment.url here
});
// Finally, open the modal
file_frame.open();
return false
});
For WP 3.5, you can use the new media uploader. I'll be brief in the hopes that you know what you're doing. The idea is to call the wp_enqueue_script (this only works on WP >= 3.5 btw). Once the script is called, you can manipulate the javascript object. You'll have to do some inspecting to see your full set of options.
First you have to enqueue the script:
add_action( 'wp_enqueue_scripts', 'front_upload_enqueues' );
function front_upload_enqueues() {
wp_register_script('uploads',
// path to upload script
get_template_directory_uri().'/lib/js/media-upload.js'
);
wp_enqueue_script('uploads');
if ( function_exists('wp_enqueue_media') ) {
// this enqueues all the media upload stuff
wp_enqueue_media();
}
}
Then you have to add the javascript (jQuery in my case):
jQuery(document).ready(function($){
var frame;
/*
* Upload button click event, which builds the choose-from-library frame.
*
*/
$('.form-table').on('click', '.member-upload-field .btn-upload', function( event ) {
var $el = $(this);
event.preventDefault();
// Create the media frame.
frame = wp.media.frames.customHeader = wp.media({
title: $el.data('choose'),
library: { // remove these to show all
type: 'image', // specific mime
author: userSettings.uid // specific user-posted attachment
},
button: {
text: $el.data('update'), // button text
close: true // whether click closes
}
});
// When an image is selected, run a callback.
frame.on( 'select', function() {
// Grab the selected attachment.
var attachment = frame.state().get('selection').first(),
link = $el.data('updateLink');
$el.prev('input').val( attachment.attributes.id );
$el.parent().prev().find('img').attr('src', attachment.attributes.url );
});
frame.open();
});
});