Clicked Connect Method Triggger more than once - python-3.x

I've function as a edit_parameters when I changed value on my edit_table. When I open the edit table screen edit_parameters function working.
def edit_parameters(self):
self.ui.edit_table.setEditTriggers(QtWidgets.QTableWidget.CurrentChanged)
oldListValue = []
for i in range(0, 46):
oldListValue.append(self.ui.edit_table.item(i, 1).text())
self.ui.changeButton.clicked.connect(partial(self.write_changed_value_to_device,0,oldListValue))
Than I define changeButton in above function, so I expect when I click this button, write_changed_value_to_device calling once. But when I click the button sometimes this function calling more than once
def on_write_changed_value_to_device(self,changeType,oldListValue = []):
print("changed")
When I click once, I see:
changed
changed
changed
Why this happenning I want to call only once when I click the button.

Related

Qt: QFormLayout - How to find the row from the button

How to find the row number of QFormLayout() from a button which is in that row? I have a delete button on each row of the form. Such that if I click the delete button, that specific row will get deleted. For this, I am planning to use the command QtWidgets.QFormLayout.removeRow(row) command. I have defined the QFormLayout() within my def __init__(self): function like so.
self.attachForm = QFormLayout()
I also have an Add button which calls the self.attachBtn_clicked(self) function given below. So every time the Add button is clicked a new row is added. Any help will be appreciated.
def attachBtn_clicked(self):
hbox = QHBoxLayout()
self.attachForm.addRow('',hbox)
browseBtn = QPushButton("Open")
hbox.addWidget(browseBtn)
addAttachEdit = QLineEdit()
hbox.addWidget(addAttachEdit)
delAttachBtn = QPushButton("x")
delAttachBtn.setFixedSize(15,15)
delAttachBtn.clicked.connect(self.delAttachBtn_clicked)
hbox.addWidget(delAttachBtn)
The objective is now to write the self.delAttachBtn_clicked(self) function which will delete the specific row.
You can iterate through the rows and find the button that matches the sender.
def delAttachBtn_clicked(self):
for i in range(self.attachForm.rowCount()):
if self.sender() == self.attachForm.itemAt(i, QFormLayout.FieldRole).itemAt(2).widget():
self.attachForm.removeRow(i)
return
itemAt(2) is used since delAttachBtn is the 3rd item in each QHBoxLayout.

How to give button ID when calling a create button function

Please excuse my ignorance as I'm new to Python and am experimenting.
I am creating a dashboard that allows users to open a file. When a user opens a file, the software adds a row with the file name, progress bar and a few buttons all on the same row. The row creation is done by calling a function which increments the row value every time its called to ensure it doesn't replace the existing row but instead adds another row beneath it to represent the latest file opened by the user.
Lets say there are two rows on the dashboard with their respective file names and buttons. My problem is when I go to press the button on the first row, it thinks that I'm pressing the button on the second row simply because the counter is set to 2 when adding a second row and I am trying to identify which button the user is pressing by checking the row but am unable to do that due to the counter.
Is there anyway I can "bind" the row value to the button when declaring it when calling the create button function so that they keep some form of ID and I can tell which row the user is interacting with?
I have tried assigning the button an ID when calling the function to identify which button is being pressed and on what row, but the button gets overwritten on all rows when the function is called again.
I have also tried to check what button the user is pressing by checking the text of the button, but that also gets overwritten when the function is re-called regardless if the names of the buttons are different on the UI itself.
Any help is very much appreciated. Hopefully I was clear enough.
def OpenFile(self): # user opening file which creates row with button
print("Opening")
btnCreation(self)
def btnCreation(self): # function to create buttons dynamically
incrementFunction(self)
global EXEBtn
EXEBtn = Button(Main_frame,
text="Execute",
width=8,
command=self.Execute)
EXEBtn.grid(row=RowCounter, column=2, padx=3)
def incrementFunction(self):
global RowCounter
RowCounter = RowCounter + 1
def Execute(self):
# check which row the execute button was pressed on to do something
A simple and quick solution is just to give the function the current RowCounter value with a lambda expression like this:
def btnCreation(self): # function that creates button dynamically
incrementFunction(self)
global EXEBtn
EXEBtn = Button(Main_frame,
text="Execute",
width=8,
command=lambda e=RowCounter: self.Execute(e))
EXEBtn.grid(row=RowCounter, column=2, padx=3)
The specific change here is command=lambda e=RowCounter.get(): self.Execute(e), changing the way the buttons command works. Basically it is creating a lambda expression that saves the value of RowCounter, which will be passed to the Execute() function when the button is pressed.

