I am Learning QML newly and am trying to resolve the following warning:
[warning] main.qml:392:25: Unable to assign [undefined] to double
main.qml
Rectangle{
id: rect
...
readonly property real scale0: (rotateRepeater.yPointM - rotateRepeater.yPointT) / height
readonly property real scale1: (rotateRepeater.yPointB - rotateRepeater.yPointM) / height
readonly property real yScale: [scale0, scale1][index] // Warning is in this line
}
The error is being show for property yScale.
Method 1 that I tried was -
readonly property real yScale: Binding {
when: onScale0Changed && onScale1Changed
yScale: [scale0, scale1][index]
}
and got the following error :
"cannot assign to non-existent property "yScale"
I tried Googling and found out two possible answers
-https://stackoverflow.com/questions/52290153/qml-unable-to-assign-undefined-to
-https://stackoverflow.com/questions/73306793/qml-failure-accessing-properties-with-error-unable-to-assign-undefined-to
but, I was unable to solve the warning.
Any help here is much appreciated.
Thanks in Advance.
Some further explorative testing is required for you to narrow down the cause of the undefined values. Here's one way how you can achieve further debugging:
Rectangle{
id: rect
...
readonly property real scale0: (rotateRepeater.yPointM - rotateRepeater.yPointT) / height
readonly property real scale1: (rotateRepeater.yPointB - rotateRepeater.yPointM) / height
readonly property real yScale: getYScale(scale0, scale1, index)
function getYScale(scale0, scale1, index) {
console.log("scale0: ", scale0, "scale1: ", scale1, "index: ", index);
return [scale0, scale1][index];
}
}
I made an assumption that I believe one of your inputs has an undefined value, and that undefined value was, possibly momentary. Doing the above code will not only help you see which parameter it is but, that function may get triggered multiple times so you can see it transition from an undefined state to a defined state. Then, you can build error handling in your function, e.g.
function getYScale(scale0, scale1, index) {
console.log("scale0: ", scale0, "scale1: ", scale1, "index: ", index);
if (scale0 === undefined) scale0 = 0;
if (scale1 === undefined) scale1 = 0;
if (index === undefined) index = 0;
let result = [scale0, scale1][index];
if (result === undefined) result = 0;
return result;
}
Doing the above actually has a lot of paranoid edge case handling, but, it should give you a deeper understanding of the intermediate values used in your property binding and help tailor a fix. Once you get the problem solved, you can discard the above function and incorporate the result back into a 1 line solution, perhaps something like:
Rectangle{
id: rect
...
readonly property real scale0: (rotateRepeater.yPointM - rotateRepeater.yPointT) / height
readonly property real scale1: (rotateRepeater.yPointB - rotateRepeater.yPointM) / height
readonly property real yScale: [scale0 ?? 0, scale1 ?? 0][index ?? 0] ?? 0
}
As I said above, you probably set incorrect index that is out of range. Check this code:
Item {
id: item
property int index: 0
property double value: [1.0, 2.0, 3.0][index]
onValueChanged: {
console.log(value)
}
Timer {
interval: 1000;
running: true;
repeat: true
onTriggered: item.index = Math.round(Math.random() * 3)
}
}
The output is possible will be:
qml: 1
qml: 3
qml: 2
main.qml:18:9: Unable to assign [undefined] to double
qml: 3
qml: 2
qml: 3
main.qml:18:9: Unable to assign [undefined] to double
Do this:
Rectangle{
id: rect
...
readonly property real scales: [(rotateRepeater.yPointM - rotateRepeater.yPointT) / height ,
(rotateRepeater.yPointB - rotateRepeater.yPointM) / height]
readonly property real yScale: scales[index] // Warning is in this line
}
Property evaluations are arbitrarily ordered, so the eval of yScale may happen when either scale0 or scale1 are not evaluated yet. There is also a possibility that the index value is out of range, as mentioned in other answers.
Quote from the Qt documentation:
Syntactically, bindings are allowed to be of arbitrary complexity. However, if a binding is overly complex - such as involving multiple lines, or imperative loops - it could indicate that the binding is being used for more than describing property relationships. Complex bindings can reduce code performance, readability, and maintainability. It may be a good idea to redesign components that have complex bindings, or at least factor the binding out into a separate function. As a general rule, users should not rely on the evaluation order of bindings.
Related
This bit of Code here creates a scrollview of buttons to allow me select from a list of different "tickets"
SearchResultButton(Button(text=str(Datarray2[i]),id=str(Datarray2[i]),on_press=self.Pressbtn ))
self.ids.SearchResult.add_widget(SearchResultButton)
From there it opens this function, which should set a variable (In this case "UpdateTicketNum") which will be used in another function to set the label text in another screen.
def Pressbtn(self, SearchResultButton):
global UpdateTicket
UpdateTicket = OPENTicket
woo = SearchResultButton.text
print(SearchResultButton.text)
wow = [blank.strip() for blank in woo.split(',')]
print("\n\n\n\n")
global UpdateTicketNum
UpdateTicketNum = (wow[0])
self.manager.get_screen('UpdateTicket').UpdateOpen()
At this point it opens up the sqlite DB and double checks that the TicketNumber is valid. The issue comes in when trying to access the label inside the kv build
def UpdateOpen(self):
print("TESTSETST")
conn = sqlite3.connect('TicketData.db', timeout=10)
UD = conn.cursor()
UD.execute('SELECT TicketNumber FROM TicketData WHERE TicketNumber = ?',(UpdateTicketNum,))
tips = UD.fetchone()
print(tips[0])
tipsy = tips[0]
UpdatedLabelTexT = tipsy
sm.current=('UpdateTicket')
UpdateTicket.ids.UpdateLabels['text']=(UpdatedLabelTexT)
The UpdateTicket.ids.UpdateLabels['text']=UpdatedLabelText] field always claims to be a property of the scrollview buttons even though I am initializing it inside another class, and with different parameters. apologies if this question is poorly formatted. but 3 days of dying trying to figure this out and I snapped.
Here is the bit in KV
<UpdateTicket>
name: 'UpdateTicket'
on_enter:
root.UpdateOpen()
orientation: "vertical"
FloatLayout:
canvas.before:
Color:
rgba: .0, .6, 1, 1
Rectangle:
pos: self.pos
size: self.size
source: "lights.jpg"
Label:
id: UpdateLabels
text: "filler"
multiline: False
size_hint: (None, None)
size: (root.width/5,root.height/20)
pos_hint:{'center_x': .5,'center_y': .5 }
and how I initialize the screen
sm.add_widget(UpdateTicket(name='UpdateTicket'))
I found the solution that worked for me. when first initializing the app
class SampleApp(App)
return sm(to build the application)
I needed to replace that return SM with
global root
return sm
root = ScreenManager()
return root
And that appeared to fix my issue. thanks for reading
I'm using a canvas object inside my component to generate a chart. In order for it animate i'm calling the method recursively. I keep getting an error saying that the method is not defined. Not sure how I need to structure it.
any assistance appreciated.
// Animate function
protected animate(draw_to) {
// Clear off the canvas
this.ctx.clearRect(0, 0, this.width, this.height);
// Start over
this.ctx.beginPath();
// arc(x, y, radius, startAngle, endAngle, anticlockwise)
// Re-draw from the very beginning each time so there isn't tiny line spaces between each section (the browser paint rendering will probably be smoother too)
this.ctx.arc(this.x, this.y, this.radius, this.start, draw_to, false);
// Draw
this.ctx.stroke();
// Increment percent
this.curr++;
// Animate until end
if (this.curr < this.finish + 1) {
// Recursive repeat this function until the end is reached
requestAnimationFrame(function () {
error happens here >>> this.animate(this.circum * this.curr / 100 + this.start);
});
}
}
You need to use an arrow function to keep the same context in the function you give to requestAnimationFrame.
requestAnimationFrame(() => {
error happens here >>> this.animate(this.circum * this.curr / 100 + this.start);
});
Another option is:
requestAnimationFrame(this.animate.bind(this, this.circum * this.curr / 100 + this.start));
You are passing a reference to this.animate which is already bound to the correct this along with the parameters.
I can assign values to a variable property but not to an array here? ... values aren't kept.
Column {
id: table
property variant aa: [false, false] //issue... later
property variant bb: false //this works
...
Button {
anchors.top: parent.top
anchors.topMargin: 0//40
anchors.right: parent.right
anchors.rightMargin: 0//50
corpFarmAware: true
text: tr_NOOP("Next")
onClicked: {
table.aa[0] = false;
table.aa[1] = true;
cb0.checked = table.aa[0];//issue of arrays ??
cb1.checked = table.aa[1];
table.bb = true;
cb2.checked = table.bb;//WORKS
}
}
According to the documentation on variant in QML:
While this is a convenient way to store array and map-type values, you must be aware that the items and attributes properties above are not QML objects (and certainly not JavaScript object either) and the key-value pairs in attributes are not QML properties. Rather, the items property holds an array of values, and attributes holds a set of key-value pairs. Since they are stored as a set of values, instead of as an object, their contents cannot be modified individually
I think you should use var to store your properties.
in Flex I have something like that:
var dg:DataGrid = new DataGrid();
if (something) dg = dg1 else if (something_2) dg = dg2;
dg.dataProvider.getItemAt(3).id;
and dg is ALWAYS pointing at DataGrid (even if dg1 has name DataGrid_test and dg2 = DataGrid_test2) and finally action is made on my first DataGrid (DataGrid_test).
Why?
How can I pass dg1 or dg2 to dg?
Here is pasted almost full code of this part of application. I edited it to make that more clear.
var dg:DataGrid = null;
if ( currentState == "state1" ) { //if this condition is true then app. go into if and
dg = dataGrid_first; // make dg = DataGrid (1)
test.text = "inco"; // shows "inco" in "test" label
} else if ( currentState == "state2" ) { // if this is true then app. go..
dg = dataGrid_second; //here and set dg as DataGrid (exactly!) (2)
test.text = "outgo"; // and change test label into blank text (earlier text disapears)
}
search(dg);
It is modified with advice of '#splash'
Still not working.
EDIT:
I made this sceond edit to answer for all You who are helping me with that :) I think that it will be the best way. In codeblock above I added comments. (please read now comments and after that come back here :) )
Now I will explain exactly what happens.
I debug it many times and here are results:
dg is pointing at DataGrid (as component in flex, not as my dataGrid_first), I needed to extend DataGrid so now it is ColorColumn component (I don't know if I called it properly), not DataGrid. And dg is pointing at ColorColumn not at dataGrid_first or dataGrid_second. I even tried today the same thing what suggest #splash:
if ( currentState == "state1" ) {
test.text = "inco";
search(dataGrid_first);
} else if ( currentState == "state2" ) {
test.text = "outgo";
search(dataGrid_second);
}
and search still points at ColorColumn :/ My problem is really easy- I just want to pass to search different dataGrid on each state. If You have other ideas how I can do that in right way then I will pleased to hear about it. :)
But still I don't understand why it doesn't work. My search function uses algorhitm Boyer-Moor for searching through dataGrid.dataProvider for some text. If it find something then it is pushed into new array and after passing whole dataProvider I colorize rows with searched word.
If dg is never pointing to dg1 and dg2 then your (something) expressions may be evaluate to false. Check the value of your if-conditions - this should be easy to debug.
This should work:
var dg:DataGrid = null;
if (something)
dg = dg1;
else if (something_2)
dg = dg2;
if (dg)
{
// do something with dg
}
[Update]
I still can't see why your code isn't working, but you could simplify it like this:
if ( currentState == "state1" ) {
test.text = "inco";
search(dataGrid_first);
} else if ( currentState == "state2" ) {
test.text = "outgo";
search(dataGrid_second);
}
I'd propose to write this - since I guess either dg1 or dg2 should be assigned:
if (something) {
dg = dg1;
} else {
dg = dg2;
}
There may be cases, where if () {} else () {} neither executes the first or the second conditional block.
Finally a small hint, which structurally eliminates unwanted assignments in if conditions: Always write the literal left of the comparison operation: if ( "state1" == currentState ). If you accidentally typed = instead of ==, the flex compiler emits an error. The other notation silently assigns a value.
Additionally: Did you single-stepped through your code and watched the variables dg1, dg2 and dg? If not, set a breakpoint a few line before the if-statement and run the code step by step from there on. What do you see?
Here's a another tip: Use assertions to check for inconistencies:
package my.company.utilities {
public function assert(expression:Boolean):void {
// probably conditionally compile this statement
if (!expression) {
throw new Error("Assertion failed!");
}
} // assert
}
Use it e.g. at the beginning of a method like this:
public function doTransaction( fromAccount:int, toAccount:int ) {
assert( 0 < fromAccount );
assert( 0 < toAccount );
}
A typically good use of assert is to check variables regarding their range. As of the above example, fromAccount and toAccount should always be positive. Due to a bug, bad values might get passed to doTransaction(). In this case, the assertion fires an error.
for some reason this flex 4 code gives me an error but I can't figure out why. In my WindowedApplication I have:
var prefs:Object = fs.readObject();
fs.close();
var rect:Rectangle = new Rectangle();
rect = prefs.bounds as Rectangle;
this.bounds = rect; // error here
Error message:
ArgumentError: Error #2007: Parameter rect must be non-null.
I originally also tried it without the rect object and just did:
this.bounds = prefs.bounds as Rectangle;
which gives me the following error:
TypeError: Error #1034: Type Coercion failed: cannot convert Object#1dbbe1f1 to flash.geom.Rectangle.
That seems like a bogus error since I can assign pref.bounds to rect without an error. I don't know why this isn't working. It works under flex 3 compatibility mode but that also breaks a lot of my spark components so I can't use it.
rect = prefs.bounds as Rectangle;
rect ends up as null because prefs.bounds is not an instance of Rectangle class. Casting with as keywords returns null if it fails.
Just give a trace(prefs.bounds); after the call to readObject to see what it contains.
Update:
The fact that the value in prefs.bounds have x, y, width and height properties, doesn't make it a Rectangle object - it is just an object with those four properties. The easy solution is to create a Rectangle object from those values and use that:
var prefs:Object = fs.readObject();
var rect:Rectangle = new Rectangle(prefs.bounds.x, prefs.bounds.y, prefs.width, prefs.height);
this.bounds = rect;
If you call registerClassAlias before writing the rectangle object to the file stream, the readObject would return an object of appropriate type instead of a generic one.
registerClassAlias("flash.geom.Rectangle", Rectangle);
fs.writeObject(this.bounds);
//later...
//Casting with () will throw an error if the read object is not a Rectangle
var rect:Rectangle = Rectangle(fs.readObject());
trace(rect);