choose checkbox in QListWidgetItem - python

I have this code with pyqt5:
elif (content1 == "next"):
todos = ["one" , "two" , "three" , "four", "five"]
self.todo_listWidget.show()
for todo in todos:
item = QListWidgetItem(todo)
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
item.setCheckState(QtCore.Qt.Unchecked)
self.todo_listWidget.addItem(item)
And I want if i chose one item make something
like if item (x) is checked then do something
how can i do this?
thanks

Connect the itemChanged signal of self.todo_listWidget with a function that takes the item as its argument.
This signal is emitted whenever the data of item has changed.
In the function, you can check the resp. item's checkState and proceed accordingly.
An alternative is itemActivated. Which one works better for you depends on if you want to react to all (also programmatical) changes of the check state or only to user interaction.
This signal is emitted when the item is activated. The item is activated when the user clicks or double clicks on it, depending on the system configuration. It is also activated when the user presses the activation key (on Windows and X11 this is the Return key, on Mac OS X it is Command+O).

Related

How to trigger a function after clicking on a list item in a QListWidget? PyQt5

I want to know how to trigger the function "self.runEverything" when a specific item in a list widget is selected.
I tried this but nothing is happening because I am not entering the if-statement.
if(self.listwidget.item(0).isSelected()):
self.runEverything(filepath)
You may want to check QListWidget currentRowChanged signal.
So, depending on the thing you want:
# example call
# QListWidget::currentRowChanged() emits an int value.
self.listwidget.currentRowChanged.connect(self.slotOrLambdaFunction)
def slotOrLambdaFunction(self, idx : int):
if idx == 0:
self.runEverything(filePath)
And then trigger stuff you need from the currently selected row in the widget.
You can also use QListWidget::itemClicked(QListWidgetItem item).

Tkinter - Selecting an item from a Treeview using single click instead of double click (Callback on Treeview item selection)

When you want to select an item in a Treeview, you usually use the double-click:
def print_element(event):
print(my_treeview.selection()[0])
my_treeview.bind("<Double-1>", print_element)
Today I tried to do the same but using a single click instead:
my_treeview.bind("<Button-1>", print_element)
But it wouldn't work. The output was just an empty tuple.
I started to search online for an explanation... why is it not working?
EDIT:
My goal was actually to do something every time a treeview item was selected.
I proposed a solution myself using the identify() function of Tkinter
Another user proposed to use the Tkinter callback <ButtonRelease-1> which is much more appropriate
Finally, a third user focused his answer on using the Tkinter callback <<TreeviewSelect>>, which is for sure the best option
The reason it doesn't work the way you expect is because your custom single-click binding happens before the default behavior. So, when your single-click is processed, that happens before an item is selected. The second time you click, your function will print the previously selected item.
If you want to have a function called when an item is selected, you should bind to <<TreeviewSelect>>, which will fire immediately after the user selects an item with a single click or via the keyboard.
The default behavior of a treeview supports selecting multiple items at once, so the following code will print out the text of all of the selected items as a list, even if only a single item is selected. You can, of course, modify this to only print out the first selected item if you so desire.
def print_element(event):
tree = event.widget
selection = [tree.item(item)["text"] for item in tree.selection()]
print("selected items:", selection)
tree.bind("<<TreeviewSelect>>", print_element)
It is because the selection is not set yet when the <Button-1> (it is the same as <ButtonPress-1>, i.e. when the mouse button 1 is pressed and not released) event callback is called.
You should bind on <ButtonRelease-1> or <<TreeviewSelect>> instead as the selection is set when the event callback is being executed.
Why it doesn't work
When you click an item in a treeview, that item is still not in a SELECTED status in the moment the callback is activated. You are changing the status in that very moment.
Using a double-click, the first click change the status, and at the second click you are activating your callback, so the status has already been changed.
How can it work
Kudos to this website
In short,
def print_element(event):
print(my_treeview.identify('item', e.x, e.y))
my_treeview.bind("<Button-1>", print_element)
This time, print_element() will check the coordinates of the mouse, and will discover the selected item check what is under the mouse. Nice and clean!

How to enable a button only when two comboboxes have been activated