QTableView: Prevent a user from navigating away from a spesific row

I am having trouble preventing the user form changing the current selection, if the save action did not complete successfully. I can re-select a row using the QTableView's selection models' currentRowChanged signal but although the selection change, the blue selection indicator does not. See the image below.
Example: In the image below the user attempted to add a new row nr 537. But the save action got an error and I don't want the user to navigate away from row 537 before the record is either deleted or edited and then saved
Question: How do I move the blue line to the current selection? (the current selection is the last row) (The QTableView's Selection Behavior is set to select rows)
Here is the code I got so far:
def __init__(self, parent):
...
self.__tableViewSelectionModel = self.__ui.tableView.selectionModel()
self.__tableViewSelectionModel.currentRowChanged.connect(self.rowChanged)
def rowChanged(self, current=None, previous=None):
if save() == True:
self.__ui.tableView.clearSelection()
self.__ui.tableView.selectRow(previous.row())
Replacing this:
self.__ui.tableView.clearSelection()
self.__ui.tableView.selectRow(previous.row())
with this:
QtCore.QTimer.singleShot(0.00001, lambda: self.__ui.tableView.selectRow(previous.row()))
produced the desired outcome

Error appears when curselection bind to ListBox returns empty tuple after clicking in other widget

I have an issue with curselection of ListBox. It appears in Python 3.6. In Python 3.4 everything works fine. My code selects items from ListBox and put it in Entry widget. It works perfectly well when i click on the items in ListBox. But sometimes (after 5-10 clicks) when I click in Entry widget an error appears:
_tkinter.TclError: bad listbox index "": must be active, anchor, end, #x,y, or a number
Here's my code sample:
from tkinter import *
def insert_into_entry(event):
index=list_box.curselection()
print(index)
selected_item=list_box.get(index)
entry1.delete(0,END)
entry1.insert(END,selected_item)
window=Tk()
entry=Entry(window)
entry.grid(row=0,column=0)
list_box=Listbox(window,height=5,width=45)
list_box.grid(row=1,column=0)
list_box.bind('<<ListboxSelect>>',insert_into_entry)
entry1=Entry(window)
entry1.grid(row=2,column=0)
a=['one','two','three','four']
for i in a:
list_box.insert(END,i)
window.mainloop()
I tried to examine changes in index value. And error brings about when after clicking in Entry widget index returns empty tuple. It's my first question so I'll be greatfull for every response.
From what I can see by testing <<ListboxSelect>> I believe that the <<ListboxSelect>> event activates every time the selection changes even if that selection changes to "nothing selected". I believe this is why when you click off of the listbox and into any other field and the <<ListboxSelect>> event is triggered your insert_into_entry function is getting an empty tuple from curselection().
According to the documentation here the courselection() method will return an empty tuple if nothing is selected.
To avoid any errors we can first check if the results of ndex = list_box.curselection() are not equal to () an empty tuple. If not then perform the rest of the function. This should prevent any errors caused by this behaviour with the <<ListboxSelect>> event being called outside of the listbox.
Oh and one other thing. Don't use built in names for variable names. change index = list_box.curselection() to something like ndex = list_box.curselection()
from tkinter import *
window=Tk()
def insert_into_entry(Event = None):
ndex = list_box.curselection()
if ndex != ():
selected_item=list_box.get(ndex)
entry1.delete(0,END)
entry1.insert(END,selected_item)
entry=Entry(window)
entry.grid(row=0,column=0)
list_box=Listbox(window,height=5,width=45)
list_box.grid(row=1,column=0)
list_box.bind('<<ListboxSelect>>', insert_into_entry)
entry1=Entry(window)
entry1.grid(row=2,column=0)
a=['one','two','three','four']
for i in a:
list_box.insert(END,i)
window.mainloop()

Tkinter, How to do destroy the button I click in a grid made by a for loop

for x in range(xBtns):
for y in range(yBtns):
btn = Button(board, width=2, height=1)
btn.grid(column=x, row=y)
btn.bind('<Button-3>', btnFunction)
Where btnFunction deletes the button that was right-clicked
The event object that is passed to a bound function contains a reference to the widget that received the event:
def btnFunction(event):
event.widget.destroy()
You can just do:
canvas.delete("all")
when the button is clicked.

Resources