PySide - Get list of all visible rows in a table - python

Given that I have an instance of QTableView (or a subclass thereof), connected to a subclass of QAbstractTableModel (or functionally equivalent model + view), is it possible to get a list of the indexes of all rows currently visible to the user (i.e. those not falling outside the current scroll range)?
It would be great if the solution scales to different window/screen sizes.

You can obtain the item position using QAbstractItemView::visualRect. It is in the viewport coordinates, so we need to check if it is in the viewport rect. Here is an example:
viewport_rect = QRect(QPoint(0, 0), self.view.viewport().size())
for row in range(0, self.model.rowCount()):
rect = self.view.visualRect(self.model.index(row, 0))
is_visible = viewport_rect.intersects(rect)
This example works only with one column, but you can add a for loop for iterate over all columns.
In this code items are considered visible if they are partially visible. If you want to get only items that are completely visible, use contains instead of intersects.

Related

Does npyscreen support clickable grid rows?

npyscreen lets you create a grid, and even set select_whole_line=True so that an entire line is selected when you move through the grid with your arrow keys. Is it possible to do something when the user picks a row in the grid and hits enter?
Turns out I can add this to my form class' create method:
self.grid_widget.add_handlers({curses.ascii.NL: self.do_stuff})
And then this to the form class:
def do_stuff(self, input):
self.MyText.value = self.grid_widget.selected_row()
self.MyText.display()
Note that I tried using curses.KEY_ENTER instead of curses.ascii.NL, but that didn't seem to work for some reason.

How to modify tags in Tkinter Canvas by events

I am programmatically adding tag_binds to all objects on my canvas that have the tag "tag":
self.canvas.tag_bind("tag","<Button 2>",self.tag_highlight)
self.canvas contains all the objects that the user has added (all tagged with "tag".
However, in tag_highlight, I would simply like to have a handle on the actual element within the canvas. event.widget doesn't seem to help, its just a tuple of 4 floats that I cannot link to any canvas item. I have tried to use the following, to no avail:
self.canvas.find_closest(event.x,event.y)
What I would like to do, is have a handle like:
t=self.canvas.getitem(event.widget)
so that I can use it for example in:
self.canvas.Move(t,30,20)
print self.canvas.coords(t)
and so forth.
Maybe I am just missing the obvious?
You can use the tag "current", which refers to the "current" object. The current object is described like this in the official tk documentation:
The tag current is managed automatically by Tk; it applies to the
current item, which is the topmost item whose drawn area covers the
position of the mouse cursor (different item types interpret this in
varying ways; see the individual item type documentation for details).
If the mouse is not in the canvas widget or is not over an item, then
no item has the current tag.

asigning ids in kivy on the python side

im using kivy. the what im trying to do is have and 'idea',a slider and a label containing the slider's current value in a row in a grid layout
now getting the layout is fine but getting the label to have a text value the same as the slider's current value is tricky. I'm trying to use string concation to refer to the label with the same number suffix as the slider that it is paired with.
I think the problem im having is that im trying to assign ids on the python side when they normally have to be done on the kv side. It's either that or the fact the ids i'm assigning are strings when kv would normally expect plain text. any help would be appreciated
class ScatterTextWidget(FloatLayout):
def run_me(self):
r=1
main_list=self.ids.main_list
main_list.clear_widgets()
main_list.height=0
for idea in imported_ideas:
main_list.add_widget(Label(text=idea,color=(0,0,0,1),id='idea_label_'+str(r)))
main_list.add_widget(Slider(id='Slider_'+str(r),min=0,max=10,value=5, step=1,on_value_pos=self.slider_slid(self)))
main_list.add_widget(Label(color=(0,0,0,1),id='value_label_'+str(r)))
value_label=self.ids['value_label_'+str(r)] # get this working and then apply the method into slider slid
value_label.text='xxx'
main_list.height+=35
r +=1
button_1=self.ids.button_1
button_1.text='Begin'
button_1.bind(on_press=self.begin)
def slider_slid(self,sender):
s=str(sender.id)
value_label=self.ids['value_label_'+str(s[12:])]
value_label.text=str(sender.value)
value_label=self.ids['value_label_'+str(s[12:])]
KeyError: 'value_label_'
self.ids only collects ids from children in the kv language rule of the widget. It doesn't know about widgets you added via python.
You don't need to use the id though. In this case you could keep e.g. a dictionary of id -> widget keys.
self.keys_dict = {}
for idea in imported_ideas:
new_widget = Label(color=(0,0,0,1),id='value_label_'+str(r)))
main_list.add_widget(new_widget)
self.keys_dict['value_label_' + str(r)] = new_widget
Then later you can access it with self.keys_dict['value_label_' + str(s[12:])] or whatever you like.
I suppose in practice you could also modify the actual ids dictionary in the same way, though I subjectively feel it is preferable to maintain your own dictionary with a name that represents its more specific contents.

