QlineEdit and Findchild() in python - python

When the following line of codes executes in Python QT it creates a new object and puts it over the original object (Yellow area in the picture).
for (section_name,section_object) in self.settings.items():
for (setting, value) in self.settings.items(section_name):
target = self.tabWidget.findChild(QLineEdit,setting)
if(isinstance(target,QLineEdit)):
obj = QLineEdit(target)
obj.setText(self.settings.get(section_name,setting))
Wrong state
If I do this instead the same above happens
for (section_name,section_object) in self.settings.items():
for (setting, value) in self.settings.items(section_name):
target = self.tabWidget.findChild(QLineEdit,setting)
if(isinstance(target,QLineEdit)):
QLineEdit(target).setText(self.settings.get(section_name,setting))
When the expected outcome would be something like this where object is set directly and no new object gets created
Correct state
Could someone help my identify where the problem is or is it even possible to do so.

Related

How to dynamically return Object attributes in python, including attributes of objects that are attributes

I am trying to write a testing program for a python program that takes data, does calculations on it, then puts the output in a class instance object. This object contains several other objects, each with their own attributes. I'm trying to access all the attributes and sub-attributes dynamically with a one size fits all solution, corresponding to elements in a dictionary I wrote to cycle through and get all those attributes for printing onto a test output file.
Edit: this may not be clear from the above but I have a list of the attributes I want, so using something to actually get those attributes is not a problem, although I'm aware python has methods that accomplish this. What I need to do is to be able to get all of those attributes with the same function call, regardless of whether they are top level object attributes or attributes of object attributes.
Python is having some trouble with this - first I tried doing something like this:
for string in attr_dictionary:
...
outputFile.print(outputclass.string)
...
But Python did not like this, and returned an AttributeError
After checking SE, I learned that this is a supposed solution:
for string in attr_dictionary:
...
outputFile.print(getattr(outputclass, string))
...
The only problem is - I want to dynamically access the attributes of objects that are attributes of outputclass. So ideally it would be something like outputclass.objectAttribute.attribute, but this does not work in python. When I use getattr(outputclass, objectAttribute.string), python returns an AttributeError
Any good solution here?
One thing I have thought of trying is creating methods to return those sub-attributes, something like:
class outputObject:
...
def attributeIWant(self,...):
return self.subObject.attributeIWant
...
Even then, it seems like getattr() will return an error because attributeIWant() is supposed to be a function call, it's not actually an attribute. I'm not certain that this is even within the capabilities of Python to make this happen.
Thank you in advance for reading and/or responding, if anyone is familiar with a way to do this it would save me a bunch of refactoring or additional code.
edit: Additional Clarification
The class for example is outputData, and inside that class you could have and instance of the class furtherData, which has the attribute dataIWant:
class outputData:
example: furtherData
example = furtherData()
example.dataIWant = someData
...
with the python getattr I can't access both attributes directly in outputData and attributes of example unless I use separate calls, the attribute of example needs two calls to getattr.
Edit2: I have found a solution I think works for this, see below
I was able to figure this out - I just wrote a quick function that splits the attribute string (for example outputObj.subObj.propertyIWant) then proceeds down the resultant array, calling getattr on each subobject until it reaches the end of the array and returns the actual attribute.
Code:
def obtainAttribute(sample, attributeString: str):
baseObj = sample
attrArray = attributeString.split(".")
for string in attrArray:
if(attrArray.index(string) == (len(attrArray) - 1)):
return getattr(baseObj,string)
else:
baseObj = getattr(baseObj,string)
return "failed"
sample is the object and attributeString is, for example object.subObject.attributeYouWant

MDataHandle.setFloat() isn't changing Plug value

