Bottom Page

Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
 [Tkinter] Spawn sub-window with button press
#1
Hey, I'm trying to open a sub-window on top of my main window for a specific time, then close it. I'm going the tkinter.Toplevel route for this and plan on destroying it with subwindow.destroy(). But I keep getting an error that I have no idea what to do with. Code:
class MainWindow(ttk.Frame):
    def __init__(self, parent):
        ttk.Frame.__init__(self)
        ttk.Frame.grid(self, column=0, row=0, sticky=('N', 'E', 'S', 'W'))
        ttk.Frame.columnconfigure(self, 0, weight=1)
        ttk.Frame.rowconfigure(self, 0, weight=1)
        self.mem_exists = tkinter.StringVar()
        self.reg_scan = tkinter.StringVar()
        self.widgets()

    def widgets(self):
        self.mem_labl1 = ttk.Label(self, text='Memory Dumps:')
        self.mem_labl1.grid(column=0, row=0)
        self.mem_labl2 = ttk.Label(self, textvariable=self.mem_exists)
        self.mem_labl2.grid(column=0, row=1)
        self.mem_buton = ttk.Button(self, text='Delete', command=self.delete_dmps)
        self.mem_buton.grid(column=0, row=2)
        self.dmp_separ = ttk.Separator(self, orient='horizontal')
        self.dmp_separ.grid(column=0, row=3, rowspan=1, sticky=('EW'))
        self.scn_labl1 = ttk.Label(self, text='Scan for Dumps')
        self.scn_labl1.grid(column=0, row=4)
        self.scn_buton = ttk.Button(self, text='Scan', command=self.scan_pressed)
        self.scn_buton.grid(column=0, row=5)
        self.vrt_separ = ttk.Separator(self, orient='vertical')
        self.vrt_separ.grid(column=1, row=0, rowspan=6, sticky=('NS'))
        self.reg_labl1 = ttk.Label(self, text='Unneeded Keys')
        self.reg_labl1.grid(column=2, row=0)
        self.reg_labl2 = ttk.Label(self, textvariable=self.reg_scan)
        self.reg_labl2.grid(column=2, row=1)
        self.reg_buton = ttk.Button(self, text='Delete', command=self.delete_keys)
        self.reg_buton.grid(column=2, row=2)
        ......
    def scan_pressed(self):
        self.sub_win = tkinter.Toplevel(self, root) <----- ERROR HERE
        self.write_dumps()
        size = self.get_size()
        self.mem_exists.set(f'{size} KB of memory dumps found!')
When I press the button (scn_buton) I want it to spawn a little window with a label that says "scanning..." (or something of that nature), but it gives me this error:

Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python37\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "c:\users\mark\downloads\practice_gui_2.py", line 83, in scan_pressed
self.sub_win = tkinter.Toplevel(self, root)
File "C:\Python37\lib\tkinter\__init__.py", line 2334, in __init__
if wmkey in cnf:
File "C:\Python37\lib\tkinter\__init__.py", line 1489, in cget
return self.tk.call(self._w, 'cget', '-' + key)
TypeError: can only concatenate str (not "int") to str

I have no clue where to even begin on that one. Google results turn up things not related to tkinter.

malonn

Well, I figured out why the window wouldn't spawn. The fix was to remove the master from the call to Toplevel() like so
self.sub_win = tkinter.Toplevel(self)
but the window doesn't spawn until after the rest of the code for that method ("scan_pressed") is run. Why is that? The code calls os.walk which takes a while to complete and I want the second window to block it while it happens.
Quote
#2
See if this makes more sense. It also runs without errors.
import sys
if 3 == sys.version_info[0]: ## 3.X is default if dual system
    import tkinter as tk     ## Python 3.x
    from tkinter import ttk
else:
    import Tkinter as tk     ## Python 2.x
    import ttk