Refreshing panel contents in wxPython

What is the approach to update widgets in a wxPanel based on events from other controls on same panel?
Scenario 1 is updating the list of a comboBox based on what has been selected from another comboBox , where both are in same panel.
Scenario 2 is showing a new control/widget in a panel based on an event.
Basically creating new controls is easy but I dont know how to refresh/update my panel so immedialtly shows them.
Scenario 1
To change the choices of a combobox self.cbx you can use any of the following methods:
self.cbx.SetItems(choices) where choices is the full list of choices.
self.cbx.SetString(n, string) that sets the string at position n.
InsertItems(items, pos) Inserts the list of strings in the items argument into the list box before the position in the pos argument.
Note that the method Set(choices) of listboxes does not exist for the list in comboboxes. You must use SetItems(choices) instead (this is not clearly indicated in some textbooks).
If you want these changes to occur as a result of a selection in another combobox self.cbx_1 , just get the event (self.Bind(wx.EVT_COMBOBOX, on_combo_1, self.cbx_1)) of the first combobox, process your data as you like in the corresponding self.on_combo method and use one of the above methods to modify the second combobox.
For example:
def on_combo_1(self, evt):
"append cbx_1 selection to cbx if not already in cbx"
selection = self.cbx_1.GetStringSelection()
cbx_choices = self.cbx.GetItems()
if selection not in cbx_choices:
cbx_choices.append(selection)
self.cbx.SetItems(cbx_choices)
The fact the comboboxes are in the same or different panel is irrelevant for that.
Scenario 2
Normally you put your widgets inside sizers. To hide or made visible elements on the sizer you call the methods Show, Hide or Layout:
Show(self, item, show=True, recursive=false)
Shows or hides an item managed by the sizer. To make a sizer item disappear or reappear, use Show followed by Layout. The item parameter can be either a window, a sizer, or the zero-based index of the item. Use the recursive parameter to show or hide an item in a subsizer. Returns True if the item was found.
Hide(self, item, recursive)
A convenience method for Show (item, False, recursive).
Layout(self)
This method will force the recalculation and layout of the items controlled by the sizer using the current space allocated to the sizer. Normally this is called automatically from the owning window's EVT_SIZE handler, but it is also useful to call it from user code when one of the items in a sizer change size, or items are added or removed.
References: wxPython in Action, Noel Rappin and Robin Dunn
For scenario one, you'd do something like the following (assuming the first combobox is bound to its EVT_COMBOBOX:
value = self.cboOne.GetValue()
if value == "something":
self.cboTwo.SetItems(someList)
For showing a new widget, you could create it and then use Show()/Hide() as necessary. If the widget is in a sizer, then use the Sizer's Append or Insert methods. It also has a Detach method that can be used to hide widgets or you just call Hide itself. See the documentation for more information: http://www.wxpython.org/docs/api/wx.Sizer-class.html

Detect when column in gtk.treeview is resized

What signal can I catch to detect when a column changes size in a gtk.TreeView? I can't seem to find it in the docs.
gtk.TreeViewColumns aren't widgets so they unfortunately don't have a dedicated signal for size changes. But you can register a callback function that receives "width" change notifications:
def onColWidthChange(col, width):
# Note that "width" is a GParamInt object, not an integer
...
col.connect("notify::width", onColWidthChange)
In the example, col must be a gtk.TreeViewColumn object. If you don't initialize the columns in code, you can use gtk.TreeView.get_column to get these objects.
If you only need notifications when the treeview changes its size, you can use its "size-allocate" signal instead.

Categories