Let's say I've the following class:
class Person(object):
def __init__(self, attributes):
# Attributes is just a dictionary (string -> value)
self.attributes = attributes
def set_attribute(self, attribute, value):
self.attributes[attribute] = value
# Some other code which may cause the value of other attributes to change,
# or other attributes to be added or deleted too
Now I'd like to create a PyQt dialog with a simple form, but which is dynamically generated (to account for the variable number of attributes). I did this by creating a QFormLayout in a QDialog and adding a row for every attribute the Person object has:
self.formLayout = QtWidgets.QFormLayout()
for attribute in self.person.attributes.keys():
label = QtWidgets.QLabel(self)
label.setText(attribute)
lineEdit = QtWidgets.QLineEdit(self)
lineEdit.textEdited['QString'].connect(self.onAttributeChanged)
# or use a checkbox instead of a line edit if the attribute is a boolean,
# combo box if it's an enum or similar, etc.
self.formLayout.addRow(label, lineEdit)
Where onAttributeChanged() calls self.person.set_attribute with the appropriate attribute and the new value inputted by the user.
Now that takes care of updating the model with the user's input values, but the problem I'm facing is how to update the view when set_attribute modifies the person's other attributes (since set_attribute may add or delete other attributes, or change the other attributes' names or values). So far, I've considered to following:
Rebuild the entire form whenever information changes. There's probably something better than this.
Use the Qt signal/slot model, like I did by connecting lineEdit to onAttributeChanged. From what I understand, this means using pyqtSignal to create signals in my Person class representing the attribute names, plus emitting the appropriate signals whenever the names are modified. However, I'd like to keep my Person class intact, and free from any Qt .emit() calls. (Not to say this still doesn't handle the case of attributes being added/removed.)
Ditch the form altogether and use a table view with a QStandardItemModel instead. Not ideal since I really wanted a form and not a table (for the sake of better usability).
Is there some elegant way of handling this kind of dynamic form in PyQt?
Related
I have a simple form that's in a dialog fragment used to submitting two fields for log-in auth.
For simplicity I was hoping to not have to use data binding, but rather use some method to gather all data inside my sap.ui.layout.form.SimpleForm.
I added a name property to each input element which says in the docs it is " Defines the name of the control for the purposes of form submission."
https://openui5.hana.ondemand.com/#/api/sap.m.InputBase/controlProperties#name
However hard as I try to find there doesn't seem to be any getFormData methods.
All SO questions and guides either use data binding to a model, or hard-code references to the individual input controls with .getValue() methods.
And looking further into the form API, there doesn't seem to be a Submit event either.
Given an arbitrary form, what would be the best way to gather all submission values without hard-coded references or data-binding?
Would a method that walks though all the children elements of a form looking for all submission values work? I think it might, but there are more submission input types then just the input component.
You can get the value of the fields by directly using;
var oField = sap.ui.getCore().byId('IdOfTheFieldAtTheDialog');
var sValue = oField.getValue();
But it's always better and convenient to use data binding which keep things neat.
And If I assume that you have the id of parent form container, you can iterate over the items and get the sap.m.Input elements in it without knowing the IDs of the individual inputs, and you may check the name property of the fields if you want. Check this snippet;
https://jsfiddle.net/hdereli/9e92osfk/3/
I'd like to know if there is a way to configure, disable or otherwise override the way Symfony handles automatically generating form labels for entity properties.
We also use the Sonata Admin Bundle and Symfony native and Sonata do not always produce the same label for complex form fields based on a given entity property, specifically when adding related entity properties e.g. something.somethingRelated. Sometimes it seems there is an extra space added to the label string (where the "dot" is) so we end up with two different labels being generated for the exact same property in two different forms.
Sonata has a configuration that allows some control over how the label is generated; e.g underscores, native, do nothing, etc.
We are trying to get our translations under control but still use the automatic generation of form labels rather than having to add a label (key) to each form field.
Right now I think my best alternative is to just turn it off in Symfony and let the actual property name be the "string" that is generated without any processing on it. So, thisIsTheProperty would have an automatically generated label string "thisIsTheProperty", not "This Is The Property" or whatever.
Was previously using this line in my controler to return an id and text column from, a stored procedfure in asp.net MVC
user = new SelectList(ctx.Database.SqlQuery<LkUpGenderModel>("EXEC dbo.uspGetLkUpGender").ToList(), "GenderID", "Gender");
However i now want to return more text values, I have extended the model to have these extra fields but I'm getting an error.
Is there a way to get this working:
user = new SelectList(ctx.Database.SqlQuery<LkUpGenderModel>("EXEC dbo.uspGetLkUpGender").ToList(), "GenderID", "Gender", "GenderShort", "GenderCombined");
currently it flags the SelectList( saying the call is ambiguous
The previous code simply returns instances of LkUpGenderModel and then builds a SelectList from that using the GenderID property of that class as the value and the Gender property as the display text.
Your new code doesn't request more properties, it simply passes additional parameters to the SelectList constructor: namely, dataGroupField which you're setting to the GenderShort property, and selectedValue, which you're setting to the GenderCombined property. See: https://msdn.microsoft.com/en-us/library/dn725507(v=vs.118).aspx.
If you have additional columns being returned from the stored procedure that you want filled in on the class, then you should add additional properties to the class to handle those. However, since all you're doing with the data is creating a SelectList from it, you can't send any additional data to the view other than the value and display text, making returning additional data pointless in this instance.
I've built a Zend_Form_Decorator_Input class which extends Zend_Form_Decorator_Abstract, so that I could customize my form inputs -- works great. I ran into a problem in the decorate class, in trying to get the form name of the element, so as to built a unique id for each field (in case there are multiple forms with identical field names).
There is no method like this: Zend_Form_Element::getForm(); It seems Zend_Form_Decorator_Abstract doesn't have this ability either. Any ideas?
I don't think changing the id from the decorator is the right approach. At the time the decorator is called the element already has been rendered. Thus changing the id would have no effect to the source code. Additionally, as you already have pointed out, the relation between a form and its elements is unidirectional, i.e. (to my best knowledge) there is no direct way to access the form from the element.
So far the bad news.
The good news is, that there actually is a pretty easy solution to your problem: The Zend_Form option elementsBelongTo. It prevents that the same ID is assigned to two form elements that have the same name but belong to different forms:
$form1 = new Zend_Form(array('elementsBelongTo' => 'form1'));
$form1->addElement('Text', 'text1');
$form2 = new Zend_Form(array('elementsBelongTo' => 'form2'));
$form2->addElement('Text', 'text1');
Although both forms have a text field named 'text1', they have different ids: 'form1-text1' and 'form2-text1'. However, there is a major drawback to this: This also changes the name elements in such a way that they are in the format formname[elementname]. Therefore $this->getRequest()->getParam('formname') will return an associative array containing the form elements.
I have few short questions regarding Enterprise architect.
My question is regarding the automation interface. When following the instructions provided on this page: http://www.sparxsystems.com/uml_tool_guide/sdk_for_enterprise_architect/colle... in order to add a new element to the collection ( and the .eap file) it does not add the element. I can get data from the elements, modify and even delete them, but adding a new element does not work?
Instructions provided:
Call AddNew to add a new item.
Modify the item as required.
Call Update on the item to save it to the database.
Call Refresh on the collection to include it in the current set.
my java example:
elements is a collection of all the elements in the model...
org.sparx.Element elementEa = elements.AddNew("Requirement", "non-functional");
elementEa.Update();
elements.Refresh();
With the api is it possible to change the id or guid of an element since there are no methods specified in org.sparx for that?
One last thing... Is it possible to create a custom element in EA, for example a requirement which will not have the standard properties like difficulty, priority etc.. , but will have others? (normal properties, not tagged values)
The arguments to AddNew() are Name and Type, so to create a Requirement element you should specify "SomeRequirementName" and "Requirement".
You can't change the ID or GUID through the API, and your models would crash and burn if you did (connectors would be left dangling, elements would vanish from diagrams, etc, etc).
With an MDG Technology you can create very detailed stereotyped elements if you like, with their own visual representations (shape scripts) etc, but if you're after creating an element type with its own properties dialog the answer is no; there is no hook for a custom dialog in the API.
Collection<Package> packageCollection = myPackage.GetPackages();
Package consolidatedCfsSpecPackage = packageCollection.AddNew("somePackageName", "");
if (!consolidatedCfsSpecPackage.Update()) {
System.err.println("Not Updated: somePackageName");
}
packageCollection.Refresh();
This works for me. I suggest you to check return value of elementEa.Update() method you called. If it returns false, you can get the reason by calling elementEa.GetLastError().