Using the Maya Python API 2.0, I'm trying to make a callback that changes the value of a plug. However, none of the methods I've tried are working.
I've tried using the MPlug.setFloat() method, but this didn't lead to expected results; I found no change in the plug's value. I figured this hadn't worked because I needed to clean the plug after changing its value. So, I then tried getting the plug's data handle using the MPlug.asDataHandle() method, then using the data handle's datablock() method in order to use the data handle and datablock to set the plug's value and clean it. However, I got an error saying "RuntimeError: (kFailure): Unexpected Internal Failure" upon using MDataHandle.datablock().
Now I'm trying the following, which uses the data handle to set the plug's value and clean it:
def setPlugFloatValue(node, plugName, val):
fnSet = OpenMaya.MFnDependencyNode(node)
plug = fnSet.findPlug(plugName,True)
handle = plug.asMDataHandle()
handle.setFloat(val)
handle.setClean()
The above function is intended to find a certain plug in a node, then use its data handle to set its value and clean it. In my program, the callback uses this function to change the translateX, translateY and translateZ plugs of a node's child nodes. The callback runs when the translate value of the node it's applied to changes. In a scene I'm using to test this callback, I apply the callback to a polygon mesh object, with one child which is also a polygon mesh object. So, as I translate the parent object, I expect the translate values of its child to change. But when I select the child object after translating its parent, its translate values haven't changed.
Tried your example and used setFloat() on the plug, which appears to work fine.
import maya.api.OpenMaya as OpenMaya
def setPlugFloatValue(node, plugName, val):
fnSet = OpenMaya.MFnDependencyNode(node)
plug = fnSet.findPlug(plugName,True)
plug.setFloat(val)
def applyToSelectedObjects():
sl_list = OpenMaya.MGlobal.getActiveSelectionList()
iterator = OpenMaya.MItSelectionList(sl_list)
while not iterator.isDone():
obj = iterator.getDependNode()
setPlugFloatValue(obj, "translateX", -2.0)
iterator.next()
applyToSelectedObjects()
Perhaps your issue is something else? You can also try to use setMDistance() instead, but it didn't make any difference in my testing.
distance = OpenMaya.MDistance(val)
plug.setMDistance(distance)

Python-pptx: “Show legend overlapping the chart”

I am using Office 2007.
I found if I would like to show the legend overlapping the chart in office2007.
The XML should be as the following.
`-<c:legend>
<c:overlay val="1"/>`
But no matter I use the API from python-pptx 'chart.legend.include_in_layout = True' or I leave it as the default. The generated XML would always be as the following.
`-<c:legend>
<c:overlay/>`
Without the val=1, then office2007 won't show the format properly.
What can I do to force the python-pptx to write the val=1? thanks.
Explanation
In short, the True value is not explicitly set (in contrast to False) because True corresponds to the default value of overlay's val attribute.
To explain it in more detail - you can follow the python-pptx hierarchy as follows: overlay is mapped to CT_Boolean (all overlay oxml elements are instantiated from CT_Boolean). The actual val parameter is then mapped via OptionalAttribute and is defined with the default value of True:
class CT_Boolean(BaseOxmlElement):
"""
Common complex type used for elements having a True/False value.
"""
val = OptionalAttribute('val', XsdBoolean, default=True)
Now, when setting the optional attribute to its default value, it is actually skipped/deleted, as you can see here if value == self._default:
class OptionalAttribute(BaseAttribute):
"""
Defines an optional attribute on a custom element class. An optional
attribute returns a default value when not present for reading. When
assigned |None|, the attribute is removed.
"""
#property
def _setter(self):
def set_attr_value(obj, value):
if value == self._default:
if self._clark_name in obj.attrib:
del obj.attrib[self._clark_name]
return
str_value = self._simple_type.to_xml(value)
obj.set(self._clark_name, str_value)
return set_attr_value
Fix - provide custom CT_Boolean class
Add these lines somewhere before you need to use the overlay. It will overwrite python-pptx overlay mapping with the custom CT_Boolean_NoDefault class:
from pptx.oxml import register_element_cls
from pptx.oxml.xmlchemy import BaseOxmlElement, OptionalAttribute
from pptx.oxml.simpletypes import XsdBoolean
class CT_Boolean_NoDefault(BaseOxmlElement):
"""
Common complex type used for elements having a True/False value with no
default value.
"""
val = OptionalAttribute('val', XsdBoolean)
register_element_cls('c:overlay', CT_Boolean_NoDefault)
This worked for me and finally I got:
<c:legend>
<c:overlay val="1"/>
</c:legend>
Fix - modify python-pptx permanently
This is not recommended but you might want to modify python-pptx instead of adding the solution from above for each script you run.
First, add the following to pptx/oxml/chart/shared.py which defines a new bool class without a default value:
class CT_Boolean_NoDefault(BaseOxmlElement):
"""
Common complex type used for elements having a True/False value.
"""
val = OptionalAttribute('val', XsdBoolean)
Second, modify pptx/oxml/__init__.py to add the new bool class:
from .chart.shared import (
CT_Boolean, CT_Double, CT_Layout, CT_LayoutMode, CT_ManualLayout,
CT_NumFmt, CT_Tx, CT_UnsignedInt, CT_Boolean_NoDefault
)
Third, modify pptx/oxml/__init__.py to change the mapping of the overlay element to the new bool class:
register_element_cls('c:overlay', CT_Boolean_NoDefault)
Better solution
In case you have time, please submit a ticket here so it might become a permanent fix. In case #scanny finds some time, he will read this. Perhaps there is some better solution for this, too, and I've completely missed something.
#pansen 's analysis is spot-on. Here's an alternative way to get this working in your case that might be a little lighter weight:
def include_in_layout(legend):
legend_element = legend._element
overlay = legend_element.get_or_add_overlay()
overlay.set('val', '1')
This appears to be a localized non-conformance of that version of PowerPoint with the ISO/IEC 29500 spec. As pansen rightly points out, a missing val attribute is to be interpreted the same as val=1 (True). I'd be interested to discover how extensive this non-conformance goes, i.e. what other elements exhibit this same behavior. The CT_Boolean type is used quite frequently in PowerPoint, for things like bold, italic, varyColors, smooth, and on and on. So a "compensating" fix would need to be applied carefully to avoid reporting incorrect results for other elements.
I think I'll take pansen's cue and use a specialized element class for this element only. It will still report True for an element without the val attribute, which will be inconsistent with the observed behavior on this version of PowerPoint; but assuming other versions behave correctly (according to the spec), the inconsistency will be localized and at least assigning True to that property will make the legend show up the way you want.

