How to set property type of qml signal? - pyqt

I am learning qml,quick and pyqt5 and write a small test script.
In this script, I want to drop something on my UI and print the url of it.
test.qml
import QtQuick 2.3
Rectangle {
id : root
signal clicked(int x, int y)
signal filedroped(list url)
width: 800
height: 450
MouseArea {
anchors.fill: parent
onClicked: {
parent.clicked(mouseX, mouseY)
}
DropArea {
anchors.fill: parent
onDropped: {
root.filedroped(drop.urls)
}
}
}
}
The doc says:Any of the QML Basic Types aside from the enumeration type can be used as custom property types.
But I got error like this in signal filedroped:
Invalid signal parameter type: list
Also, I have tried urllist and string.
urllist failed and string works.
What's wrong with my script?
EDIT
Since I use qml with pyqt, I do not want to use the type var.
With var, I'll got a QJSValue object instead of basic type of python in my python script.
Why qml performs different with the official document? Is the document wrong?

It seems on there's indeed an error in the Qt Documentation. It is said (here) that
the allowed parameter types [for signal parameters] are the same as those listed under
Defining Property Attributes on this page.
Yet one can define a property as follow:
property list<Item> items
whereas this is invalid:
signal mysignal(list<Item> items)
But anyway, the QML list type was not a solution. The official documentation is quite clear:
A list can only store QML objects, and cannot contain any basic type
values. (To store basic types within a list, use the var type
instead.).
In other words you can't use list to store strings, url, int. You have to use var. Another solution would be to use a formatted string with a custom separator instead of your url list, and split it on the Python side.

It looks that urllist is an array of urls so you can use var in this case:
signal filedroped(var urls)

Related

I want to make a dropdown container in my script

I want to create a dropdown container to organize my export variable. Is it possible to create a custom dropdown container in the script?
Like this:
This is another approach to do this. It also requires the script to be tool.
What we need for this approach as a common prefix for the variables you want to group. The advantage is that we don't need _get and _set:
tool
extends Node
var custom_position:Vector2
var custom_rotation_degrees:float
var custom_scale:Vector2
func _get_property_list():
return [
{
name = "Custom",
type = TYPE_NIL,
hint_string = "custom_",
usage = PROPERTY_USAGE_GROUP
},
{
name = "custom_position",
type = TYPE_VECTOR2
},
{
name = "custom_rotation_degrees",
type = TYPE_REAL
},
{
name = "custom_scale",
type = TYPE_VECTOR2
}
]
As you can see we define a category with a name that will appear in the Inspector panel, and the hint_string is the prefix we will use. It is important to put the category before the properties in the array.
See: Adding script categories
Addendum: Using PROPERTY_USAGE_CATEGORY will produce a named header, similar to the one that says "Node2D" on the picture on the question. Use PROPERTY_USAGE_GROUP to make a collapsible group.
Yes, you can do this, but (in my opinion) it is a bit ugly and clutters up your script. You need to mark your script as a tool script and override the _get, _set, and _get_property_list functions.
An example based on your screenshot (not 100% sure this works exactly as-is; I'm also basing it on a recent project where I have since removed it and somewhat reorganized the project/code/node because the slightly nicer UI wasn't worth the additional clutter in the script):
tool
extends Node2D
# Note that these are NOT exported
var actual_position: Vector2
var actual_rotation: float
var actual_scale: Vector2
# Function to enumerate the properties to list in the editor
# - Not actually directly/automatically backed by variables
# - Note the naming pattern - it is {group heading}/{variable}
func _get_property_list():
var props = []
props.append({name="transform/position", type=TYPE_VECTOR2})
props.append({name="transform/rotation deg", type=TYPE_FLOAT}) # might not exist; look at docs to determine appropriate type hints for your properties
props.append({name="transform/scale", type=TYPE_VECTOR2})
return props
# Now the get/set functions to map the names shown in the editor to actual script variables
# Property names as input here will match what is displayed in the editor (what is enumerated in _get_property_list); just get/set the appropriate actual variable based on that
func _get(property: String):
if property == "transform/position":
return actual_position
if property == "transform/rotation deg":
return actual_rotation
if property == "transform/scale":
return actual_scale
func _set(property: String, value):
if property == "transform/position":
actual_position = value
return true
if property == "transform/rotation deg":
actual_rotation = value
return true
if property == "transform/scale":
actual_scale = value
return true
# Not a supported property
return false
Note that this answer is based on Godot 3.4. I'm not sure if a simpler approach is (or will be) available in Godot 4.

