TableWidget "Enter" keypressed current text - python

I am using python, Pyside2 on my interface.
I have a tableWidget and I want to get current text after press enter.
So I have below codes:
I add below function in to current page open:
self.ui.edit_table.keyPressEvent = self.KeyPressed
Then I add below function:
def KeyPressed(self, event):
if event.key() == QtCore.Qt.Key_Return:
print('Enter Key Pressed')
self.ui.edit_table.setEditTriggers(QtWidgets.QTableWidget.CurrentChanged)
print(self.ui.edit_table.item(0, 1).text())
newListValues = []
for i in range(0, 46):
newListValues.append(self.ui.edit_table.item(i, 1).text())
print(newListValues)
newListValues.clear()
When I change the value, and press the enter I see Enter Key Pressed but I couldnt see new value. But if I press the enter button one more without any changing, I can see new values in newListValue. Why the new value shows me with delay ?
For example item(0, 1) value is 5, when I change this value to 12 and press enter I couldnt see any changing in print(self.ui.edit_table.item(0, 1).text()) but when I press enter again I can see 12 value.
Why this happening ?

When pressing Return or Enter during the editing state, the data is not instantly submitted to the model.
The key press event is handled by the delegate editor (usually, the line edit) which will eventually validate or fixup the entered value and, finally, submit the data.
If you want to know when data has actually changed, connect to the itemChanged signal.
Also note that:
"patching" event handlers like this is discouraged, as often leads to silent errors or mishandled events (since the scope of the function is not the instance of the class that should handle the event); you either use an event filter, or a promoted widget;
you should always call the base implementation of the event handler, unless you're completely sure that you don't want to handle it; for instance, in your case your implementation completely prevents keyboard navigation or the possibility to enter the edit mode by pressing Return or F2;

Related

python tkinter wait until entry box widget has an input by user ONLY after then continue

I have a code snippet which runs perfectly. In some cases, I need user input, but there are also cases where user input is not necessary and code functions without it perfectly.
So, in that cases I create with conditional a flow where entry box widget is created and destroyed after value is get() by script. But I cannot make code to wait until to say stops(pauses) when the user has given input value then continues to run.
code is below;
varSheetname_GS = ''
if varsoundTitle_usernameHeroContainer == 'FloatingBlueRecords' or varsoundTitle_usernameHeroContainer == 'DayDoseOfHouse':
varSheetname_GS = varsoundTitle_usernameHeroContainer
else:
# look for sheetname as an input value entered by user
new_sheetname_entryBox=tk.Entry(canvas2,width=30).pack()
new_sheetname_entryBox.focus()
var_new_sheetName =new_sheetname_entryBox.get()
new_sheetname_entryBox.destroy()
varSheetname_GS = var_new_sheetName #input("Enter the sheetname in (GooSheets):")
I have looked for so_01 and so_02 which are related to topic but was not able to implement in my situation. So, anyone who would guide me towards that answers would be great from yourside.
Thanks ahead!
You can use the wait_window method to wait until the entry widget has been destroyed. You can then bind the return key to destroy the window. If the entry is associated with a StringVar, you can get the value after the widget has been destroyed.
The solution might look something like this:
entry_var = tk.StringVar()
new_sheetname_entryBox=tk.Entry(canvas2,width=30, textvariable=entry_var)
new_sheetname_entryBox.pack()
new_sheetname_entryBox.bind("<Return>", lambda event: new_sheetname_entryBox.destroy())
new_sheetname_entryBox.focus_set()
# wait for the entry widget to be deleted...
new_sheetname_entryBox.wait_window()
# save the value
varSheetname_GS = entry_var.get()

Cancel / Ignore valueChanged on Enter

How can I cancel / block or ignore the valueChanged() event in a spin box when enter key is pressed?
Having multiple double spin-boxes in a group that are updated when one is changed.
[spin1] [spin2]
When spin1 emits the valueChanged() event, I update the value of spin2 and vice versa. However: if Enter key is pressed, the value should not be updated.
E.g. user types 250 in spin1, press Tab so that spin2 get focus. Then press Enter. Now spin1 should not be updated (as value of spin2 has not been changed).
Connected as:
self.spin1.valueChanged.connect(self.update_values)
self.spin2.valueChanged.connect(self.update_values)
One option is to get the lineEdit object of the spin-box and check isModified()
It will not block the signal, but it is at least a way of filtering out the event and can be applied in update_values.

After the EVT_KILL_FOCUS event is executed, why does the blinking cursor in TextCtrl disappear?

