how to make EVT_TEXT_ENTER work with EVT_KILL_FOCUS? - python

I have a text ctrl where user gives number.
once he finished i want to perform an operation.
I know the user finished when the textctrl loses focus or when he press enter.
I did the following:
self.a= wx.TextCtrl(self, -1,style=wx.TE_PROCESS_ENTER)
self.a.Bind(wx.EVT_KILL_FOCUS, self.OnA)
self.a.Bind(wx.EVT_TEXT_ENTER, self.OnA)
def onA(self,event):
print "hello"
event.Skip()
My problem is that if the users click somewhere else with the mouse then eveything works. hello is printed once which means that EVT_KILL_FOCUS happened.
but if uses press enter than hello is printed twice. It means that both EVT_KILL_FOCUS and EVT_TEXT_ENTER happed. I don't want to proccess the event twice.
What can I do?

The simplest answer is not to code for both events.
I would choose EVT_KILL_FOCUS and forget about EVT_TEXT_ENTER and remember to remove the event.Skip()
Edit:
Your problem is that you are mixing a wx.Event (kill-focus) and a wx.commandevent (enter) see: http://wiki.wxpython.org/EventPropagation for further information. The issue here,I think, is that wx.commandevent (Enter) is causing the kill-focus event.
Edit 2:
Assign the events to different functions.
In the function that is used for the EVT_TEXT_ENTER unbind the EVT_KILL_FOCUS, output your error message and then re-bind the EVT_KILL_FOCUS event
i.e.
self.a.Unbind(wx.EVT_KILL_FOCUS)
(do whatever to announce that there is a error here)
self.a.Bind(wx.EVT_KILL_FOCUS, self.OnA)

Related

TableWidget "Enter" keypressed current text

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;

How to prevent buttons within an Inline Keyboard Markup from being pressed more than once?

I am using pyTelegramBotAPI. I want to remove my Inline Keyboard Markup when a button response callback occurs. I do that in three ways:
Editing the reply_markup message and passing a null array to the reply_markup argument:
bot.edit_message_reply_markup (call.message.chat.id, call.message.id, 'Example response', reply_markup = [])
Deleting the message and sending a new one:
bot.delete_message (call.message.chat.id, call.message.id)
bot.send_message (call.message.chat.id, 'Example response.')
Editing the message directly without reply_markup arguments:
bot.edit_message_text ('Example response.', call.message.chat.id, call.message.message_id)
They all work but when I press the button repeatedly before it disappears, the callback executes repeatedly, causing an error in all three ways, in the first and third when not able to edit message with same content. In the second when a message is already deleted.
How could I restrict the buttons to only be pressed once, or only sendg a callback, or the callback only allowing certain commands to be executed once, at least, until the Inline Keyboard Markup is shown again?
A global boolean variable that changes on button press is not an option as I have a lot of Inline Keyboard Markups that could be displayed simultaneously.
There is no option to limit call back query. If you need suggest to respective devs
Use a database to save the state of the button for the given user, with the expiration seconds you want. Then create an "if clicked" condition.

Python - wxPython Sequence of Command Execution