My segmented picker has normal Int values as tags, How is this passed to and from CoreData?

My SwiftUI segmented control picker uses plain Int ".tag(1)" etc values for its selection.
CoreData only has Int16, Int32 & Int64 options to choose from, and with any of those options it seems my picker selection and CoreData refuse to talk to each other.
How is this (??simple??) task achieved please?
I've tried every numeric based option within CoreData including Int16-64, doubles and floats, all of them break my code or simply just don't work.
Picker(selection: $addDogVM.gender, label: Text("Gender?")) {
Text("Boy ♂").tag(1)
Text("?").tag(2)
Text("Girl ♀").tag(3)
}
I expected any of the 3 CoreData Int options to work out of the box, and to be compatible with the (standard) Int used by the picker.
Each element of a segmented control is represented by an index of type Int, and this index therefore commences at 0.
So using your example of a segmented control with three segments (for example: Boy ♂, ?, Girl ♀), each segment is represented by three indexes 0, 1 & 2.
If the user selects the segmented control that represents Girl ♀, then...
segmentedControl.selectedSegmentIndex = 2
When storing a value using Core Data framework, that is to be represented as a segmented control index in the UI, I therefore always commence with 0.
Everything you read from this point onwards is programmer preference - that is and to be clear - there are a number of ways to achieve the same outcome and you should choose one that best suits you and your coding style. Note also that this can be confusing for a newcomer, so I would encourage patience. My only advice, keep things as simple as possible until you've tested and debugged and tested enough to understand the differences.
So to continue:
The Apple Documentation states that...
...on 64-bit platforms, Int is the same size as Int64.
So in the Core Data model editor (.xcdatamodeld file), I choose to apply an Integer 64 attribute type for any value that will be used as an Int in my code.
Also, somewhere, some time ago, I read that if there is no reason to use Integer 16 or Integer 32, then default to the use of Integer 64 in object model graph. (I assume Integer 16 or Integer 32 are kept for backward compatibility.) If I find that reference I'll link it here.
I could write about the use of scalar attribute types here and manually writing your managed object subclass/es by selecting in the attribute inspector Class Codegen = Manual/None, but honestly I have decided such added detail will only complicate matters.
So your "automatically generated by Core Data" managed object subclass/es (NSManagedObject) will use the optional NSNumber? wrapper...
You will therefore need to convert your persisted/saved data in your code.
I do this in two places... when I access the data and when I persist the data.
(Noting I assume your entity is of type Dog and an instance exists of dog i.e. let dog = Dog())
// access
tempGender = dog.gender as? Int
// save
dog.gender = tempGender as NSNumber?
In between, I use a "temp" var property of type Int to work with the segmented control.
// temporary property to use with segmented control
private var tempGender: Int?
UPDATE
I do the last part a little differently now...
Rather than convert the data in code, I made a simple extension to my managed object subclass to execute the conversion. So rather than accessing the Core Data attribute directly and manipulating the data in code, now I instead use this convenience var.
extension Dog {
var genderAsInt: Int {
get {
guard let gender = self.gender else { return 0 }
return Int(truncating: gender)
}
set {
self.gender = NSNumber(value: newValue)
}
}
}
Your picker code...
Picker(selection: $addDogVM.genderAsInt, label: Text("Gender?")) {
Text("Boy ♂").tag(0)
Text("?").tag(1)
Text("Girl ♀").tag(2)
}
Any questions, ask in the comments.

WPFExtendedToolkit PropertyGrid Standard Values