I have a TextCtrl that has an EVT_KILL_FOCUS event that I use to validate the contents of the field, alerting the user when the value is wrong. After opening the MessageBox, I clear the field and i set the focus to the field that I left validate again. Problem is that the text blinking cursor that should appear inside the field disappears and I do not know why or how to fix it. This behavior causes the user to not know in which field the focus is positioned.
Does anyone have any ideas?
...
self.txtCode = wx.TextCtrl(self, value='')
self.txtCode.Bind(wx.EVT_KILL_FOCUS, self.__onTxtCodeKillFocus)
self.txtCode.Bind(wx.EVT_CHAR_HOOK, self.__onTxtCodeTabKey)
def __validateTxtCodeContent(self):
if self.txtCode.GetValue() == "":
self.MessageBox(self, "Error Text", _("Warning"))
return False
return True
def __onTxtCodeKillFocus(self, event):
event.Skip()
if self.__validateTxtCodeContent() == False:
self.txtCode.SetValue("")
self.txtCode.SetFocus()
def __onTxtCodeTabKey(self, event):
key = event.GetKeyCode()
shift = event.ShiftDown()
# 9 = TAB, 13 = ENTER
if key != 9 and key != 13:
event.Skip()
return
elif key == 9:
if self.__validateTxtCodeContent():
if shift:
self.btnSave.SetFocus()
else:
self.txtDescription.SetFocus()
else:
self.txtCode.SetValue("")
self.txtCode.SetFocus()
else:
return False
My validation is not only for empty field, but for example only empty field can be.
Important: In the EVT_CHAR_HOOK event this behavior does occurs too.
I tried to use this too:
self.txtCode.SetValue("")
self.txtCode.SetFocus()
self.txtCode.SetInsertionPointEnd()
self.txtCode.Refresh()
But it did not work well.
You can't call SetFocus() from KILL_FOCUS handler. The most direct workaround is to use CallAfter() to call it slightly later, but even though this would "work", it's a very bad idea because you should not prevent the user from leaving the window -- and there is no way to completely prevent it from happening anyhow.
Just mark the code as being invalid (e.g. change its background), but don't try to retain focus when you're losing it.
P.S. Calling MessageBox() from a focus event handler may be a bad idea too in many circumstances, it's better to use wxLogWarning() or CallAfter() to delay showing the message box until the next event loop iteration.
In addition to what Vadim already said:
You can do validation on the hitting "OK" button or when the dialog/panel is about to close
You can use wxValidator to validate the user input depending on your task at hand.

Unable to send signal from Button created in Python loop

I am trying to create a series of buttons in a loop. Each button gets an id number as it's text and when the button is clicked it is supposed to send the id number to a function that will open an archived order. At this time I just want to print the order number to prove that the signal works and each button is connected to the correct order number.
ui.cmdOpen = QtWidgets.QPushButton(ui.frOrdHist)
ui.cmdOpen.setGeometry(QtCore.QRect(269, line1Y, 61, 22))
ui.cmdOpen.setText(iOrderId)
ui.cmdOpen.setObjectName("cmdOpen")
ui.cmdOpen.clicked.connect(lambda button=ui.cmdOpen:displayOrder(ui, button))
def displayOrder(ui, button):
i = button.text()
print(i)
When I click the button, I get an error message that says "boolean object has no text attribute"
I tried passing the order number directly and it would print "False" so still a boolean. I don't know where the boolean is coming from, it must be something wrong in the signal.
The clicked signal always sends the checked state of the button. So this will overwrite your default button argument with a boolean value, which is why you get the AttributeError (i.e. because bool doesn't have that method). You should instead make the connection like this:
ui.cmdOpen.clicked.connect(
lambda checked, button=ui.cmdOpen: displayOrder(ui, button))
PS: another common source of this issue is the triggered signal of QAction. If you ever find your slots receiving unexpected inputs, it's always worth checking the Qt Docs to see if the signature of the signal has any parameters with default values - i.e. that look something like this:
void QSomeClass::someSignal(bool param = false)

pyqt4: How to change button event without adding a new event?

I have a click button that I want to change events when the button is pressed. A minimal version of the existing code looks like this:
# Event that happens the first time
def first_event(self):
button.setText("Second Event")
button.clicked.connect(second_event)
# Event that happens the second time
def second_event(self):
button.setText("First Event")
button.clicked.connect(first_event)
button = QtGui.QPushButton("First Event")
button.clicked.connect(first_event)
Unfortunately, instead of changing the event that happens, it simply adds and event to the clicked signal, meaning that the following happens:
First button press - calls first_event
Second button press - calls first_event and second_event
Third button press - calls first_event twice and second_event
etc...
My desired behavior would be to have the button change functions when it is pressed, so that the resulting behavior would be:
First button press - calls first_event
Second button press - calls second_event
Third button press - calls first_event
etc...
Is there a way to make it so that it changes the click event instead of adding a new one? Is there a way to remove events after the fact?
I found a way to separate old events from signals using the disconnect() method. Here is an edited version that accomplishes what I originally wanted to do:
# Event that happens the first time
def first_event(self):
button.setText("Second Event")
button.clicked.disconnect()
button.clicked.connect(second_event)
# Event that happens the second time
def second_event(self):
button.setText("First Event")
button.clicked.disconnect()
button.clicked.connect(first_event)
button = QtGui.QPushButton("First Event")
button.clicked.connect(first_event)
It's worth noting that instead of doing this, I eventually did what ekhumoro mentioned in the comments, and created a wrapper function with a flag to record the current state, and then call first_event() or second_event() based on the value of the flag.

Categories

Resources