GtkComboBox invoking a warning about get_active_iter? - python

I have a GtkComboBox's changed signal connected to the following function:
def changeCombo(self, widget):
selected = self.ui['comboBox'].get_active_iter()
...
This sort-of-works. However, when the combo's associated model -- a ListStore -- is emptied (and rebuilt), I get this error when the function is invoked:
AttributeError: 'gtk.TreeView' object has no attribute 'get_active_iter'
Thereafter, the code destabilises and stops working properly. (If you select a valid entry, before getting this warning, it works fine.)
What's going on here? I realise the combobox is probably implemented as a TreeView by GTK, but get_active_iter is definitely a member of ComboBox... Does this error imply that the availability of this function is contingent on the model containing items? The documentation, however, implies that a combobox without a selection (or an empty model) should return None for get_active_iter.

Related

PyQT5: What's this boolean passed when a menu action is triggered?

So I'm relatively new at Python, and I've been trying to learn PyQt. I wanted to create a menu dynamically based on the contents of a list. I found an example which I adapted and it looked like this:
for someText in myList:
entry = QAction(someText,MainWindow)
self.myMenu.addAction(entry)
entry.triggered.connect(lambda menuItem=someText: self.doStuff(menuItem))
entry.setText(someText)
The menu was created but when a menu item was chosen doStuff() always got passed a value of False. So I changed the above to:
for someText in myList:
entry = QAction(someText,MainWindow)
self.myMenu.addAction(entry)
entry.triggered.connect(lambda bVal, menuItem=someText: self.doStuff(bVal,menuItem))
entry.setText(someText)
and sure enough everything now works as I'd like. I still get the False in bVal which I just ignore.
I've tried looking at the PyQt documentation but the reference section links to the C++ documentation and it's not obvious to me from that what's going on.
I'd like to understand what the boolean value is and why, in my case, it's always False. I've tried changing various things but I haven't managed to find a scenario where it's True.
Thanks
PyQT5.4, Python 3.4.2 on Windows.
The C++ documentation for the triggered signal shouldn't be too hard to understand:
void QAction::​triggered(bool checked = false)
...
If the action is checkable, checked is true if the action is checked, or false if the action is unchecked.
So the signal is emitted with a boolean parameter which indicates the action's 'checked' state, and this parameter overwrote the default value for your menuItem argument.

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.

Connect PySide to a signal using QSignalMapper and an instance method

I have a small app with a table. This table has some data and a button on each row. These buttons should allow the user to remove corresponding row data. I'm trying to implement it via the clicked button signal, but I need to pass the row number, so I tried using QSignalMapper, as shown in the excerpt below
btnRemoveItem = QPushButton()
btnRemoveItem.clicked.connect(self.removeItem)
self.mapper = QSignalMapper(self)
self.connect(btnRemoveItem, QtCore.SIGNAL("clicked()"), self.mapper,
QtCore.SLOT("map()"))
self.mapper.setMapping(btnRemoveItem, nextRow)
self.connect(self.mapper, QtCore.SIGNAL("mapped(int)"), self.removeItem(),
QtCore.SIGNAL("clicked(int)"))
Problem is, my removeItem(self, index) method is an instance method (because my table belongs to a specific class) and I'm having trouble mapping it in a way I can pass self along with index.
Currently, my code fails with the following error:
TypeError: removeItem() takes exactly 2 arguments (1 given)
Is there a way to make this work correctly? Or is it impossible to map instance methods with QSignalMapper in PySide?
I tried to reproduce your code in PyQt but I'm not fully aware of the differences between Pyside and PyQt so my answer is more of a guess.
Try to remove the second line of your code and replace the last one with:
self.mapper.mapped.connect(self.removeItem)
In the last line of your code, in the connect method, I believe you have a typo in your code
self.connect(self.mapper, QtCore.SIGNAL("mapped(int)"), self.removeItem(),
QtCore.SIGNAL("clicked(int)"))
should be
self.connect(self.mapper, QtCore.SIGNAL("mapped(int)"), self.removeItem,
QtCore.SIGNAL("clicked(int)"))
Having self.removeItem() in the connect method will actually try to call the self.removeItem method rather than providing the subsystem an address to connect the function
As finmor suggests, you should look at new syntax signals and slots as they will dramatically help to clarify your code and make it more Pythonic.

