Python Forum
[Tkinter] GUI help and review
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] GUI help and review
#1
This is my first foray into Classes. Code:

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


class MainWindow(ttk.Frame):
    def __init__(self, master):
        ttk.Frame.__init__(self, master)
        self.master = master
        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.reg_labl1 = ttk.Label(self, text='Unneeded Keys')
        self.reg_labl1.grid(column=1, row=0)
        self.reg_labl2 = ttk.Label(self, textvariable=self.reg_scan)
        self.reg_labl2.grid(column=1, row=1)
        self.reg_buton = ttk.Button(self, text='Delete', command=self.delete_keys)
        self.reg_buton.grid(column=1, 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 get_size(self):
        '''Takes the dict created by "scan_dumps()" and gets total size
        of all .DMP files to display in the GUI.'''
        dmp = self.scan_dumps()
        i = 0
        tsize = 0
        while i < len(dmp):
            tsize += dmp[i][1]
            i += 1
        tsize /= 1024
        tsize = round(tsize)
        return format(tsize, ',')

    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) 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.'''
        mem = self.scan_dumps()
        i = 0
        while i < len(mem):
            (p, s) = mem[i]
            os.remove(p)
            i += 1

    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 works fine, but I was wondering if it's "optimal"? Would a vet make any changes? More importantly, I want to have the interface respond to a button press. There already is a command tied to the buttons; it works fine. I want an event to happen in addition to the event tied to the button. I want the label with a variable to change what it displays after the button is pressed and the event is fired.
So, you press the button, it does what it is supposed to, then the label gets updated with new info to show that the button has been pressed. If I could be directed, I can figure out the rest.

Thanks,
-malonn
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020