How to change focus of simpledialog in Tkinter?

225 Views Asked by At

I have several simpledialog popup windows. The first one that shows is in focus and after it closes then every single one after that is not in focus. The simpledialog code is this:

from tkinter import *
from tkinter import messagebox
import os
import tkinter as tk
from tkinter import simpledialog
    
def doing_stocks():
    name = myaskstring("Input data", "Enter box number:", parent = root)
    name2 = myaskstring("Input data2", "Enter box number2:", parent = root)
    name3 = myaskstring("Input data3", "Enter box number3:", parent = root)

class My_QueryString(tk.simpledialog._QueryString):

      def body(self, master):
          self.bind('<KP_Enter>', self.ok)
          self.bind('<Return>', self.ok)
          w = Label(master, text=self.prompt, justify=LEFT)
          w.grid(row=0, padx=5, sticky=W)

          self.entry = Entry(master, name="entry")
          self.entry.grid(row=1, padx=5, sticky=W+E)

          if self.initialvalue is not None:
              self.entry.insert(0, self.initialvalue)
              self.entry.select_range(0, END)

          root.update_idletasks()
          self.entry.focus_force()
          return self.entry

def myaskstring(title, prompt, **kw):
    d = My_QueryString(title, prompt, **kw)
    root.update_idletasks()
    answer = d.result 
    d.destroy()
    return answer
   
root = Tk()
root.geometry("700x761")
label1 = Label(root, text="")
label1.place(x = 0, y = 0)

button2 = Button(root, text = "Doing Stocks", command=doing_stocks).place(x = 300, y = 340)

root.mainloop()

This is a simplified version of the code. I call my simpledialog popups like this:

myaskstring("Title", "Prompt", parent = root)

In the doing_stocks() method the first time I call myaskstring the window and the entry field will be in focus then all times after that it won't be. How can I make every simpledialog be in focus when it appears on the screen?

1

There are 1 best solutions below

0
On

I agree is seems odd that the focus isn't set to each My_QueryString instance when it's initialized. Regardless of the reason why, a workaround for it not happening is to bind a <Map> event handler function to the dialog's Entry widget to shift keyboard focus to itself whenever it's made visible.

The code below shows an implementation doing that. It's based on your code with the important changes indicated with # ALL CAP comments to make them stand out.

import tkinter as tk
from tkinter import simpledialog
from tkinter.constants import *


def doing_stocks():
    name = myaskstring("Input data", "Enter box number:", parent=root)
    name2 = myaskstring("Input data2", "Enter box number2:", parent=root)
    name3 = myaskstring("Input data3", "Enter box number3:", parent=root)


class My_QueryString(tk.simpledialog._QueryString):

    def body(self, master):
        self.bind('<KP_Enter>', self.ok)
        self.bind('<Return>', self.ok)
        w = tk.Label(master, text=self.prompt, justify=LEFT)
        w.grid(row=0, padx=5, sticky=W)

        self.entry = tk.Entry(master, name="entry")
        self.entry.grid(row=1, padx=5, sticky=W+E)
        self.entry.bind('<Map>', self.on_map)  # <--- ADDED.

        if self.initialvalue is not None:
            self.entry.insert(0, self.initialvalue)
            self.entry.select_range(0, END)

        root.update_idletasks()
#        self.entry.focus_force()  # <--- NOT NEEDED.
        return self.entry

    # ADDED METHOD.
    def on_map(self, event):
        self.entry.focus_force()


def myaskstring(title, prompt, **kw):
    d = My_QueryString(title, prompt, **kw)
    root.update_idletasks()
    answer = d.result
#    d.destroy()  # <--- NOT NEEDED.
    return answer


root = tk.Tk()
root.geometry("700x761")

label1 = tk.Label(root, text="")
label1.place(x = 0, y = 0)

button2 = tk.Button(root, text = "Doing Stocks", command=doing_stocks)
button2.place(x = 300, y = 340)

root.mainloop()