PyQt TypeError connect()

I'm very new to Python, so I'm sorry ahead of time if this is a simple mistake.
class TaskTabs(QtGui.QTabWidget):
...(some init stuff here)....
def remove(self):
self.removeTab(0)
self.addTab(Tabs.General(self.nao, self.parent), 'General')
In another class:
self.taskTabs = TaskTabs(self.nao, mainWidget)
....(Some other stuff here)....
loadEmpathy = QtGui.QAction(QtGui.QIcon(), '&Load Empathy', self)
loadEmpathy.setShortcut('Ctrl+E')
loadEmpathy.triggered.connect(self.taskTabs.remove())
There error that I am getting is:
TypeError: connect() slot argument should be a callable or a signal, not 'NoneType'
What I am trying to do is to remove a tab in my GUI and add in various ones (which I'll implement later, just testing this now) from a menu. My menu code works perfectly, and now I want to set an action for what happens when it's clicked. I created this remove method in my TaskedTabs file, the remove function works great in my init function, but I want to separate it (for purposes later on). Can anyone explain what is wrong with my code?
As the error message says, connect() needs a callable method. But what you are giving it is the result of a method, because you're calling it. remove() returns None, which is then used as the argument for connect(), which doesn't work. Solve this by removing the brackets after remove.
loadEmpathy.triggered.connect(self.taskTabs.remove)

A sorted and filtered treemodel in Python Gtk+3..?

I am trying to get a treemodel (a liststore in fact) that can be filtered and also sorted. I have the following piece of code
self.modelfilter = self.liststore.filter_new()
self.modelfilter.set_visible_func(\
self._visible_filter_function)
self.treeview.set_model(self.modelfilter)
where self.liststore and self.treeview are standard Gtk.ListStore and Gtk.TreeView objects that I get from a glade file, and self._visible_filter_function is a filtering function.
The problem is that self.modelfilter does not seem to be sortable. When I click on the column headers (of the columns in self.treeview) to sort them, I get
Gtk-CRITICAL **: gtk_tree_sortable_get_sort_column_id: assertion `GTK_IS_TREE_SORTABLE (sortable)' failed
saying that the treemodel is not sortable.
This problem seems to be surmountable in PyGtk as suggested here. The idea is to stack a ListStore, a TreeModelFilter and a TreeSortFilter one inside the other and feed the last one as the model for the treeview.
However this trick does not seem to be working in Python Gtk+3. When I try
self.modelfilter = self.liststore.filter_new()
self.modelfilter.set_visible_func(\
self._visible_filter_function)
self.sorted_and_filtered_model = \
Gtk.TreeModelSort(self.modelfilter)
self.treeview.set_model(self.sorted_and_filtered_model)
it complains
Gtk.TreeModelSort(self.modelfilter)
TypeError: GObject.__init__() takes exactly 0 arguments (1 given)
Now I tried to get a instance of Gtk.TreeModelSort with no arguments. But this instance does not have any set_model method.
I am lost here.
Is there another way to set the model for Gtk.TreeModelSort? Or is there a totally different way to get a filtered and sortable treemodel object that can be displayed in a treeview?
>>> from gi.repository import Gtk
>>> mymodel = Gtk.ListStore()
>>> Gtk.TreeModelSort(model=mymodel)
<TreeModelSort object at 0x1d4d190 (GtkTreeModelSort at 0x1f0d3f0)>
In my opinion PyGObject is not ready yet. It has no browsable documentation, some things are not instrospected yet and in particular this:
Sometimes a widget work with Gtk.MyWidget(attr=foo), like this one.
Sometimes with Gtk.MyWidget.new_with_label('Foo'), like buttons. Yes, Gtk.MyWidget(label='Foo') doesn't work.
Kind regards

Categories

Resources