I want to wait for the next action until the button is pressed by Tkinter.

Asked 2 years ago, Updated 2 years ago, 349 views

For applications using Tkinter and Selenium, press Start to launch Chrome, press Start to launch
input('>If you type something, you'll see the text of the p element on the console')
Wait for to get the p element until works and presses Enter on the console.
Next
input('>Enter something to display text for h2 elements on the console')
will also wait for the h2 element to be retrieved.

"I would like to make ""Press Enter key on console"" correspond to ""Press Next Button"" and wait for the next action until the next button is pressed." How should I implement it?

The reason I want to stop processing is to visually check the output one by one and then proceed to the next.

At present, next() does not do anything, but when I press the next button, next() works and I want to proceed to the next process.

  • Treatment 1
    Wait for next() to run
  • Treatment 2
    Wait for next() to run
  • Treatment 3
    <

処理 I don't want to prevent the window from closing after processing.

Please let me know.

Enter a description of the image here

import ctypes
import tkinter as tk
import tkinter.ttk as ttk
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.options import Options

try:
    ctypes.windll.shcore.SetProcessDpiAwareness (True)
exceptBaseException:
    pass


def next():
    pass


def start():
    global driver

    chrome_options=Options()
    chrome_options.add_experimental_option("detach", True)

    driver = webdriver.Chrome(
        service=Service(ChromeDriverManager().install()) ,
        options=chrome_options
    )

    driver.get('https://scrape-b276b.web.app/')
    input ('> type something and the p element text will be displayed on the console')
    print(driver.find_element(by.CSS_SELECTOR, '#app>div>main>div>div>div>div>section>div.text>p')
    input('> type something and the h2 element text will be displayed on the console')
    print(driver.find_element(By.CSS_SELECTOR, 'h2').text)
    input('>Enter something and exit')


defmain():
    frame = tk.Tk()
    frame.title('title')
    frame.geometry("230x60+400+440")

    button1=ttk.Button(frame, text='Next', command=next)
    button1.place(x=10,y=10,width=100)
    button2=ttk.Button(frame, text='start', command=start)
    button2.place (x=120, y=10, width=100)

    frame.mainloop()


if__name__=='__main__':
    main()

python selenium tkinter

2022-10-22 09:14

2 Answers

"How to wait for the next action until the Tkinter button is pressed" is a basic feature of Tkinter and is not something to be added later on the user-created program.

The question program starts with the execution of the line frame.mainloop() and waits for an event such as a button or other widget mouse keyboard while it is running, and invokes the action if the corresponding event exists by default or is registered from the user program.
There is an explanation in this article.
[Python] Explanation of mainloop on tkinter

Therefore, "def start(): in the function def start(): and wait for the button to click to proceed" in a program similar to the question is bad behavior from a GUI point of view, and there is no point in using Tkinter.

From a GUI perspective, as shown in the answers to the previous question and the comments on this question, you should do the following:

  • def start(): The function only displays sites
  • Each search and display of elements in a site requires as many special buttons and functions as needed and calls them individually
  • Display the corresponding number for the text on the button if the order of processing is determined

If you still want to do just one button, you can prepare a variable to indicate how far you have done the processing, and then change the processing by determining the variable as follows.
Show only the parts you want to change and omit the front and back.

import traceback
phase=-1#### Variable to save processing stage: -1 is browser not started
def next():
    global phase####Declaration using global variables

    #### Each of the following processes is performed according to the value of the variable that stores the processing stage, and the variable is moved to the next stage.
    try:
        if phase == 0:
            print('The first 'Next' was clicked, so the p element text is displayed on the console')
            print(driver.find_element(by.CSS_SELECTOR, '#app>div>main>div>div>div>div>section>div.text>p')
            phase+=1#### variable to the next level
        elif phase==1:
            print('The second 'Next' was clicked, so the h2 element text is displayed on the console')
            print(driver.find_element(By.CSS_SELECTOR, 'h2').text)
            phase+=1#### variable to the next level
        elif phase==2:
            print('Close browser as 3rd 'Next' was clicked')
            phase=-1#### variable to pre-browser startup stage
            driver.quit()
    except Exception as:
        print({e.__class__.__name_}Exception Occurs in f'{phase} Step Process')
        print(traceback.format_exc())
        phase+=1#### variable to the next level
        if phase>2:
            phase=-1#### The range is over, so move the variable to the pre-browser startup stage
        pass

def start():
    global driver
    global phase####Declaration using global variables

    chrome_options=Options()
    chrome_options.add_experimental_option("detach", True)

    driver = webdriver.Chrome(
        service=Service(ChromeDriverManager().install()) ,
        options=chrome_options
    )
    driver.get('https://scrape-b276b.web.app/')

    print('Browser launched, site displayed, ready')
    phase=0#### Set the variable to the first step


2022-10-22 09:14

Difficulty waiting

The request to "wait until the button is pressed before proceeding to the next step" indicates the difficulty of an event-driven program.

  • To "wait" for an event, you must exit the callback function and return to the event loop
  • But when you exit the function, the "next action" goes away

That's right.

wait_variable

Cubick's comment explains how to use the wait series of tkinter features in links to.I don't know much about it, but there may be many situations where there is no problem.However, when this feature is invoked, it appears to be a bit complicated (such as "local event loop" being created or something), and there are problems such as not being able to exit the program while wait.I have the impression that it is a kind of hack to the event loop, and that it cannot be used without understanding it at the Tcl/Tk level.

General Solution

If you exclude the Tck/Tk specific features above, there are two possible solutions.

  • Develop callback functions
  • Run the GUI and others in a different process (thread)

This answer deals with the former.

Chain of

Registration for

Next Action

Kunif's answer is to calculate what to do with each callback function.I think this is simple and easy to understand.

There is another way to explicitly treat "next action" as a function.This is a bit complicated, but I think it's a way to think about future and promote, so I'll explain it to you.

  • Register the first action as a callback function
  • The first callback function registers the "next action" as the callback function when it is called and finished processing itself
  • Register "Next Action" as a callback function for the following callback functions in the same way
  • Repeat the following

That's the flow.

If you write this honestly, the code will look like the one below.

def start(root, next_button):

    # ...

    defproc_01():
        print('--Process 1--')
        # Change to a callback function (command) that:
        next_button.configure(command=proc_02)

    defproc_02():
        print('--Process 2--')
        # Change to a callback function (command) that:
        next_button.configure(command=proc_03)

    defproc_03():
        print('--exit--')
        root.quit()

    # Set the first callback function (command)
    next_button.configure(command=proc_01)
    print('--start--')

Python provides iterator as a way to handle the following actions (values):There is also a generator that can be used instead of the complicated code above.

def start(root, next_button):

    # ...

    def proc_gen():
        print('--Process 1--')
        yield

        print('--Process 2--')
        yield

        print('--exit--')
        root.quit()
        yield

    # Generate iterators
    # Every time `proc_itr` is `next`, proceed to the next field.
    proc_itr=proc_gen()

    # Callback (command) is set to invoke `next`
    next_button.configure(command=lambda:next(proc_itr))
    print('--start--')

The syntax sugar coating for these "next actions" is given to event-driven processes such as async/away syntax.Eventually, the GUI toolkit may be better combined.

Moving Code:
This code has been verified to work.In order to move it by hand, I have changed the content of the process from the question.next is Python's built-in function.I avoid overwriting it with my own functions.

import tkinter ask
import tkinter.ttk as ttk
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.options import Options

url='https://google.com/'


def start (root, next_button):
    chrome_options=Options()
    chrome_options.add_experimental_option("detach", True)

    driver = webdriver.Chrome(
        service=Service(ChromeDriverManager().install()) ,
        options=chrome_options
    )

    driver.get(url)

    def proc_gen():
        print('--div Element--')
        print(driver.find_element(By.CSS_SELECTOR, 'div').text)
        yield

        print('--a element--')
        print(driver.find_element(By.CSS_SELECTOR, 'a').text)
        yield

        print('--exit--')
        root.quit()
        yield

    # Generate iterators
    # Every time `proc_itr` is `next`, proceed to the next field.
    proc_itr=proc_gen()

    # Callback (command) is set to invoke `next`
    next_button.configure(command=lambda:next(proc_itr))
    print('--start--')


defmain():
    frame = tk.Tk()
    frame.title('title')
    frame.geometry("230x60+400+440")

    button1 = ttk.Button(frame, text='Next')
    button1.place(x=10,y=10,width=100)
    button2=ttk.Button(frame, text='start', command=lambda:start(frame,button1)))
    button2.place (x=120, y=10, width=100)

    frame.mainloop()


if__name__=='__main__':
    main()


2022-10-22 09:14

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.