My question is if we can assign/bind some value to a certain item and hide that value(or if we can do the same thing in another way).
Example: Lets say the columns on ListCtrl are "Name" and "Description":
self.lc = wx.ListCtrl(self, -1, style=wx.LC_REPORT)
self.lc.InsertColumn(0, 'Name')
self.lc.InsertColumn(1, 'Description')
And when I add a item I want them to show the Name parameter and the description:
num_items = self.lc.GetItemCount()
self.lc.InsertStringItem(num_items, "Randomname")
self.lc.SetStringItem(num_items, 1, "Some description here")
Now what I want to do is basically assign something to that item that is not shown so I can access later on the app.
So I would like to add something that is not shown on the app but is on the item value like:
hiddendescription = "Somerandomthing"
Still didn't undestand? Well lets say I add a button to add a item with some other TextCtrls to set the parameters and the TextCtrls parameters are:
"Name"
"Description"
"Hiddendescription"
So then the user fills this textctrls out and clicks the button to create the item, and I basically want only to show the Name and Description and hide the "HiddenDescription" but to do it so I can use it later.
Sorry for explaining more than 1 time on this post but I want to make sure you understand what I pretend to do.
Instead of using the ListCtrl as your data structure, you could keep a separate list/dict of objects that contain all the information you want and refresh the ListCtrl from your other data structure.
For example:
class MyObject(object):
def __init__(self, name, description, hidden_description):
self.name = name
self.description = description
self.hidden_description = hidden_description
Then in your application:
def __init__(self):
self.my_items = {}
self.lc = wx.ListCtrl(self, -1, style=wx.LC_REPORT)
self.lc.InsertColumn(0, 'Name')
self.lc.InsertColumn(1, 'Description')
def addItemToMyListCtrl(self, name, description, hidden):
new_item = MyObject(name, description, hidden)
self.my_items[name] = new_item
self.lc.Append((new_item.name, new_item.description))
Then when you want to use your additional data you can just look up the correct item in the dictionary and your data will be there.
the wxListCtrl lets you associate arbitrary data with an item, that will not be displayed - read the docs for the following methods:
SetItemData
GetItemData
FindItemData
The wxListItem class also has GetData and SetData methods.
You could always set the width of the hidden column to zero, that might accomplish what you want. I just tried it in a C++ (non-wx) program and it worked fine.
wx.ListCtrl doesn't let you associate a python object with an item like wx.TreeCtrl does with its extremely useful SetPyData() method (and corresponding GetPyData()).
I haven't tried it myself, but there is code here that shows how to create a class to mix in python data with a list. Although I'll admit, it's not clear to me how you're meant to use it.
It also might be possible to directly inherit from wx.ListCtrl, and add the appropriate methods, but I haven't seen any attempts at that anywhere, so it may be harder than I'm thinking.
Alternately you can just use SetItemData() to store an int in each item, and use that int to index a dict (or list, if the items are ordered reliably and consistently) that contains the associated objects. tgray has already shown how to do this, and it's listed at the page I link above as well, so I won't go over it again.
Related
Codenerix
Has anyone knows how to use correctly ng-readonly in a GenModelForm when coming from a sublist tab (GenList) who calls a GenCreateModal windows?
Structure is a master-detail, sublist tab has pk of master table and calls GenCreateModal with this pk argument of master table.
GenCreateModal receives pk argument in his asociated form (the mentioned GenModelForm) and can use it. The goal is to disable field with ng-disabled if pk argument of master table is filled. This way when create from another list of detail table without arguments, field can be filled with a value selecting it with the dropdown, and when coming from master table it cannot be modified and it will be assigned to master pk value.
I tried to do it that way:
First assign 'client' on GenCreateModal with:
def get_initial(self):
client = self.kwargs.get('pk', None)
if client:
self.kwargs['client'] = client
return self.kwargs
Then read it on the GenModelform with:
def __init__(self, *args, **kwargs):
super(DetailForm, self).__init__(*args, **kwargs)
if kwargs.get('initial', None) and kwargs['initial'].get('client', None):
self.fields['client'].widget.attrs[u'ng-readonly'] = 'true'
But it do not work with dropdown fields. Field can be modified.
Cause is that in templatetags_list.py of codenerix we have:
def inireadonly(attrs, i):
field = ngmodel(i)
return addattr(attrs, 'ng-readonly=readonly_{0}'.format(field))
This code set ng-readonly to "true readonly_client" instead of "true" when it comes with value "true" from GenModelForm, values are concatenated.
I found a workaround with:
self.fields['client'].widget.attrs[u'ng-readonly'] = 'true || '
this way the end value will be "true || readonly_client" that result on "true" as desired when evaluated, but I think it is not the proper way.
On my personal fork of django-codenerix I have changed the function to (functions is on two py files, should change both):
def inireadonly(attrs, i):
field = ngmodel(i)
if attrs.get('ng-readonly', None) is None:
attrs = addattr(attrs, 'ng-readonly=readonly_{0}'.format(field))
return attrs
This way it respects the value when it comes filled form GenModelForm, but I'm not sure about inconveniences and collateral effects. For example when want to concatenate conditions, with that change should read old value, concatenate manually and set new value. I think it should be a better way to do it and 'ng-readonly=readonly_{0}'.format(field) should have a functionality that I haven't discovered yet. Don't want to lose it when I discover it. So I revert the change and look for another solution.
Currently I'm using
self.fields['client'].widget.attrs[u'ng-disabled'] = 'true'
and it goes OK, I'm using this way and I have no problem now, but I'm curious about the way to use ng-readonly if I need it on the future. That's because with ng-readonly we can select text on fields with the mouse for example and can not select it with ng-disabled. In some cases it could be of interest.
Has anyone knows how to use ng-readonly in a correct way?
Has anyone knows the functionality of 'ng-readonly=readonly_{0}'.format(field)?
You can define an extra attribute to your fields in your forms. Add {'extra': ['ng-disabled=true']} in the field of your GenModelForm, inside your __groups__ method. Example:
def __groups__(self):
g = [
(_('Info'), 12,
['client', 6, {'extra': ['ng-disabled=true']}],
)
]
return g
You should use ng-disabled as you are doing. This is the way we do it in Django Codenerix Example # Gibhub (lines 41 and 42) and this is how it has been developed for StaticSelects (line 228) as well.
Well, i'm a beginner using kivy framework, so i thought that someone here could help me.
My question is:
On my app, the user input a number n, then the app return n TextInput widgets. But how can i use the values inserted on each TextInput? The first part is easy to do, i did it by a list. (If someone know how to do it directly on kv file i would appreciate it). My issue is on second part, i need to use and manipulate these values (in TextInputs) later but i can't reach to them. I mean, i set up for each widget in the list an id, but i can't reach to .text attribute of them. Here is a piece of my code:
class FirstLayout(BoxLayout):
def next_layout(self):
self.clear_widgets()
secondLayout = Factory.SecondLayout()
number = NumericProperty()
# This 'number' variable came from another widget on kv file
textinput_list = []
# That list will receive as many TextInputs field as my variable 'number' said (by the loop for)
for i in range(int(self.number.text)):
textinput_list.append(TextInput())
textinput_list[i].id = "input" + str(i + 1)
# So for each textinput, i added a id named 'inputx' (where x is the number of the current
# iteration) my question resides here. How could i use those values (inside of each textinput
# on this list
# later? Because i'm not creating these widgets (TextInputs) on kv language so i don't know how to
# bind the ids for a new variable directly in .py file
secondLayout.container.add_widget(textinput_list[i])
self.add_widget(secondLayout)
If I understand your question right, you just have to make textinput_list a class variable. So this.
textinput_list = []
becomes
self.textinput_list = []
Lets say you have an object of FirstLayout called first. With first.textinput_list[0] you can access the first textinput and so on.
If you want to easily access the textinputs via id I would suggest using a dictionary, with the keys being the id's and the values being the inputs.
I was wondering of any function that can ease/solve above challenge. Basically, when a GUI (containing list and table widgets) starts. Whenever user click on each item in the list, the table should also responds to data corresponding to the list item. Refer to the following example for better understanding.
From time to time, the data in list or table can be removed, modified or added by user. I would also like to implement function to gather those. Currently, I am thinking of playing around python list and dict.
You can
use the QListWidget.itemClicked signal.
Connect it to a function, that takes an QListWidgetItem as argument.
Identify the item and act accordingly
Example
...
self.myListWidget.itemClicked.connect(self.showDataInTable)
....
def showDataInTable(item):
item_name = str(item.text()) # getting item name as python string
... # show data or do what ever you like
dataToShow = myDataDict[item_name]
I have a number of items in a QTreeView. Each item is generated using this class:
class Branch(QStandardItem):
def __init__(self, label, uri = None):
QStandardItem.__init__(self, label)
self.uri = uri
This is my actual tree:
class FileTree(QTreeView):
def __init__(self):
QTreeView.__init__(self)
def keyPressEvent(self, event):
if event.key() == Qt.Key_Space or event.key() == Qt.Key_Return:
crawler = self.selectedIndexes()[0].model().item(self.selectedIndexes()[0].row())
print(crawler.uri)
QTreeView.keyPressEvent(self, event)
As you can see, I'm a little unsure as to how to get the uri variable from the selected item. I found that selectedIndexes() returns a model and not the item itself. I'm not sure how to get from one to the other. Trying to get the item number using self.selectedIndexes()[0].row() was a bit of a shot in the dark, but it seems to ignore the various branches in the tree (for instance, it will give me a 0 for the first row in a branch, but won't tell me anything about what branch it's in).
What's the proper way to get the selected item from the QTreeView? Or is there a better way of detecting the spacebar or return keys being hit that would make this easier? There's a severe lack of Python documentation for Qt, so it's really hard to know if I'm ever doing things in a sensical manner.
You are calling the right function, it actually returns a QModelIndexList which is just a typedef for QList<QModelIndex> with the QModelIndex being the data structure that can point to any part of the tree. QModelIndex is not a Model in the sense of Model View Controller (MVC) but an adress of an object in a QAbstractItemModel which is the datastructure under all of Qt's ItemView objects, including your tree. You are actually pretty close, QAbstractModelIndex consists of a row, a column and a parent, which lets it adress any position in a hierarchical data structure. If you use the line
index = self.selectedIndexes()[0]
crawler = index.model().itemFromIndex(index)
you should get to the object that you are looking for.
As for documentation, even though there is no python specific documentation it helps to read through the official Qt documentation, the class hierarchy and functionality is still the same. There is very little C++ specific information in the docs.
Harald's answer didn't work for me, because I'm using a QSqlQueryModel as the model (I got the error {AttributeError}'QSqlQueryModel' object has no attribute 'itemFromIndex').
The below did the trick for me though, to get the 0th column data of the selected row:
dbQueryModel.itemData(treeView.selectedIndexes()[0])
I have created a custom Archetypes content type called "Résumé" and would like to enforce a limitation that lets a Member add only one item of this type inside a folder. Even better would be redirecting the member to the edit page of his or her item, if it already exists in that folder.
How can I enforce this limitation and provide this extra functionality?
A solution to a similar usecase for Plone 3 can be found in the eestec.base. We did it by overriding the createObject.cpy and adding a special check for this.
Code is in the collective SVN, at http://dev.plone.org/collective/browser/eestec.base/trunk/eestec/base/skins/eestec_base_templates/createObject.cpy, lines 20-32.
Well, it is a sort of validation constraint, so maybe add a validator to the title field that in reality does not bother about the title, but checks the user etc.? (I think a field validator is passed enough information to pull this off, if not, overriding the post_validate method or listening to the corresponding event should work.)
If you try this, bear in mind that post_validate is already called while the user is editing (ie on moving focus out of a field).
I dont't know if it's best practice, but you can hook up on def at_post_create_script from base object on creation and manage_beforeDelete on delete.
for example:
from Products.ATContentTypes.lib import constraintypes
class YourContentype(folder.ATFolder)
[...]
def at_post_create(self):
origin = aq_parent(aq_inner(self))
origin.setConstrainTypesMode(constraintypes.ENABLED) # enable constrain types
org_types = origin.getLocallyAllowedTypes() # returns an immutable tuple
new_types = [x for x in org_types if x! = self.portal_type] # filter tuple into a list
origin.setLocallyAllowedTypes(new_types)
def manage_beforeDelete(self, item, container)
BaseObject.manage_beforeDelete(self, item, container) # from baseObject
self._v_cp_refs = None # from baseObject
origin = aq_parent(aq_inner(self))
origin.setConstrainTypesMode(constraintypes.ENABLED) # enable constrain types
org_types = origin.getLocallyAllowedTypes() # returns an immutable tuple
new_types = [x for x in org_types].append(self.portal_type)
origin.setLocallyAllowedTypes(new_types)
Note: There is also a method called setImmediatelyAddableTypes(), which you may want to explore.
Note II: This does not survive content migration.