class MainWindow():
    def __init__(self, parent):
        self.parent=parent
        self.fr=ttk.Frame(parent)
        self.fr.grid(column=0, row=0, sticky='nsew')
        self.fr.columnconfigure(0, weight=1)
        self.fr.rowconfigure(0, weight=1)
        self.mem_exists = tk.StringVar()
        self.reg_scan = tk.StringVar()
        self.sub_win=None
        self.widgets()
 

    def delete_dmps(self):
        if self.sub_win:
            self.sub_win.destroy()

    def widgets(self):
        self.mem_labl1 = ttk.Label(self.fr, text='Memory Dumps:')
        self.mem_labl1.grid(column=0, row=0)
        self.mem_labl2 = ttk.Label(self.fr, textvariable=self.mem_exists)
        self.mem_labl2.grid(column=0, row=1)
        self.mem_buton = ttk.Button(self.fr, text='Delete', command=self.delete_dmps)
        self.mem_buton.grid(column=0, row=2)
        self.dmp_separ = ttk.Separator(self.fr, orient='horizontal')
        self.dmp_separ.grid(column=0, row=3, rowspan=1, sticky=('EW'))
        self.scn_labl1 = ttk.Label(self.fr, text='Scan for Dumps')
        self.scn_labl1.grid(column=0, row=4)
        self.scn_buton = ttk.Button(self.fr, text='Scan', command=self.scan_pressed)
        self.scn_buton.grid(column=0, row=5)
        self.vrt_separ = ttk.Separator(self.fr, orient='vertical')
        self.vrt_separ.grid(column=1, row=0, rowspan=6, sticky=('NS'))
        self.reg_labl1 = ttk.Label(self.fr, text='Unneeded Keys')
        self.reg_labl1.grid(column=2, row=0)
        self.reg_labl2 = ttk.Label(self.fr, textvariable=self.reg_scan)
        self.reg_labl2.grid(column=2, row=1)
##        self.reg_buton = ttk.Button(self.fr, text='Delete', command=self.delete_keys)
##        self.reg_buton.grid(column=2, row=2)
 
    def scan_pressed(self):
        self.sub_win = tk.Toplevel(self.parent) ##<----- ERROR HERE
##        self.write_dumps()
##        size = self.get_size()
##        self.mem_exists.set(f'{size} KB of memory dumps found!')

root=tk.Tk()
MW=MainWindow(root)
root.mainloop()
Quote
#3
I'm sorry, I didn't post the full program, just an excerpt of the problem I was having. Here's the full (working) program:

import os
import winreg
import tkinter
from tkinter import ttk
import ctypes
import sys


