(Thanks in advance if you decide to answer. Sorry If I am not able to describe the content of the Application clearly.)
I am currently making Desktop Application using Tkinter Python for my gui interface. I am having a problem related to the flow of the Application.
My Application
Main Page of my application has form designed with some textboxes and checkboxes. Check button work as True or False Condition, where each check button refers to whether or not a specific function has to be executed or not.
To store the values of the check button, the dictionary is maintained with keys as LabelName and values as True/False value.
Checkbox code
f1=tk.BoolVar() #People tend to use IntVar() but i prefer BoolVar()
ttk.Label(text="func1")
ttk.Checkbutton(parent, variable=f1)
f2=tk.BoolVar()
ttk.Label(text="func2")
ttk.Checkbutton(parent, variable=f2)
-------other such CheckButtons------------------
There's a submit button in the form on pressing which all the data entered into textbox along with these check buttons. Based on true-false values, functions are called which is handled by if-else conditions.
#submit button
ttk.Button(parent,text="Submit",command=onsubmit)
###########
def onsubmit():
----------statements to read data--------------
dict['func1']=f1
dict['func2']=f2
#other statements
-----------------------------------------------
if dict['func1']:
func1()
if dict['func2']:
func2()
---other if-else conditions---
Each function is individual module which consists of either form, or frame with data or matplotlib graphs for visualization of data and to do other operations on data and graphs which are placed on root window frame.
My problem
I want the user to control the flow by giving them the next button after every function is executed and then move onto the execution of the next function based on his input of the check button. The program should wait until the User presses the next button and after they press the next button, it should execute the next function and then wait again for the next button.
One of the solution:
Using fig.waitforbuttonpress() was the solution. But I didn't find it reliable. Because even mouse click could skip the function execution. But I need to specifically assign a button through which the user can select when to proceed to the next function.
I am not sure if I understood what your code does, but you could do it something like that I guess:
next_button = ttk.Button(parent,text="Next",command=func1)
...
def func1():
#do your stuff here
next_button.configure(command=func2)
Then you would have to add the last line of code to all the functions to always reassign the button.
Another way could be:
process = 0
next_button = ttk.Button(parent,text="Next",command=next)
def next():
global process
process += 1
if process == 1:
func1()
elif process == 2:
func2()
...
elif *last_function_reached*:
process = 0
Related
I am trying to assign different functions to the clicked signal of a button depending on the activated value of a combo box with PyQt5.
Here is how I am trying to do it:
self.filterComboBox.activated[int].connect(self.filterComboChange)
def filterComboChange(self,option):
if(option==1):
self.filterAddButton.clicked.connect(self.onClickFilterAddButtonAge)
elif(option==2):
self.filterAddButton.clicked.connect(self.onClickFilterAddButtonFormat)
def onClickFilterAddButtonAge(self):
#some lines of code
def onClickFilterAddButtonFormat(self):
#some lines of code
I am selecting the first option in the combo Box, I push the button, function 1 runs fine
After that when I am pushing the button with the other option selected, before the second function being run, the first function runs.
Can anyone tell me the reason for this or tell me what I am doing wrong?
If signal is already connected, you need to disconnect it first before connecting it again.
def filterComboChange(self,option):
try:
self.filterAddButton.disconnect()
except:
pass
if(option==1):
self.filterAddButton.clicked.connect(self.onClickFilterAddButtonAge)
elif(option==2):
self.filterAddButton.clicked.connect(self.onClickFilterAddButtonFormat)
I have a sweep function that returns a string of data. What I want to do is have two buttons, a start button and a stop button. When the start button is hit, the sweep function is called, and once that function is finished it is called again and again and again. Running nonstop until the stop button is hit. I'm using flask.
I don't think this is a duplicate because most of the other question regarding this want it to stop at a specific time, ie. run for 45 seconds. I need mine to run continuously until the stop button is pressed.
My thought process was to do something like
#app.route('continue_sweep', methods=["GET","POST")
def continue_sweep():
while (sweep_continue flag = true):
sweep()
and then in my stop button function just have a sort of break all? I don't know if that's a thing or not, but that was my thought process.
#app.route('stop_sweep', methods=["GET","POST"])
def stop_sweep():
break all -->> end the above sweep function here
--------------------Updated code
I can do something like this
#app.route('/start_continue_sweep', methods=["GET","POST"])
def start_continue_sweep():
if init_tester_flag == False:
initialize_tester()
stop_btn_flag = False
while (stop_btn_flag == False):
sweep_continue_fun()
return render_template('sweep_results.html', sweep_str = remove_err_str)
def sweep_continue_fun():
sweep_btn()
return render_template('sweep_results.html', sweep_str = remove_err_str)
and it gives me what I want, but does not update the sweep_results.html. Is this why I would need something like what was mentioned in your answers below? Or is there an easier fix to make it update?
That's not how web requests work. One request gets one response, then it's done. If you want something to move continuously, you will have to do that with Javascript in the browser, not in the server.
I am pretty new to python and have been working with a program that was originally meant for the command line. As such, it uses the input() function quite a bit, especially in the middle of loops. Mostly, the original code would do something like this:
for item in list:
# some logic here
user_input - input("prompt")
# uses user_input
I've decided I want to make a GUI for it, but I also want to make it optional. I have a class called Viewer that decorates the original program, and I am struggling to figure out how to best to handle the calls to input().
My first thought was just to inject a new input function altogether so that way it looks for input in my GUI text box instead the sys.stdout. I found many Stack Overflow answers on how to print sys.stdout to a GUI element (like this), but not how to take input from one. All of my attempts either ended in freezing the GUI by creating a loop, or the program not pausing for input and simply grabbing what was in the box when the prompt was put forward.
Secondly, I tried to break apart my functions to better match the code examples for buttons. So, button 1 would trigger a function_part_1, which would go until it required an input. If the GUI flag was turned off, it would automatically go to an input function, otherwise it would return and a button press would trigger function_part_2:
def function_part_1(list):
item = list[0]
# do some logic on item 1
if GUI:
print("prompt")
return
# After this, the GUI waits for a button press, and then calls function_part_2
else:
function_input(list)
def function_input(list):
user_input = input("prompt")
function_part_2(user_input, list)
def function_part_2(user_input, list):
# uses user_input on item
list.remove(list[0])
if list:
function_part_1(list)
else:
return
However, this turned ugly really quickly. First, it broke apart many loops which would require a lot of refactoring to keep the logic in tact (Especially for the nested loops). It also requires that I pass all my local variables from function-part to function-part, which exploded the function headers. In order to have only a single input box for the user, the GUI has to have logic to know which function is executing and what function-part comes next. It made my functions harder to follow and hurt readability.
Is there a nicer way to do this?
I am using appJar for the GUI, which is based around Tkinter. I am willing to switch to pure Tkinter if that would make things easier.
The easiest way is to overwrite the input function. Here's a working example using tkinter:
import tkinter as tk
def input(prompt=''):
win= tk.Tk()
label= tk.Label(win, text=prompt)
label.pack()
userinput= tk.StringVar(win)
entry= tk.Entry(win, textvariable=userinput)
entry.pack()
# pressing the button should stop the mainloop
button= tk.Button(win, text="ok", command=win.quit)
button.pack()
# block execution until the user presses the OK button
win.mainloop()
# mainloop has ended. Read the value of the Entry, then destroy the GUI.
userinput= userinput.get()
win.destroy()
return userinput
print(input('foobar'))
I have created a program in the turtle canvas in which the user can press any letter key on the keyboard and the turtle draws the corresponding letter in the canvas. I have also implemented an undo function that undoes the last function called by clearing the canvas then redrawing everything up until the point before the undone action. This undo function works by the user pressing a tkinter button at the bottom of the canvas labeled "Undo" or pressing the "left" key on the keyboard.
However, I have also decided to create a dynamic (a.k.a. selective, nonlinear, etc.) undo method in which there is a tkinter drop down menu and each drawing function, as it is called, is written to that menu. Then, from the menu, the user can select the function she previously called that he/she wants to undo and the program will undo that specific function instance. The whole process is described below:
The tkinter drop down menu is created through the following code block:
# global variables because next code block located ABOVE this one
global fav
fav = Menubutton(text = "Selective redo", state = DISABLED)
fav.pack(side = "left")
fav.menu = Menu(fav, tearoff = 0)
fav["menu"] = fav.menu
global redo1
redo1 = fav.menu
fav.pack()
When letter drawn, that letter's point object written to menu using code block below:
po = Point(v,y,c,w,isdown(),x,ph,pw)
undo1.add_command(label = Point.__str__(po), command = lambda: selectundo(undo1.index(po)))
# 'po' is a Point object for each function, and the string of that is the label of the menu item
Point.__str__() is this Point object method:
def __str__(self):
return "({})".format(self.function)
Finally, user supposed to be able to select –from menu– which instance of letter to undo, and program undoes that letter instance using the user-defined function below:
def selectundo(x):
for ty in range(x, len(function)):
undoHandler()
update()
listen()
The issue here is that when the user chooses to draw two or more of the same letters, they both get written to the menu with the same exact index values and thus, if the user wants to undo say, 1 of those, it will instead undo ALL instances of the letter from the canvas, not just the one selected by the user! However, I want the program to ONLY undo the instance of the letter that the user selects from the menu. Any ideas on how I would fix this issue? Any help is much appreciated! :)
I am looking for a solution to emulate the behavior of the UI of an electronic component and the user interaction (which should be pushing buttons) with LEDs reporting an internal state of the electronic component.
I am using python and the tKinter module to do so.
My code runs and my GUI window displays correctly. However, when I push several times on buttons the behavior is not as expected.
I have 4 possible state for each LED (OFF, ON, (Blinking) SLOW, (Blinking) FAST).
I have 4 buttons which can have an impact on the state. Each button has an interaction function defined in the widget class I have defined, and each of this function, once called, redefines the internal state of the widget.
In order to control the blinking of the LED, I use a single loop and the self.after( ..) function. This function is the following:
def toggleLeds(self):
for led in [self.ledTxIP, self.ledRxIP, self.ledTxRS, self.ledRxRS, self.ledPower, self.ledRun, self.ledStatus, self.ledConfig]:
if (((led[1] == "SLOW") and (self._FastBlinking == 0)) or (led[1] =="FAST")):
bg = led[0].cget("background")
bg = "green" if bg == "black" else "black"
led[0].configure(background=bg)
elif((led[1] == "OFF") and (self._update == 1)):
led[0].configure(background="black")
self._update = 0
elif (self._update == 1):
led[0].configure(background="green")
self._update = 0
self._FastBlinking = (self._FastBlinking + 1)%2
self.update_idletasks()
self.after(self._FastBlinkTime, self.toggleLeds)
This one is called recursively through the self.after function, and at the end of the interaction function I have defined for each button.
Here is how I have defined a single LED:
self.ledTxIP = [tk.Label(self, width=1, borderwidth=2, relief="groove"),"OFF"]
And here is an example of the button interaction function:
def pushMode(self):
if (re.search("Reset",self.state) == None):
if (self.clickModCnt == 0):
self.state = "Status"
self._stateTimer = int(time.gmtime()[5])
elif (self.clickModCnt == 1):
if(int(time.gmtime()[5]) - self._stateTimer < 3):
self.state = "Config"
else:
self.state = "RunMode"
else:
self.state = "RunMode"
self.clickModCnt = (self.clickModCnt + 1)%3
self._update = 1
self.updateLedState()
If anybody has an advice on this, it would be more than welcome.
I don't know why this didn't jump out at me sooner, but I think the problem is listed in your own question text, referring to the toggleLeds method:
This one is called recursively through the self.after function, and at the end of the interaction function I have defined for each button.
When the program initially runs, I'm assuming that you call toggleLeds somewhere to kick off the initial pattern for the LEDs. That sets up a single recursive loop via the self.after call at the end of the method. However, if you also call that same method every time you click a button to change state, you're setting up a new loop with every button click, and each new loop may or may not be in sync with your initial loop.
There are a couple ways that I can think of to handle this possible conflict. One is to avoid making new calls to toggleLeds, but that way there could be a delay between the button click and the new LED pattern. If you don't mind that delay, that's probably the best solution.
If you want the light/blink pattern to change immediately, you need to interrupt the current loop and start a new one with the new light/blink states. According to the Tkinter reference produced by New Mexico Tech, the after method:
...returns an integer “after identifier” that can be passed to the .after_cancel() method if you want to cancel the callback.
Here's how you could take advantage of that. First make sure that you're storing that identifier when calling the after method:
self.after_id = self.after(self._FastBlinkTime, self.toggleLeds)
Then change your toggleLeds method definition to accept an optional "interrupt" argument, and to cancel the existing after loop if that argument is True:
def toggleLeds(self, interrupt=False):
if interrupt:
self.after_cancel(self.after_id)
# Existing code follows
Finally, pass True to that argument when calling the method after a button has been clicked:
# Existing button processing code here
self.toggleLeds(interrupt=True)
With these changes in place, each button click would cancel the current after cycle and start a new one, preventing more than one cycle from running at once, which should keep the LEDs in sync.