I am trying to clear my Tkinter frame a few seconds after I click a button. Currently, this program works fine. It runs, and when the button is clicked, the frame is cleared. However, I want to make it so that after the button is clicked, the frame stays there for x number of seconds longer. After the time is up, the frame is cleared in the same way as it currently does (my clearFrame function). The commented line - I thought the .after would accomplish this but it just makes the popup label show after x seconds instead. I've seen this page but couldn't successfully apply it to what I want to do. Unlike what that page shows, I don't want to destroy my window or my frame, I just want to run my clearFrame function after x seconds.
#runs when the button is clicked, the button is on frame1
def click():
top, top_width, top_height = createFrame()
createPopUpLabel(top, "Ok")
autoClose(top, 5) #automatically close my pop up label
#frame1.after(2000, clearFrame(frame1))
clearFrame(frame1)
frame1.after(2000, clearFrame(frame1))
after takes a callback function, which should just be a reference to a function e.g. clearFrame.
That's why your function just executes immediately, you need to pass lambda: clearFrame(frame1)
Related
I am trying to write a function to dynamically resize an image displayed in a tkinter window.
Therefore I bound this function to the Configure event:
connroot.bind( "<Configure>", connresiz)
My problems are:
That the connresiz() function gets called 3 times (why 3?) at program start, and
More troublesome, that dynamically resizing the window calls the function continuously as I drag the mouse! How can avoid this?
I thought about checking at the simultaneous presence of a <Configure> and <ButtonRelease-1> events, but I don't know how to code it.
1) We don't know that, since we can't see your code...
2) Short answer is: you can't, because that's exactly what <Configure> event does! Long answer, you can, with a little trick/hack. Since anytime the window is changing, it will call all the binded functions to <Configure>, and the same happens anytime as the mouse button released (right after the last <Configure> call) we can create a flag/switch which will tell us, if the window was "configured" then we can check that switch anytime the mouse button is released, and switch it back to the default value after we ran some actions.
So if you want the image to resized only, when the mouse was released and the window was changed this is the code you need:
from tkinter import *
class Run:
def __init__(self):
self.root = Tk()
self.clicked = False
self.root.bind('<ButtonRelease-1>', self.image_resize)
self.root.bind('<Configure>', lambda e: self.click(True))
def image_resize(self, event):
if self.clicked:
print("I'm printed after <Configure>.") # the action goes here!
self.click(False)
def click(self, value):
self.clicked = value
app = Run()
app.root.mainloop()
According to the official tk documentation, <Configure> events fire "whenever its size, position, or border width changes, and sometimes when it has changed position in the stacking order." This can happen several times during startup.
It is called continuously while you resize the window because the size of the widget is changing. That's what it's defined to do. You can't prevent it from being called, though you can certainly modify what you do in the callback. For example, you could delay resizing the image until you've not received another <Configure> event for a second or two -- which likely means the user has stopped interactive resizing.
I have a GUI with alot of buttons/widgets. I want that if 30 secs passes and the user didnt hit anything on the GUI that it will automaticly go back to the first screen.
I added this between root = Tk() and root.mainloop()
root.after(30000, lambda: showFirstScreen())
This line will go to my first screen after 30 seconds even if you hit the screen. So there is no counter that resets after hitting a button/widget.
I try'd to add it to a specific button on a other window so:
button13.after(30000, lambda: showFirstScreen())
If I reach the page with the button it will move to the main window after 30 seconds. But If I go back to the button it wont repeat the action above.
Any idea what im doing wrong?
You could use a variable to check if the user interacts with widgets, something like,
def showFirstScreen(buttons_pressed):
if buttons_pressed==True:
...code to go to first screen...
Use the buttons_pressed variable inside all your buttons' call methods to check if the user has used any button.
If you want to add after() to a button on another window, you can use a separate function,
button13_onPress():
if buttons_pressed==True:
root.after(30000, lambda: showFirstScreen())
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 the following problem when using tkinter to create a very simple window containing a matrix of buttons: When one of the buttons is clicked, the event handler changes the text of that button using the configure method on the button widget. This works. But I also want to change the text in one of the other buttons, which does not work. The method I use is that on creating the button, I store the object returned by the Button method before I use the grid geometry manager to place it. This object looks like ".123456789L" when printed and seems to be a pointer to the widget. I also use configure on this to change the button text. But somehow it seems to be wrong, because it works sometimes, and most of the times not. There's unfortunately no error message, just nothing happens when calling configure. I checked and it seems to be the correct pointer to the widget. Do I have to use a special way to affect a widget other that the one that called the event handler? These are the relevant parts of the code:
# CREATING THE BUTTONS:
buttons={} # global
for i in range(3):
for j in range(3):
button = Tkinter.Button(self,text='foo')
buttons[button]=(i,j)
button.grid(column=j,row=i)
button.bind( "<Button-1>", self.OnButtonClick )
# CHANGING BUTTONS:
def find_button(i,j):
"""Return the pointer to the other button to be changed when a button has been clicked."""
for button,key in buttons.items():
if key==(i,j): return button
def OnButtonClick(self,event):
print "You clicked the button",buttons[event.widget]
i,j=buttons[event.widget]
old_button=find_button(i,j) # This is simplified, I don't actually pass i,j, but other values. But I checked this and it returns the reference to the correct button. But this simplified version works the same way, just assume a different button that the one pressed would be returned.
old_button.configure(text = 'blabla') # THIS DOES NOT WORK
event.widget.configure(text = 'something') # THIS WORKS
I have the same problem and i solve it with:
buttons[button]=(i,j,button)
and in the function OnButtonClicK:
i,j,old_button=buttons[event.widget]
old_button.configure(text = 'blabla') # THIS DOES NOT WORK
Am learning Gtk. I wanted to build a calculator, in which i want to display the number pressed , in the textbox. I have completed it, by calling different functions for different buttons clicked, and appending the value in the textbox with the value of the button pressed. Using python 2.7.3
Is there a way to obtain the label value of the button pressed so that i can use a single function instead of 10 functions from 0 to 9?
Thanks in advance
Button callbacks include the widget itself, and you can also pass data. See here.
instead of reading the label of the GtkButton, which is pretty much error prone, you should associate the value represented by the button to the button instance itself, e.g.:
button = Gtk.Button(label='1')
button._value = 1
# add button to the container
button.connect('clicked', on_button_clicked)
button = Gtk.Button(label='2')
button._value = 2
# add button to the container
button.connect('clicked', on_button_clicked)
and then read the value from the button instance inside the signal handler, e.g.:
def on_button_clicked(button):
print 'you pressed the button of value: %d' % (button._value)
GtkWidget instances in Python are Python object, and thus behave like any other Python object.