class MainWindow(ttk.Frame):
    def __init__(self, parent):
        ttk.Frame.__init__(self)
        ttk.Frame.grid(self, column=0, row=0, sticky=('N', 'E', 'S', 'W'))
        ttk.Frame.columnconfigure(self, 0, weight=1)
        ttk.Frame.rowconfigure(self, 0, weight=1)
        self.mem_exists = tkinter.StringVar()
        self.reg_scan = tkinter.StringVar()
        self.widgets()

    def widgets(self):
        self.mem_labl1 = ttk.Label(self, text='Memory Dumps:')
        self.mem_labl1.grid(column=0, row=0)
        self.mem_labl2 = ttk.Label(self, textvariable=self.mem_exists)
        self.mem_labl2.grid(column=0, row=1)
        self.mem_buton = ttk.Button(self, text='Delete', command=self.delete_dmps)
        self.mem_buton.grid(column=0, row=2)
        self.dmp_separ = ttk.Separator(self, orient='horizontal')
        self.dmp_separ.grid(column=0, row=3, rowspan=1, sticky=('EW'))
        self.scn_labl1 = ttk.Label(self, text='Scan for Dumps')
        self.scn_labl1.grid(column=0, row=4)
        self.scn_buton = ttk.Button(self, text='Scan', command=self.scan_pressed)
        self.scn_buton.grid(column=0, row=5)
        self.vrt_separ = ttk.Separator(self, orient='vertical')
        self.vrt_separ.grid(column=1, row=0, rowspan=6, sticky=('NS'))
        self.reg_labl1 = ttk.Label(self, text='Unneeded Keys')
        self.reg_labl1.grid(column=2, row=0)
        self.reg_labl2 = ttk.Label(self, textvariable=self.reg_scan)
        self.reg_labl2.grid(column=2, row=1)
        self.reg_buton = ttk.Button(self, text='Delete', command=self.delete_keys)
        self.reg_buton.grid(column=2, row=2)

    def scan_dumps(self):
        '''Walks the OS drive and returns a dict with the path to and
        size of each .DMP file found on the drive.'''
        dumps = {}
        k = 0
        for dpath, dname, fname in os.walk('C:\\'):
            for f_n in fname:
                if f_n.endswith('.dmp'):
                    dumps[k] = [os.path.join(dpath, f_n), os.stat(os.path.join(dpath, f_n)).st_size]
                    k += 1
        return dumps

    def write_dumps(self):
        dumps = self.scan_dumps()
        with open(os.path.join(sys.path[0], 'practice_gui_2.ini'), 'w') as f:
            for key, value in dumps.items():
                f.write(f'{value}\n')

    def read_dumps(self):
        dumps = {}
        k = 0
        with open(os.path.join(sys.path[0], 'practice_gui_2.ini'), 'r') as f:
            for line in f:
                lst = line.split(',')
                pth = lst[0][2:-1]
                sze = lst[1][1:-2]
                dumps[k] = [os.path.normpath(pth), sze]
                k += 1
        return dumps

    def get_size(self):
        '''Reads from ini created by "write_dumps()" and gets total size
        of all .DMP files to display in the GUI.'''
        dumps = self.read_dumps()
        tsize = 0
        for key, value in dumps.items():
            tsize += int(value[1])
        tsize /= 1024
        tsize = round(tsize)
        return format(tsize, ',')

    def scan_pressed(self):
        self.sub_win = tkinter.Toplevel(self)
        self.write_dumps()
        size = self.get_size()
        self.mem_exists.set(f'{size} KB of memory dumps found!')

    def get_profile_keys(self):
        '''Opens a specific registry key and creates a list of key +
        sub-key.'''
        reg_key = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Profiles'
        with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, reg_key, 0, winreg.KEY_ALL_ACCESS | winreg.KEY_WOW64_64KEY) as k:
            ns = winreg.QueryInfoKey(k)[0]
            subs = []
            for i in range(ns):
                subs.append(reg_key + '\\' + winreg.EnumKey(k, i))
        return subs

    def get_newest_keys(self):
        '''Takes "get_profile_keys" and decodes the "DateCreated" registry
        value.  Next finds the newest values per "DateCreated"and returns
        a list of the full registry key for the newest key(s).'''
        keys = self.get_profile_keys()
        stamp = []
        stamps = {}
        for i in range(len(keys)):
            reg_key = keys[i]
            with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, reg_key, 0, winreg.KEY_ALL_ACCESS) as k:
                val = winreg.QueryValueEx(k, 'DateCreated')
                stamp.append(int.from_bytes(val[0][:2], 'little'))
                stamp.append(int.from_bytes(val[0][2:4], 'little'))
                stamp.append(int.from_bytes(val[0][6:8], 'little'))
                stamp.append(int.from_bytes(val[0][8:10], 'little'))
                stamp.append(int.from_bytes(val[0][10:12], 'little'))
                stamp.append(int.from_bytes(val[0][12:14], 'little'))
                stamps[i] = stamp
                stamp = []
        if len(stamps) == 1:
            return None
        elif len(stamps) == 2:
            z = 0
            for x in stamps[0]:
                if x > stamps[1][z]:
                    return keys[0]
                elif x < stamps[1][z]:
                    return keys[1]
                z += 1
        # add condition for more than two keys

    def delete_dmps(self):
        '''Walks the dict created by "scan_dumps()"and removes each file
        stored.'''
        dumps = self.read_dumps()
        for key, value in dumps.items():
            path = value[0]
            os.remove(path)
        self.write_dumps()
        size = self.get_size()
        self.mem_exists.set(f'{size} KB of memory dumps found!')

    def delete_keys(self):
        '''Takes the list returned by "get_newest_keys" and deletes each
        key.'''
        delete = self.get_newest_keys()
        if delete is None:
            return None
        elif isinstance(delete, str):
            winreg.DeleteKey(winreg.HKEY_LOCAL_MACHINE, delete)
        else:
            for x in delete:
                winreg.DeleteKey(winreg.HKEY_LOCAL_MACHINE, x)

    def set_mem_label(self):
        size = self.get_size()
        self.mem_exists.set(f'{size} KB of memory dumps found!')

    def set_reg_label(self):
        keys = self.get_profile_keys()
        if len(keys) > 1:
            num = len(keys) - 1
            self.reg_scan.set(f'{num} unwanted key(s) found!')
        else:
            self.reg_scan.set('No unwanted keys found!')