I have a properly working code, I understand I am not pasting enough code - but I will explain each command with proper comments. My question here is why is the code behaving rather than what I expected it to behave.
My code:
def OnReset(self, event): # A function event which works after a button is pressed
self.reset_pump.Disable() # Disables the button so it is clicked
self.WriteToController([0x30],'GuiMsgIn') # Sends the reset command
self.flag_read.set() # Set Event of the thread
time.sleep(0.25)
self.tr.join() # Joining a Thread
self.MessageBox('Pump RESET going on Click OK \n')
# Having the above step is useful
# The question I have is based on the commands from here:
self.offset_text_control.Clear()
self.gain_text_control.Clear()
self.firmware_version_text_control.Clear()
self.pump_rpm_text_control.Clear()
self.pressure_text_control.Clear()
self.last_error_text_control.Clear()
self.error_count_text_control.Clear()
self.pump_model_text_control.Clear()
self.pump_serial_number_text_control.Clear()
self.on_time_text_control.Clear()
self.job_on_time_text_control.Clear()
# The above commands clear various widgets on my GUI.
self.ser.close() # Closes my serial connection to MCU
time.sleep(5)
self.OnCorrectComPort(event) # An external function which gets executed. This function has a Message BOX - which says - PORT IS OPENED.
return
I expect, once the thread is joined - my commands will clear the GUI. Then close the serial connection using (ser.close()). Then the self.OnCorrectComPort(event) gets executed.
This is what I am seeing: Thread joins with tr.join() then self.OnCorrecComPort(event) gets executed as I can see the Message box with "PORT OPENED" appears, I click OK, then my GUI gets CLEARED. To my understanding this is wrong, anyone please correct me.
The problem is that you're calling time.sleep(5) and self.OnCorrectComPort() in the callback, before returning to the mainloop where the events will be processed.
The widgets will not reflect the effects of your Clear calls until you exit of the callback into the wx mainloop.
What happens is, the routines you call are executed (takes several seconds because of the time.sleep call, then wx gets to process the graphical commands, and the widgets are cleared at this very moment (which is too late and the GUI seems stuck with the previous state)
If you want it the other way round, you can use wx.CallAfter() to leave wx a chance to process its events before you call your routines.
In your case, since you want to wait 5 seconds, the risk is to freeze your interface again. It's even better to call wx.CallLater() with a 5 second delay in that case, leaving the time to wx to refresh all the widgets.
Modified code:
def OnReset(self, event): # A function event which works after a button is pressed
self.reset_pump.Disable() # Disables the button so it is clicked
self.WriteToController([0x30],'GuiMsgIn') # Sends the reset command
self.flag_read.set() # Set Event of the thread
time.sleep(0.25)
self.tr.join() # Joining a Thread
self.MessageBox('Pump RESET going on Click OK \n')
# Having the above step is useful
# The question I have is based on the commands from here:
self.offset_text_control.Clear()
self.gain_text_control.Clear()
self.firmware_version_text_control.Clear()
self.pump_rpm_text_control.Clear()
self.pressure_text_control.Clear()
self.last_error_text_control.Clear()
self.error_count_text_control.Clear()
self.pump_model_text_control.Clear()
self.pump_serial_number_text_control.Clear()
self.on_time_text_control.Clear()
self.job_on_time_text_control.Clear()
# The above commands clear various widgets on my GUI.
self.ser.close() # Closes my serial connection to MCU
# will call calledAfter after 5 seconds
wx.CallLater(5000,self.calledAfter,[ser,event])
def calledAfter(self,ser,event):
self.OnCorrectComPort(event) # An external function which gets executed. This function has a Message BOX - which says - PORT IS OPENED.

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.

Python Roguelike: Inventory Disappears

Today I progressed further into this Python roguelike tutorial, and got to the inventory. As of now, I can pick up items and use them. The only problem is, when accessing the inventory, it's only visible for a split second, even though I used the console_wait_for_keypress(True) function. I'm not sure as to why it disappears. Here's the code that displays a menu(in this case, the inventory):
def menu(header,options,width):
if len(options)>26: raise ValueError('Cannot have a menu with more than 26 options.')
header_height=libtcod.console_get_height_rect(con,0,0,width,SCREEN_HEIGHT,header)
height=len(options)+header_height
window=libtcod.console_new(width,height)
libtcod.console_set_default_foreground(window,libtcod.white)
libtcod.console_print_rect_ex(window,0,0,width,height,libtcod.BKGND_NONE,libtcod.LEFT,header)
y=header_height
letter_index=ord('a')
for option_text in options:
text='('+chr(letter_index)+')'+option_text
libtcod.console_print_ex(window,0,y,libtcod.BKGND_NONE,libtcod.LEFT,text)
y+=1
letter_index+=1
x=SCREEN_WIDTH/2-width/2
y=SCREEN_HEIGHT/2-height/2
libtcod.console_blit(window,0,0,width,height,0,x,y,1.0,0.7)
libtcod.console_flush()
key=libtcod.console_wait_for_keypress(True)
index=key.c-ord('a')
if index>=0 and index<len(options): return index
return None
I'd appreciate anyone's help or input to this problem.
It may be related to an old version of the library that has an event when you press a key, and another event when you release it. So this could cause it to appear and disappear when you release the key.
So try to see if the screen stays on if you keep the key pressed.
wait_for_keypress does indeed trigger on both press and release events. To fix this, replace wait_for_keypress with the sys_wait_for_event, specifying to trigger only on press events.
Documentation

Categories

Resources