I have a simple button component in my Blaze templates. I want it to accept attributes to apply to the resulting element alongside other things, but as I've found out, you can't do it the same way as in other bindings: <button {{b "attrs: getAttrs"}}>{{text}}</button>, where getAttrs() returns the desired attributes from arguments doesn't work, as the binding argument is taken literally, i. e. it ends up taken as an object with keys 0, 1, 2, 3, 4, 5, 6, 7 (the string 'getAttrs' keys), and attempting to set attributes with those names, resulting in a DOM exception. What can be done in my case?
Related
First: I've inherited this project from someone who couldn't complete it due to time constraints.
The code contains a little over 100 declared arrays, each one containing a set of INTs. The arrays are all unique.
byte arr_foo[] = {2, 5, 6, 8, 3};
byte arr_bar[] = {1, 7};
byte arr_baz[] = {6, 10, 9, 11, 7, 8, 3};
Those INTs relate to a specific LED on a board - there are 11 total. And the arrays represent a specific sequence that these LEDs should light up.
What they were attempting to do was to write a routine that, when given an array name, would then go fetch the contents of that array and process the INTs. Well, passing an array name as a string to then be matched with a variable doesn't work. And this is where they passed it on, saying they don't have time to figure it out.
So I'm looking at this and thought, why not a 2-dimensional array? I quickly ran into trouble there.
byte seqs[][7] = {
{2, 5, 6, 8, 3},
{1, 7},
{6, 10, 9, 11, 7, 8, 3}
}
While in principle this works, the issue here is that it pads each array with trailing zeros because I told it each one has [7] elements. This results in a lot of memory being wasted and the thing running out of memory.
So I am stuck. I'm not sure how to deal with 100+ separate arrays, other than to write 100+ separate routines to be called later. Nor can I figure out how to make it more efficient.
Then there's the issue of, I may still run out of memory at a later time as more sequences are added. So then what? Add an external i2c flash memory, and shove things in there? Having never dealt with that, I'm not sure how to implement that, in what format to store the values, and how to do it. Am I correct that one has to first write a program that loads all the data in memory, upload that and run it, then put the actual program that's going to process that data on the micro controller?
So I guess I'm asking for two things: What's a better way of handling lots and lots of (small) arrays and be able to use them within a routine that calls them, and if I'm better off shoving this data into an external flash, what format should they be stored in?
Putting the data into 2D arrays wont save any space at all.
Right now, you're storing these values into your 2k of SRAM. Change these declarations to use the PROGMEM keyword, so they're stored where there's much more space.
Using the PROGMEM instructs the compiler to load this data into the flash portion of memory:
const PROGMEM uint8_t arr_foo[] = { 2, 5, 6, 8, 3 };
However the data needs to be accessed with a function call, you can't just use it directly.
for (byte k = 0; k < 5; k++)
{
uint8_t next_led = pgm_read_byte_near( arr_foo + k );
// Do something with next_led
}
If these arrays form a pattern of leds that should be lit, while the other ones are switched off, you could store the state of all leds in an uint16_t and have an array of those in PROGMEM. (As in Kingsley's answer)
If you're not familiar with HEX notation you could use the binary format.
const PROGMEM uint_16_t patterns[] = {
// BA9876543210 Led Pins
0b000101101100, //foo: 2, 5, 6, 8, 3
0b000010000010, //bar: 1, 7
0b111111001000, //baz: 6, 10, 9, 11, 7, 8, 3
// ...
};
I wonder about the order of your numbers, so I'm not sure if this guess is correct at all. So no more details how to work with this approach rigth now
Update
To me, your comments changed the intention of your question completely.
As I read it now, there's no need for a special kind of "name" data to identify an array. What you want seems to be just to pass different arrays around as function arguments.
This is usually done via pointers, and there are two things to note:
Most of the time, arrays "decay" to pointers automatically. That means that in most places an array variable can be used in place of a pointer. And a pointer can be used like an array.
An array in C does not carry any length information at runtime. The length of an array needs to be held/passed separately. Alternatively, you can define a struct (or class in C++) which contains both the array and its length as members.
Example:
If you want to pass an array of elements of type T to a function, you can declare the function to accept a pointer to T:
void somefunc(uint8_t* arr, uint8_t arrLength) {
for ( uint8_t i = 0; i < arrLength; i++ ) {
uint8_t value = arr[i];
value = *(arr+i); // equivalent to arr[i]
}
}
or equivalently
void somefunc(uint8_t arr[], uint8_t arrLength) {
...
}
then call that function by simply passing the array variable and the corresponding array's length, like
uint8_t arr_foo[] = { 1,2,3,4,5 };
uint8_t arr_bar[] = { 1,2 };
somefunc(arr_foo,5);
somefunc(arr_bar,2);
The arrays' constant data can be put into PROGMEM to save RAM, but, as others have noted, read accesses are a little more complex, requiring pgm_read_...() calls in C++. (AVR gcc does support __flash-qualified data only in C, not in C++.)
Then there's the issue of, I may still run out of memory at a later
time as more sequences are added.
Notice that the "Arduino" AVR has 32kb of flash memory. If each sequence consumes 15 bytes, it could probably still hold 1000 or 2000 of these items along with your program.
then what? Add an external i2c flash memory, and shove things in
there? Having never dealt with that, I'm not sure how to implement
that, in what format to store the values, and how to do it.
If you actually run out of flash at some point you can still resort to any form of external storage.
A common solution is SPI flash memory, which is readily available in the mega-bit range. Winbond is a well-known supplier. Just search for "Arduino SPI flash" modules and libraries.
A more complex approach would be to support SD cards as external memory. But probably not worth it unless you actually want to store gigabytes of data.
Am I correct that one has to first write a program that loads all the
data in memory, upload that and run it, then put the actual program
that's going to process that data on the micro controller?
That's definitely one way to do it. If your code space permits, you can alternatively include the routines to write to the external flash memory in your application, like some kind of bootloader so that you can switch into "upload external flash data" mode without re-flashing the microcontroller.
I've successfully added elements using
list.push(element)
But how do I remove them? I've tried the following, but none of them seem to work.
list.pop()
list.pop_front()
list.remove()
list.remove(int)
list.remove(element)
For people who always keep ending up on this page, like I did: I found a very hacky solution to remove an element from a list<QtObject>.
myList = Array.from(myList).filter(r => r !== elementIWant2Remove)
This is not very elegant, but it does the trick, if you need to remove an element.
You can't remove individual items. According to the docs:
Note that objects cannot be individually added to or removed from the list once created; to modify the contents of a list, it must be reassigned to a new list.
This means that the pop method most likely won't exist with the basic list type. (However, there is a push method.)
You'll be much better off using JavaScript arrays.
property var myArray: [1, 2, 3]
Component.onCompleted: {
myArray.push(4);
myArray.push(5);
myArray.splice(1, 1) // simulates a remove
myArray.pop(); // pop last item
console.debug(myArray) // [1, 3, 4]
}
I've used ints here, but you can also store QML objects and other types as well. Using JavaScript arrays exposes your variables to most (if not all) of JavaScript's Array functions.
Recently I tackled a problem which involved updating a large number of key values.
Naturally, I considered using a Map, with operations like Map.put/3.
However this seemed insufficient, given the immutable nature of data structures in Elixir:
iex> m = Map.put(%{}, :a, 1)
%{a: 1}
iex> Map.put(m, :b, 2)
%{a: 1, b: 2}
iex> m
%{a: 1}
I then solved the problem by holding the state of the Map in a GenServer, and updating it using handle_cast/3 calls.
Generally, is this the right approach, or was this too much here?
I then solved the problem by holding the state of the Map in a GenServer [...]
Generally, is this the right approach, or was this too much here?
It heavily depends on your goal. There are many different ways to store the state. Rebinding variables like:
m = Map.put(%{}, :a, 1)
#⇒ %{a: 1}
m = Map.put(m, :b, 2)
#⇒ %{a: 1, b: 2}
Does not store anything. It binds the local variable m to RHO and as soon as the control flow leaves the scope, this variable becomes garbage collected. Whether you need the aforementioned map within a single scope, GenServer (and other state holders) is an overkill.
OTOH, if you need to store the state for a long time and share it between different scopes (e. g. between different processes,) GenServer is the simplest way to accomplish that. In Elixir we have Agent module to decrease the boilerplate for GenServer that is used as a simple in-memory storage, but my advice would be to always use GenServer: sooner or later Agent will become too tight for your purposes.
Also, one might use ets module to keep in-memory key-value storage, shared between processes.
dets is a way to store the state between process restarts.
And, finally, mnesia is an OTP native approach to share the state between both restarts and different nodes (in distributed environment.)
Your first approach was right, you just got one thing wrong.
You should rebind the variable when you update the map, like here:
iex> m = Map.put(%{}, :a, 1)
%{a: 1}
iex> m = Map.put(m, :b, 2)
%{a: 1, b: 2}
iex> m
%{a: 1, b: 2}
But you gotta undestand here that it doesn't mutate the variable, it creates a new map and rebinds it to the same variable.
Now, this approach is the most simple one and you'd have to pass this map to every function that uses it. As an alternative, you may consider using the Agent module. All the info what it is and what it is used for can be found in its docs.
I have several TextInputs in a certain form which have been assigned id in an incremental order. For example:
<s:TextInput id = "index1"/>
<s:TextInput id = "index2"/>
<s:TextInput id = "index3"/>
Based on certain conditions I select the text from the corresponding TextInput and pass the value (index#.text) into a function
foo(var index:String)
If I had just one of the TextInput I could have used:
foo(index1.text)
Can someone suggest how I can pass the textInput using its id.
Thank you.
-H
I plus one the request for 'certain conditions'. You post alludes to the fact that you can't access the component by name, so I'm writing the rest of this based on that assumption.
To access the values of a component and pass parameters of that component into a function you need an identifier, or link, to that component. It is easiest if you use the components name. But, that is not always possible. For example, the Flextras Calendar component creates, and displays, the days of the month. Depending what month is displayed, there may be 28, 30, or 31 days. It is not practical to access them by a unique name.
this is a similar situation in a ListBased class. You won't know, at compile time, how many itemRenderers you're going to need or have on the screen at one time.
One way to approach this is to have an array of the relevant objects (dayRenderers, itemRenderers, or in your case TextInputs). When doing processing you can loop over the array and process the element. Something like this:
for (var x = 0; x<objectArray.length; x++){
foo(objectArray[x].text);
}
If that is not desirable to you, for whatever reason, you can loop over the children of a container doing something like this:
for (var x = 0; x<container.numChildren; x++){
var object : Object = this.getChildat(x);
if(object is TextInput){ foo(object.text) }
}
Functional, but it can be a bit tedious at times. It really depends what you're trying accomplish.
In the tutorials for QTestLib, there are references to the files "testgui.moc" and "testqstring.moc" (one example can be found here: http://www.englishbreakfastnetwork.org/coverage/build/qt-copy/examples/qtestlib/tutorial3/.moc/debug-shared/testgui.moc). These include several pieces of information required to configure the tests. Unfortunately, the tutorials do not explain what this information is or how to change it. Specifically, I'm referring to these lines:
static const uint qt_meta_data_TestQString[] = {
// content:
2, // revision
0, // classname
0, 0, // classinfo
2, 12, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
// slots: signature, parameters, type, tag, flags
13, 12, 12, 12, 0x08,
28, 12, 12, 12, 0x08,
0 // eod
};
static const char qt_meta_stringdata_TestQString[] = {
"TestQString\0\0toUpper_data()\0toUpper()\0"
};
Now, based on my understanding of QT, the qt_meta_stringdata_TestQString variable is the class reference with the names of the methods appended -- something which might be done through something line METHOD(toUpper()), but I'm not sure if and how this is relevant for anything other than result formatting.
I'd like to know, in general, what is going on. The comment provided at the top of the files says that it has to do with "Meta object code", and that much seems obvious based on the methods it later overrides.
More importantly, however, I want to know how I can modify that qt_meta_data array so that it will allow me to call more functions and/or allow me to re-name the functions above to names of different length (switching the method names from toUpper to toApple seems to cause no problems, but changing them to toUppercase or toUp both causes the test application to fail to run as expected).
***************************** UPDATE ********************************
There is already an accepted answer below, but I thought I should add this: The only reason those files were in the tutorials at all was because the tutorial authors decided NOT to have .h and .cpp files for their classes. They are otherwise useless.
The code you posted is generated by Qt's meta object compiler (moc) from your header file. You shouldn't write/change the file yourself. Just write your class header and run moc on it (which is usually handled by the build system you use, qmake will do it by default).