From 4c584f28e9368b9d85181d85dfe4900bf15f5872 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Wed, 28 Nov 2018 13:36:12 -0500 Subject: [PATCH] Initial checkin --- .../Qt_Demo_Desktop_Widget_CPU_Dashboard.py | 110 ++++++++++++++++++ .../Qt_Demo_Desktop_Widget_CPU_Graph.py | 78 +++++++++++++ .../Qt_Demo_Desktop_Widget_Timer.py | 72 ++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 PySimpleGUIQt/Demo Programs/Qt_Demo_Desktop_Widget_CPU_Dashboard.py create mode 100644 PySimpleGUIQt/Demo Programs/Qt_Demo_Desktop_Widget_CPU_Graph.py create mode 100644 PySimpleGUIQt/Demo Programs/Qt_Demo_Desktop_Widget_Timer.py diff --git a/PySimpleGUIQt/Demo Programs/Qt_Demo_Desktop_Widget_CPU_Dashboard.py b/PySimpleGUIQt/Demo Programs/Qt_Demo_Desktop_Widget_CPU_Dashboard.py new file mode 100644 index 00000000..a2049732 --- /dev/null +++ b/PySimpleGUIQt/Demo Programs/Qt_Demo_Desktop_Widget_CPU_Dashboard.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python +import sys +if sys.version_info[0] >= 3: + import PySimpleGUIQt as sg +else: + import PySimpleGUI27 as sg +import psutil + +""" + Desktop floating widget - CPU Cores + Uses psutil to display: + CPU usage on each individual core + Information is updated once a second and is shown as an area graph that scrolls +""" + +GRAPH_WIDTH = 120 # each individual graph size in pixels +GRAPH_HEIGHT = 60 +TRANSPARENCY = .8 # how transparent the window looks. 0 = invisible, 1 = normal window +NUM_COLS = 4 +POLL_FREQUENCY = 800 # how often to update graphs in milliseconds + +colors = ('#23a0a0', '#56d856', '#be45be', '#5681d8', '#d34545', '#BE7C29') + +# DashGraph does the drawing of each graph +class DashGraph(object): + def __init__(self, graph_elem, text_elem, starting_count, color): + self.graph_current_item = 0 + self.graph_elem = graph_elem + self.text_elem = text_elem + self.prev_value = starting_count + self.max_sent = 1 + self.color = color + + def graph_percentage_abs(self, value): + self.graph_elem.DrawLine((self.graph_current_item, 0), (self.graph_current_item, value), color=self.color) + if self.graph_current_item >= GRAPH_WIDTH: + self.graph_elem.Move(-1,0) + else: + self.graph_current_item += 1 + + def text_display(self, text): + self.text_elem.Update(text) + +def main(): + # A couple of "Uber Elements" that combine several elements and enable bulk edits + def Txt(text, **kwargs): + return(sg.Text(text, font=('Helvetica 8'), **kwargs)) + + def GraphColumn(name, key): + col = sg.Column([[Txt(name, key=key+'_TXT_'), ], + [sg.Graph((GRAPH_WIDTH, GRAPH_HEIGHT), (0, 0), (GRAPH_WIDTH, 100), background_color='black', + key=key+'_GRAPH_')]], pad=(2, 2)) + return col + + + num_cores = len(psutil.cpu_percent(percpu=True)) # get the number of cores in the CPU + + sg.ChangeLookAndFeel('Black') + sg.SetOptions(element_padding=(0,0), margins=(0,0), border_width=0) + + # ---------------- Create Layout ---------------- + layout = [[ sg.Button('', image_data=red_x , button_color=('red', 'black'), key='Exit', tooltip='Closes window'),sg.Stretch(), + sg.Text(' CPU Core Usage'), sg.Stretch()] ] + + # add on the graphs + for rows in range(num_cores//NUM_COLS+1): + row = [] + for cols in range(min(num_cores-rows*NUM_COLS, NUM_COLS)): + row.append(GraphColumn('CPU '+str(rows*NUM_COLS+cols), '_CPU_'+str(rows*NUM_COLS+cols))) + layout.append(row) + + # ---------------- Create Window ---------------- + window = sg.Window('PSG System Dashboard', + keep_on_top=True, + auto_size_buttons=False, + grab_anywhere=True, + no_titlebar=True, + default_button_element_size=(20, 15), + return_keyboard_events=True, + alpha_channel=TRANSPARENCY, + use_default_focus=False, + ).Layout(layout) + + # setup graphs & initial values + graphs = [] + for i in range(num_cores): + graphs.append(DashGraph(window.FindElement('_CPU_'+str(i)+'_GRAPH_'), + window.FindElement('_CPU_'+str(i) + '_TXT_'), + 0, colors[i%6])) + + # ---------------- main loop ---------------- + while (True): + # --------- Read and update window once every Polling Frequency -------- + event, values = window.Read(timeout=POLL_FREQUENCY) + if event in (None, 'Exit'): # Be nice and give an exit + break + # read CPU for each core + stats = psutil.cpu_percent(interval=.2, percpu=True) + # Update each graph + for i in range(num_cores): + graphs[i].graph_percentage_abs(stats[i]) + graphs[i].text_display('{} CPU {:2.0f}'.format(i, stats[i])) + window.Close() + +if __name__ == "__main__": + # the clever Red X graphic + red_x = b"R0lGODlhEAAQAPeQAIsAAI0AAI4AAI8AAJIAAJUAAJQCApkAAJoAAJ4AAJkJCaAAAKYAAKcAAKcCAKcDA6cGAKgAAKsAAKsCAKwAAK0AAK8AAK4CAK8DAqUJAKULAKwLALAAALEAALIAALMAALMDALQAALUAALYAALcEALoAALsAALsCALwAAL8AALkJAL4NAL8NAKoTAKwbAbEQALMVAL0QAL0RAKsREaodHbkQELMsALg2ALk3ALs+ALE2FbgpKbA1Nbc1Nb44N8AAAMIWAMsvAMUgDMcxAKVABb9NBbVJErFYEq1iMrtoMr5kP8BKAMFLAMxKANBBANFCANJFANFEB9JKAMFcANFZANZcANpfAMJUEMZVEc5hAM5pAMluBdRsANR8AM9YOrdERMpIQs1UVMR5WNt8X8VgYMdlZcxtYtx4YNF/btp9eraNf9qXXNCCZsyLeNSLd8SSecySf82kd9qqc9uBgdyBgd+EhN6JgtSIiNuJieGHhOGLg+GKhOKamty1ste4sNO+ueenp+inp+HHrebGrefKuOPTzejWzera1O7b1vLb2/bl4vTu7fbw7ffx7vnz8f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAJAALAAAAAAQABAAAAjUACEJHEiwYEEABniQKfNFgQCDkATQwAMokEU+PQgUFDAjjR09e/LUmUNnh8aBCcCgUeRmzBkzie6EeQBAoAAMXuA8ciRGCaJHfXzUMCAQgYooWN48anTokR8dQk4sELggBhQrU9Q8evSHiJQgLCIIfMDCSZUjhbYuQkLFCRAMAiOQGGLE0CNBcZYmaRIDLqQFGF60eTRoSxc5jwjhACFWIAgMLtgUocJFy5orL0IQRHAiQgsbRZYswbEhBIiCCH6EiJAhAwQMKU5DjHCi9gnZEHMTDAgAOw==" + + main() + sys.exit(69) \ No newline at end of file diff --git a/PySimpleGUIQt/Demo Programs/Qt_Demo_Desktop_Widget_CPU_Graph.py b/PySimpleGUIQt/Demo Programs/Qt_Demo_Desktop_Widget_CPU_Graph.py new file mode 100644 index 00000000..0d5cdaaf --- /dev/null +++ b/PySimpleGUIQt/Demo Programs/Qt_Demo_Desktop_Widget_CPU_Graph.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +import sys +import sys +if sys.version_info[0] >= 3: + import PySimpleGUIQt as sg +else: + import PySimpleGUI27 as sg +import time +import random +import psutil +from threading import Thread + + +STEP_SIZE=3 +SAMPLES = 300 +SAMPLE_MAX = 500 +CANVAS_SIZE = (300,200) + + +g_interval = .25 +g_cpu_percent = 0 +g_procs = None +g_exit = False + +def CPU_thread(args): + global g_interval, g_cpu_percent, g_procs, g_exit + + while not g_exit: + try: + g_cpu_percent = psutil.cpu_percent(interval=g_interval) + g_procs = psutil.process_iter() + except: + pass + +def main(): + global g_exit, g_response_time + # start ping measurement thread + + sg.ChangeLookAndFeel('Black') + sg.SetOptions(element_padding=(0,0)) + + layout = [ [sg.Quit( button_color=('white','black')), sg.T('', font='Helvetica 25', key='output')], + [sg.Graph(CANVAS_SIZE, (0,0), (SAMPLES,SAMPLE_MAX),background_color='black', key='graph')],] + + window = sg.Window('CPU Graph', grab_anywhere=True, keep_on_top=True, background_color='black', no_titlebar=True, use_default_focus=False, location=(0,0)).Layout(layout) + + graph = window.FindElement('graph') + output = window.FindElement('output') + # start cpu measurement thread + thread = Thread(target=CPU_thread,args=(None,)) + thread.start() + + last_cpu = i = 0 + prev_x, prev_y = 0, 0 + while True: # the Event Loop + event, values = window.Read(timeout=500) + if event == 'Quit' or event is None: # always give ths user a way out + break + # do CPU measurement and graph it + current_cpu = int(g_cpu_percent*10) + if current_cpu == last_cpu: + continue + output.Update(current_cpu/10) # show current cpu usage at top + if current_cpu > SAMPLE_MAX: + current_cpu = SAMPLE_MAX + new_x, new_y = i, current_cpu + if i >= SAMPLES: + graph.Move(-STEP_SIZE,0) # shift graph over if full of data + prev_x = prev_x - STEP_SIZE + graph.DrawLine((prev_x, prev_y), (new_x, new_y), color='white') + prev_x, prev_y = new_x, new_y + i += STEP_SIZE if i < SAMPLES else 0 + last_cpu = current_cpu + + g_exit = True + window.Close() +if __name__ == '__main__': + main() diff --git a/PySimpleGUIQt/Demo Programs/Qt_Demo_Desktop_Widget_Timer.py b/PySimpleGUIQt/Demo Programs/Qt_Demo_Desktop_Widget_Timer.py new file mode 100644 index 00000000..65d4bdc6 --- /dev/null +++ b/PySimpleGUIQt/Demo Programs/Qt_Demo_Desktop_Widget_Timer.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +import sys + +if sys.version_info[0] >= 3: + import PySimpleGUIQt as sg +else: + import PySimpleGUI27 as sg +import time + +""" + Timer Desktop Widget Creates a floating timer that is always on top of other windows You move it by grabbing anywhere on the window Good example of how to do a non-blocking, polling program using SimpleGUI Can be used to poll hardware when running on a Pi + + While the timer ticks are being generated by PySimpleGUI's "timeout" mechanism, the actual value + of the timer that is displayed comes from the system timer, time.time(). This guarantees an + accurate time value is displayed regardless of the accuracy of the PySimpleGUI timer tick. If + this design were not used, then the time value displayed would slowly drift by the amount of time + it takes to execute the PySimpleGUI read and update calls (not good!) + + NOTE - you will get a warning message printed when you exit using exit button. + It will look something like: invalid command name \"1616802625480StopMove\" +""" + +# ---------------- Create Form ---------------- +sg.ChangeLookAndFeel('Black') +sg.SetOptions(element_padding=(0, 0)) + +layout = [ + [sg.Text('test', size=(222, 90), font=('Any', 24), text_color='white', justification='center', key='text')], + [sg.Button('Pause', key='button', button_color=('white', '#001480')), + sg.Button('Reset', button_color=('white', '#007339'), key='Reset'), + sg.Exit(button_color=('white', '#B22222'), key='Exit')] +] + +window = sg.Window('Running Timer', no_titlebar=True, auto_size_buttons=False, keep_on_top=True, + grab_anywhere=True).Layout(layout) + +# ---------------- main loop ---------------- +current_time = 0 +paused = False +start_time = int(round(time.time() * 100)) +while (True): + # --------- Read and update window -------- + if not paused: + event, values = window.Read(timeout=10) + current_time = int(round(time.time() * 100)) - start_time + else: + event, values = window.Read() + if event == 'button': + event = window.FindElement(event).GetText() + # --------- Do Button Operations -------- + if event is None or event == 'Exit': # ALWAYS give a way out of program + break + if event is 'Reset': + start_time = int(round(time.time() * 100)) + current_time = 0 + paused_time = start_time + elif event == 'Pause': + paused = True + paused_time = int(round(time.time() * 100)) + element = window.FindElement('button') + element.Update(text='Run') + elif event == 'Run': + paused = False + start_time = start_time + int(round(time.time() * 100)) - paused_time + element = window.FindElement('button') + element.Update(text='Pause') + + # --------- Display timer in window -------- + window.FindElement('text').Update('{:02d}:{:02d}.{:02d}'.format((current_time // 100) // 60, + (current_time // 100) % 60, + current_time % 100)) +# --------- After loop --------