if ctypes.windll.shell32.IsUserAnAdmin():
    root = tkinter.Tk()
    gui = MainWindow(root)
    gui.set_mem_label()
    gui.set_reg_label()
    gui.mainloop()
else:
    ctypes.windll.shell32.ShellExecuteW(None, 'runas', sys.executable, 'practice_gui_2.py', None, 1)
It all works, I managed to get the sub-window to show. The problem is it doesn't show until after the rest of the method code runs.

def scan_pressed(self):
        self.sub_win = tkinter.Toplevel(self)
        self.write_dumps()
        size = self.get_size()
        self.mem_exists.set(f'{size} KB of memory dumps found!')
The first line in that code is to show the sub-window. Why doesn't the sub-window show first, then the rest of the code runs. I just want to window to pop up to distract the user while the methods are called (which could take time).
Thanks for the help though,@woooee
Quote
#4
The problem has been solved through the use of wait_visibility(). Merely add this:
def scan_pressed(self):
        self.sub_win = tkinter.Toplevel(self)
        self.sub_win.wait_visibility()
and the window now opens before the rest of the code runs.
malonn
Quote

Top Page

Possibly Related Threads...
Thread Author Replies Views Last Post
  tkinter window and turtle window error 1885 3 125 Nov-02-2019, 12:18 PM
Last Post: 1885
  [PySimpleGui] How to alter mouse click button of a standard submit button? skyerosebud 3 343 Jul-21-2019, 06:02 PM
Last Post: FullOfHelp
  [Tkinter] how to input a random entry with each button press? nadavrock 1 533 Jun-17-2019, 05:28 AM
Last Post: Yoriz
  [Tkinter] Tkinter window pop up again when i click button Orimura_Sandy 1 498 May-12-2019, 08:17 PM
Last Post: joe_momma
  [WxPython] Adding a Window to a Button wxPython ShashankDS 4 525 Apr-23-2019, 06:53 PM
Last Post: Yoriz
  tkinter- adding a new window after clicking a button built on the gui ShashankDS 2 633 Apr-18-2019, 12:48 PM
Last Post: ShashankDS
  [PyQt] Resize button with window resize FesterJester 2 1,702 Dec-03-2018, 12:02 AM
Last Post: FesterJester
  [Tkinter] Updating Label After Button Press malonn 7 1,295 Aug-23-2018, 10:52 PM
Last Post: malonn
  tkinter button acts normal ONLY after clicking off the window justin_m 8 1,376 Apr-24-2018, 06:14 AM
Last Post: Larz60+
  [Tkinter] [Solved]Detecting key press in gui Barrowman 3 10,411 Dec-10-2017, 04:38 AM
Last Post: hereathome

Forum Jump:


Users browsing this thread: 1 Guest(s)