Loop doesn't work, 3-lines python code

this question is about blender, python scripting
I'm completely new in this, so please excuse me for any stupid/newbie question/comment.
I made it simple (3 lines code) to make it easy addressing the problem.
what I need is a code that adds a new uv map for each object within loop function.
But this code instead is adding multiple new UV maps to only one object.
import bpy
for x in bpy.context.selected_objects:
bpy.ops.mesh.uv_texture_add()
what's wrong I'm doing here??
Thanks
Similar to what Sambler said, I always use:
for active in bpy.context.selected_objects:
bpy.context.scene.objects.active = active
...
These two lines I use more than any other when programming for Blender (except import bpy of course).
I think I first learned this here if you'd like a good intro on how this works:
https://cgcookiemarkets.com/2014/12/11/writing-first-blender-script/
In the article he uses:
# Create a list of all the selected objects
selected = bpy.context.selected_objects
# Iterate through all selected objects
for obj in selected:
bpy.context.scene.objects.active = obj
...
His comments explain it pretty well, but I will take it a step further. As you know, Blender lacks built-in multi-object editing, so you have selected objects and one active object. The active object is what you can and will edit if you try to set its values from python or Blender's gui itself. So although we are writing it slightly differently each time, the effect is the same. We loop over all selected objects with the for active in bpy.context.selected_objects, then we set the active object to be the next one in the loop that iterates over all the objects that are selected with bpy.context.scene.objects.active = active. As a result, whatever we do in the loop gets done once for every object in the selection and any operation we do on the object in question gets done on all of the objects. What would happen if we only used the first line and put our code in the for loop?
for active in bpy.context.selected_objects:
...
Whatever we do in the loop gets done once for every object in the selection but any operation we do on the object in question gets done on only the active object, but as many times as there are selected objects. This is why we need to set the active object from within the loop.
The uv_texture_add operator is one that only works on the current active object. You can change the active object by setting scene.objects.active
import bpy
for x in bpy.context.selected_objects:
bpy.context.scene.objects.active = x
bpy.ops.mesh.uv_texture_add()
note: I am not really familiar with blender
It seems that bpy.ops operations depend on the state of bpy.context. The context can also be overridden per-operation.
I assume that uv_texture_add() only works on a single object at a time?
Try something like this:
import bpy
for x in bpy.context.selected_objects:
override = { "selected_objects": x }
bpy.ops.mesh.uv_texture_add(override)
That should run the operations as if only one object was selected at a time.
Source:
https://www.blender.org/api/blender_python_api_2_63_17/bpy.ops.html#overriding-context

gtk ComboBoxEntry.get_child() returns none

I have a problem with the gtk ComboBoxEntry. My program crashes when I try to change the text in the combobox. I use this code:
gui.combo_txt_script.get_child().set_text(fshort)
It crashes with the error:
AttributeError: 'NoneType' object has no attribute 'set_text'
The results of the following prints:
print "combo:",gui.combo_txt_script
print "entry:",gui.combo_txt_script.get_child()
is
combo: <gtk.ComboBoxEntry object at ... >
entry: None
UPDATED
The get and set current value of Gtk.ComboBox objects is related to model attribute of these objects and you can set and/or get items similar below code:
model = combo.get_model()
value = model[combo.get_activate()][0]
# first index refers to row of list
# second index refers to cell in the row. by default an combo/combo-entry have one cell
combo.set_activate(list(model).index(value))
I found the problem. The program I use has different user levels. Every tab and thus every widget is not visible for every user level. Somehow, it happened that the user level could change by itself, which made the combo non existent.

Categories

Resources