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.
Related
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;
I'm implementing some customised behaviour for a QFileDialog.
reference_dir = r'D:\My Documents\month'
create_dir_dialog.setDirectory(reference_dir)
create_dir_dialog.setFileMode(create_dir_dialog.Directory)
options = create_dir_dialog.Options(create_dir_dialog.DontUseNativeDialog | create_dir_dialog.ShowDirsOnly)
create_dir_dialog.setOptions(options)
# identify "Choose" button
choose_button = create_dir_dialog.findChild(QtWidgets.QDialogButtonBox).button(
QtWidgets.QDialogButtonBox.Open)
# disconnect "clicked" signal from this button
choose_button.disconnect()
def check_line_edit(path):
# this slot handles enablement of the "Choose" button: if the text
# corresponds to an already-existing directory the button is disabled.
# This is because we are trying to create a new directory.
...
# get the line edit used for the path
lineEdit = create_dir_dialog.findChild(QtWidgets.QLineEdit)
lineEdit.textChanged.connect(check_line_edit)
def create_dir_and_proj():
# this function creates a directory based on the text in the QLE
new_dir = lineEdit.text()
...
create_dir_dialog.close() # programmatically close the dialog
# use the above method as the slot for the clicked signal
choose_button.clicked.connect(create_dir_and_proj)
dlg_result = create_dir_dialog.exec_()
# thread gets held up here
To my delight this works OK.
There's only one fly in the ointment: if, instead of clicking "Choose" with the mouse or using the mnemonic Alt-C to cause the click (both of which cause create_dir_and_proj to run OK), I just press "Return" key when focus is on the dialog, the previous (standard) behaviour occurs, i.e. the behaviour (slot) that I disconnected from the "Choose" button's click signal. This then causes a message box to come up saying "directory does not exist". But the point is that my new slot wants to create the new directory as entered by the user.
I surmise that this is because the "Choose" button is the "default" button of the dialog, and that things have been wired up so that this "Return-key-pressed" signal is wired up to the standard slot as normally used by the "Choose" button.
How do I get hold of this signal with a view to disconnecting it and wiring up a new slot (i.e. the above create_dir_and_proj function)?
That message-box will appear when the line-edit has focus and you press return/enter. The returnPressed signal of the line-edit is connected to the QFileDialog.accept slot. The resulting behaviour will then depend on the FileMode. For the Directory mode, this equates to a request to open the specified directory, which will obviously fail if it doesn't exist.
To override this behviour, you can simply connect your own slot:
lineEdit.returnPressed.disconnect()
lineEdit.returnPressed.connect(create_dir_and_proj)
When the line-edit does not have the focus, pressing return/enter will activate the default button (unless the current focus-widget has built-in behaviour of its own: e.g. navigating to the selected directory in the tree-view). Since you've connected your own slot to the clicked signal of this button, your slot will be called by default.
UPDATE:
It seems that connecting to a Python slot that forms a closure over the dialog can affect the order in which objects get deleted. This may sometimes result in the line-edit completer popup being left without a parent after the dialog closes, which means it won't get deleted and may remain visible on screen. A couple of possible work-arounds are to either explicitly close the popup inside the slot:
def create_dir_and_proj():
lineEdit.completer().popup().hide()
dialog.close()
or disconnect all signals connected to the slot before closing:
def create_dir_and_proj():
choose_button.clicked.disconnect()
lineEdit.returnPressed.disconnect()
dialog.close()
(NB: I have only tested this on Linux; there's no guarantee the behaviour will be the same on other platforms).
I have a tk.Button(..., command=_on_button_click).
Once it is clicked, I want to know whether the Shift key is currently held down.
But the _on_button_click is called without any event object or similar for me to check it
Assuming a button named button and a handler named shift_click, you can use the bind method:
button.bind("<Shift-Button-1>", shift_click)
Of course, you will probably also want one without shift click:
button.bind("<Button-1>", not_shift_click)
I have a textBox on my WxPython GUI, where I am displaying a changing value (Which changes every 100 mS). I have two buttons - Button A, Button B.
Initial condition: Textbox has a value of between 2000-3000. Button A is enabled, Button B is disabled.
I need the following sequence of events to go on:
The user presses the Button A. After approximately 20 seconds or some user defined time (completely variable based on the user/ type of work he is doing), the textBox value goes under less 50.
Once the textBox value goes less than 50 - Button B should be enabled.
Currently this is my following code, where I am pressing the Button A - waiting for the textBox value to less than 50. Then enable the Button B - and it is not working. The button B is not getting enabled. I tried using other means, but they are leaving to an unresponsive GUI. My Button A is - DONE, Button B is START. textBox is pressure_text_control.
def OnDone(self, event):
self.WriteToController([0x04],'GuiMsgIn')
self.status_text.SetLabel('PRESSURE CALIBRATION DONE \n DUMP PRESSURE')
self.led1.SetBackgroundColour('GREY')
self.add_pressure.Disable()
while self.pressure_text_control.GetValue() < 50:
wx.CallAfter(self.StartEnable, 'Enabling start button')
#self.start.Enable()
def StartEnable(self):
self.start.Enable()
You haven't supplied sufficient code to be able to see what is going on.
We don't know for example if self.pressure_text_control.GetValue() < 50 is in fact less than 50, given that you say the value is changing every 100mS.
If your issue is really about the fact that the GUI becomes unresponsive, then investigate wx.Timer()
See:
http://www.blog.pythonlibrary.org/2009/08/25/wxpython-using-wx-timers/
The Timer class allows you to execute code at specified intervals, which allows you to process one or more periodic events (you can declare multiple timers), as long as they are not long or blocking processes, yet leave the GUI responsive.
mocked up as follows:
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.check, self.timer)
def StartmyButton(self):
self.start.Enable()
self.timer.Start(100)
def check(self, event):
"check you input here and process any results"
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.