I'm trying to display XmlElement's attributes in Xceed PropertyGrid. For that purpose I defined custom wrapper class. It wraps XmlElement, iterates over XmlAttributes and creates custom PropertyDescriptor for each XmlAttribute. All "virtual" properties' type is String. All works fine.
Now I want to have drop-down list of possible attribute values for every attribute that has restricted set of values. In Xceed's PropertyGrid, there is ItemsSourceAttribute for that. But it has to be applied as follows:
ItemsSourceAttribute(typeof(MyCustomItemsSource))
And here is the problem - I can not provide proper argument for MyCustomItemsSource constructor. What can I do about this?
It seems that there is another possibility - to define a TypeConverter, override GetStandardValues, and supply this converter to "virtual" property. But PropertyGrid just ignores this attribute.
How this simple task can be done with Xceed PropertyGrid?
Solved. I implemented custom editor
public class AttributeValuesEditor: Xceed.Wpf.Toolkit.PropertyGrid.Editors.ComboBoxEditor
{
protected override IEnumerable CreateItemsSource(PropertyItem propertyItem)
{
var property = propertyItem.PropertyDescriptor as XmlAttributePropertyDescriptor;
Debug.Assert(property!=null);
return property.GetCompletionValues();
}
}
Here, the context is passed into method in the form of PropertyItem. Now it is possible to differentiate between different attributes and return appropriate items.

Best way to access information inside of another class with TCL?

Basically, I'm trying to create a get method for a tcl class that I have so that I can access data inside that class within a proc that isn't inside a class. For example, it would look like this:
itcl::class foo {
set list []
proc getFilterList {} {
return $list
}
}
proc bar {} {
set list itcl::foo::getFilterList
}
But hilariously the the list contains the phrase "itcl::foo::getFilterList" so I'm obviously doing something wrong. Sorry if this is an obvious one, I just can't seem to figure it out.
In addition to following the selected answer, I also made my variable available at a global scale which works for me seeing as how from creation to manipulation I know exactly when my variable is being modified and when I can access it's values.
Use
proc bar {} {
set list [itcl::foo::getFilterList]
}

Masking QLineEdit text

I am using PyQt4 QLineEdit widget to accept password. There is a setMasking property, but not following how to set the masking character.
editor = QLineEdit()
editor.setEchoMode(QLineEdit.Password)
There is no setMasking property for QLineEdit in either PyQt4 or Qt4. Are you talking about setInputMask()? If you are, this does not do what you seem to think it does. It sets the mask against which to validate the input.
To get the control to hide what is typed, use the setEchoMode() method, which will (should) display the standard password hiding character for the platform. From what I can see from the documentation, if you want a custom character to be displayed, you will need to derive a new class. In general however, this is a bad idea, since it goes against what users expect to see.
It's quite easy using Qt: you would need to define a new style and return new character from the styleHint method whenever QStyle::SH_LineEdit_PasswordCharacter constant is queried. Below is an example:
class LineEditStyle : public QProxyStyle
{
public:
LineEditStyle(QStyle *style = 0) : QProxyStyle(style) { }
int styleHint(StyleHint hint, const QStyleOption * option = 0,
const QWidget * widget = 0, QStyleHintReturn * returnData = 0 ) const
{
if (hint==QStyle::SH_LineEdit_PasswordCharacter)
return '%';
return QProxyStyle::styleHint(hint, option, widget, returnData);
}
};
lineEdit->setEchoMode(QLineEdit::Password);
lineEdit->setStyle(new LineEditStyle(ui->lineEdit->style()));
now the problem is that pyqt doesn't seem to know anything about QProxyStyle; it seem to be not wrapped there, so you're stuck, unless you would want to wrap it yourself.
regards
As docs say http://doc-snapshot.qt-project.org/4.8/stylesheet-examples.html#customizing-qlineedit:
The password character of line edits that have QLineEdit::Password echo mode can be set using:
QLineEdit[echoMode="2"] {
lineedit-password-character: 9679;
}
In Qt Designer
Select the line edit, and in the Property Editor window, there will be a property echoMode which you can set to Password.
Using python code
In this case, Anti Earth's answer will work which is:
myLineEdit.setEchoMode(QLineEdit.Password)

Resources