I have two combo boxes, and this is my attempt to enable a button only when options in both boxes are selected.
However, when I select only one comboBox, the button will enable itself.
if self.page2.comboBox2.activated and self.page2.comboBox.activated:
self.page2.viewbutton.setEnabled(True)
else:
self.page2.viewbutton.setEnabled(False)
Your code won't work, because the activated attribute is a signal object, which will always evaluate to True. If you are using comboboxes like the ones in your other question, then you need to check the current index to see whether the user has selected a valid option:
if (self.page2.comboBox2.currentIndex() > 0 and
self.page2.comboBox.currentIndex() > 0):
self.page2.viewbutton.setEnabled(True)
else:
self.page2.viewbutton.setEnabled(False)
That is, if the current index is zero, the "Select product" message is still shown.

PyQt - trigger an event when nothing is selected in a QListWidget?

I have an object of type QListWidget where the user can select 0 or more items.
If nothing is selected, how can i trigger an event that would call a function?
I know that you can detect clicking on a specific item by using:
QListWidget.itemClicked.connect(self.item_click)
Is there something similar for when nothing is selected at all? (or in other words, the QListWidget is clear)
Thanks!
Generally, you would connect to the itemSelectionChanged signal and then check whether anything is selected.
self.listwidget.itemSelectionChanged.connect(self.on_selection_changed)
def on_selection_changed(self):
if not self.listwidget.selectedItems():
# Do Stuff Here
self.nothing_selected_function()
But that will only catch events where something was selected and then the user deselected everything. If nothing was ever selected, it's not going to trigger this signal (like the first time you build the list, and nothing is selected). You'd have to call the slot manually in that case.
self.listwidget = ... # Code that builds and populates list widget
# Call this manually the first time.
self.on_selection_changed()
But part of your question is ambiguous. Why do you want to know when something is "not selected"? What about when a new item is added to the list? Should it trigger your "not selected" function since the list has changed, but there still isn't anything selected?

GTK+: How do I process RadioMenuItem choice without marking it chosen? And vise versa

In my program, I've got a menu with a group of RadioMenuItem entries. Choosing one of them should trigger a function which can either succeed or fail. If it fails, this RadioMenuItem shouldn't be marked chosen (the previous one should persist). Besides, sometimes I want to set marked item without running the choice processing function.
Here is my current code:
# Update seat menu list
def update_seat_menu(self, seats, selected_seat=None):
seat_menu = self.builder.get_object('seat_menu')
# Delete seat menu items
for menu_item in seat_menu:
# TODO: is it a good way? does remove() delete obsolete menu_item from memory?
if menu_item.__class__.__name__ == 'RadioMenuItem': seat_menu.remove(menu_item)
# Fill menu with new items
group = []
for seat in seats:
menu_item = Gtk.RadioMenuItem.new_with_label(group, str(seat[0]))
group = menu_item.get_group()
seat_menu.append(menu_item)
if str(seat[0]) == selected_seat: menu_item.activate()
menu_item.connect("activate", self.choose_seat, str(seat[0]))
menu_item.show()
# Process item choice
def choose_seat(self, entry, seat_name):
# Looks like this is called when item is deselected, too; must check if active
if entry.get_active():
# This can either succeed or fail
self.logind.AttachDevice(seat_name, '/sys'+self.device_syspath, True)
Chosen RadioMenuItem gets marked irrespective of the choose_seat() execution result; and the only way to set marked item without triggering choose_seat() is to re-run update_seat_menu() with selected_seat argument, which is an overkill.
I tried to connect choose_seat() with 'button-release-event' instead of 'activate' and call entry.activate() in choose_seat() if AttachDevice() succeeds, but this resulted in whole X desktop lockup until AttachDevice() timed out, and chosen item still got marked.
In my opinion a different approach would be better. When the user clicks an item, display a spinner or something to let the user know an operation is going on, then do your long-running choose_seat() in the background. If it fails, then change the radio button to non-active and set it to be insensitive (since you now know it doesn't work.)
Thanks to help from people on irc.gnome.org/gtk+, I've got this with handler_block_by_func()/handler_unblock_by_func():
# Update chosen seat menu item (without triggering choose_seat)
def update_chosen_seat(self, seat):
self.seat_menu_items[seat].handler_block_by_func(self.choose_seat)
self.seat_menu_items[seat].activate()
self.seat_menu_items[seat].handler_unblock_by_func(self.choose_seat)
And in choose_seat() I use the same approach to activate previously chosen item, then run actual handler code and activate chosen item if it succeeds.

Categories