0

My program streams data and I want to create a popup displaying some text whenever a condition is met. I tried to create a simple tkinter window and ctypes window, but both seem to block my code, preventing it from continuing until the window has been closed. How can I create simple popup window functionality in for example a loop?

What I have so far is something of this structure.

import tkinter as tk
for i in range(11):
    if i%5 == 0:  # Any condition
        popup = tk.Tk()
        label = ttk.Label(popup, text='hi', font=('Verdana', 12))
        label.pack(side='top', padx=10, pady=10)
        popup.mainloop()

and

import ctypes
for i in range(11):
    if i%5 == 0:  # Any condition
        popup = ctypes.windll.user32.MessageBoxW
        popup(None, 'hi', 'title', 0)

However, in both cases the loop will not proceed until I close the popup.

jerry
  • 33
  • 5
  • Does your program otherwise have a Tkinter (or other) GUI being displayed? In other words, is there a `.mainloop()` or equivalent already running? That would make this a lot easier if true. – jasonharper Sep 19 '19 at 18:04
  • The program has no other GUI. I just wanted it to create popups when it finds some event (condition being met). – jerry Sep 19 '19 at 21:40

2 Answers2

2

Case 1 - Tkinter:

You are using mainloop() which is no different than a true while loop. You can make it run continuously by removing it.

import tkinter as tk
from tkinter import ttk

for i in range(11):
    if i%5 == 0:  # Any condition
        popup = tk.Tk()
        label = ttk.Label(popup, text='hi', font=('Verdana', 12))
        label.pack(side='top', padx=10, pady=10)

Case 2 - Ctypes:

To make it run continuously, you will have to use threading.

import ctypes, threading

for i in range(11):
    if i%5 == 0:  # Any condition
        popup = ctypes.windll.user32.MessageBoxW
        threading.Thread(target = lambda :popup(None, 'hi', 'title', 0)).start()
Nouman
  • 6,947
  • 7
  • 32
  • 60
  • ctypes solution worked perfectly. I tried the tkinter solution and my loop was not blocked, but no popups appeared either. I thought it might be that the code finishes and automatically closes the popups so i added time.sleep(1) for each iteration, but I still did not see any popups. – jerry Sep 19 '19 at 21:53
  • @jerry tkinter solution works perfectly for me. I don't find any reason for it not to work. Does it show any error? Which OS are you using? Did you try the exact code I shared? I think the case is that you combined the code by *Krrr* with mine. *Krrr* included the command `root.withdraw` which hides the tkinter window – Nouman Sep 20 '19 at 09:30
  • Im on Win10, and yea i created a new python file with only your code and ran it using anaconda prompt. – jerry Sep 20 '19 at 20:16
1

Not too familiar with ctypes, but for tkinter the UI will always be blocking your main code during the mainloop.

You can somewhat bypass it if you just instantiate your Tk() without invoking mainloop and use the after function:

import tkinter as tk
from tkinter.messagebox import showinfo

root = tk.Tk()
root.withdraw()

for i in range(10):
    if i in (5, 8):
        root.after(ms=1, func=lambda x=i: showinfo('Message!', f'Stopped at {x}'))

# ... do something here

The root.after queues the message box to be displayed after 1 millisecond (ms=1).

A better way might be to create a modeless message/dialog box in ctypes but as mentioned, I'm not too familiar and a quick search didn't yield any simple solution.

r.ook
  • 13,466
  • 2
  • 22
  • 39
  • I tried the code and my loop was not blocked, but no popups appeared either. I thought it might be that the code finishes and automatically closes the popups so i added time.sleep(1) for each iteration, but I still did not see any popups. – jerry Sep 19 '19 at 21:53
  • Odd, it showed up for me on my IDE and running in console/consoleless as well. Granted, I did use `time.sleep(3)` just to make sure. – r.ook Sep 20 '19 at 12:53