commit
ddc30310fb
|
@ -27,7 +27,7 @@ sg.theme(THEME)
|
||||||
graph = sg.Graph(GSIZE, (0, 0), GSIZE, key='-GRAPH-', enable_events=True)
|
graph = sg.Graph(GSIZE, (0, 0), GSIZE, key='-GRAPH-', enable_events=True)
|
||||||
layout = [[graph]]
|
layout = [[graph]]
|
||||||
|
|
||||||
window = sg.Window('CPU Usage', layout, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, finalize=True)
|
window = sg.Window('CPU Usage Widget Square', layout, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, finalize=True)
|
||||||
|
|
||||||
text_id2 = graph.draw_text(f'CPU', (GSIZE[0] // 2, GSIZE[1] // 4), font='Any 20', text_location=sg.TEXT_LOCATION_CENTER, color=sg.theme_button_color()[0])
|
text_id2 = graph.draw_text(f'CPU', (GSIZE[0] // 2, GSIZE[1] // 4), font='Any 20', text_location=sg.TEXT_LOCATION_CENTER, color=sg.theme_button_color()[0])
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ def main():
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
window = sg.Window('CPU Utilization', layout,
|
window = sg.Window('Top CPU Processes', layout,
|
||||||
no_titlebar=True, keep_on_top=True, use_default_focus=False, alpha_channel=.8, grab_anywhere=True)
|
no_titlebar=True, keep_on_top=True, use_default_focus=False, alpha_channel=.8, grab_anywhere=True)
|
||||||
|
|
||||||
# start cpu measurement thread
|
# start cpu measurement thread
|
|
@ -58,7 +58,7 @@ def main():
|
||||||
layout += [[sg.Text('Refresh', font='Any 8', key='-REFRESH-', enable_events=True), sg.Text('❎', enable_events=True, key='Exit Text')]]
|
layout += [[sg.Text('Refresh', font='Any 8', key='-REFRESH-', enable_events=True), sg.Text('❎', enable_events=True, key='Exit Text')]]
|
||||||
|
|
||||||
# ---------------- Create Window ----------------
|
# ---------------- Create Window ----------------
|
||||||
window = sg.Window('Drive status', layout, keep_on_top=True, grab_anywhere=True, no_titlebar=True, alpha_channel=ALPHA, use_default_focus=False,
|
window = sg.Window('Drive Status Widget', layout, keep_on_top=True, grab_anywhere=True, no_titlebar=True, alpha_channel=ALPHA, use_default_focus=False,
|
||||||
finalize=True)
|
finalize=True)
|
||||||
|
|
||||||
update_window(window) # sets the progress bars
|
update_window(window) # sets the progress bars
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import PySimpleGUI as sg
|
||||||
|
import os
|
||||||
|
import psutil
|
||||||
|
import win32api
|
||||||
|
import win32con
|
||||||
|
import win32gui
|
||||||
|
import win32process
|
||||||
|
import cv2
|
||||||
|
from PIL import ImageGrab
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
def convert_string_to_tuple(string):
|
||||||
|
"""
|
||||||
|
Converts a string that represents a tuple. These strings have the format:
|
||||||
|
"('item 1', 'item 2')"
|
||||||
|
The desired return value is ('item 1', 'item 2')
|
||||||
|
:param string:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
parts = string[1:-1].split(',')
|
||||||
|
part1 = parts[0][1:-1]
|
||||||
|
part2 = parts[1][2:-1]
|
||||||
|
return part1, part2
|
||||||
|
|
||||||
|
|
||||||
|
def show_list_by_name(window, output_key, python_only):
|
||||||
|
process_list = get_window_list()
|
||||||
|
|
||||||
|
title_list = []
|
||||||
|
for proc in process_list:
|
||||||
|
names = convert_string_to_tuple(proc)
|
||||||
|
if python_only and names[0] == 'python.exe':
|
||||||
|
title_list.append(names[1])
|
||||||
|
elif not python_only:
|
||||||
|
title_list.append(names[1])
|
||||||
|
title_list.sort()
|
||||||
|
window[output_key].update(title_list)
|
||||||
|
return title_list
|
||||||
|
|
||||||
|
|
||||||
|
def get_window_list():
|
||||||
|
titles = []
|
||||||
|
t = []
|
||||||
|
pidList = [(p.pid, p.name()) for p in psutil.process_iter()]
|
||||||
|
|
||||||
|
def enumWindowsProc(hwnd, lParam):
|
||||||
|
""" append window titles which match a pid """
|
||||||
|
if (lParam is None) or ((lParam is not None) and (win32process.GetWindowThreadProcessId(hwnd)[1] == lParam)):
|
||||||
|
text = win32gui.GetWindowText(hwnd)
|
||||||
|
if text:
|
||||||
|
wStyle = win32api.GetWindowLong(hwnd, win32con.GWL_STYLE)
|
||||||
|
if wStyle & win32con.WS_VISIBLE:
|
||||||
|
t.append("%s" % (text))
|
||||||
|
return
|
||||||
|
|
||||||
|
def enumProcWnds(pid=None):
|
||||||
|
win32gui.EnumWindows(enumWindowsProc, pid)
|
||||||
|
|
||||||
|
for pid, pName in pidList:
|
||||||
|
enumProcWnds(pid)
|
||||||
|
if t:
|
||||||
|
for title in t:
|
||||||
|
titles.append("('{0}', '{1}')".format(pName, title))
|
||||||
|
t = []
|
||||||
|
titles = sorted(titles, key=lambda x: x[0].lower())
|
||||||
|
return titles
|
||||||
|
|
||||||
|
|
||||||
|
def save_win(filename=None, title=None, crop=True):
|
||||||
|
"""
|
||||||
|
Saves a window with the title provided as a file using the provided filename.
|
||||||
|
If one of them is missing, then a window is created and the information collected
|
||||||
|
|
||||||
|
:param filename:
|
||||||
|
:param title:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
C = 7 if crop else 0 # pixels to crop
|
||||||
|
if filename is None or title is None:
|
||||||
|
layout = [[sg.T('Choose window to save', font='Any 18')],
|
||||||
|
[sg.T('The extension you choose for filename will determine the image format')],
|
||||||
|
[sg.T('Window Title:', size=(12, 1)), sg.I(title if title is not None else '', key='-T-')],
|
||||||
|
[sg.T('Filename:', size=(12, 1)), sg.I(filename if filename is not None else '', key='-F-')],
|
||||||
|
[sg.Button('Ok', bind_return_key=True), sg.Button('Cancel')]]
|
||||||
|
event, values = sg.Window('Choose Win Title and Filename', layout).read(close=True)
|
||||||
|
if event != 'Ok': # if cancelled or closed the window
|
||||||
|
print('Cancelling the save')
|
||||||
|
return
|
||||||
|
filename, title = values['-F-'], values['-T-']
|
||||||
|
try:
|
||||||
|
fceuxHWND = win32gui.FindWindow(None, title)
|
||||||
|
rect = win32gui.GetWindowRect(fceuxHWND)
|
||||||
|
rect_cropped = (rect[0] + C, rect[1], rect[2] - C, rect[3] - C)
|
||||||
|
frame = np.array(ImageGrab.grab(bbox=rect_cropped), dtype=np.uint8)
|
||||||
|
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||||
|
cv2.imwrite(filename, frame)
|
||||||
|
sg.cprint('Wrote image to file:', filename)
|
||||||
|
except Exception as e:
|
||||||
|
sg.popup('Error trying to save screenshot file', e, keep_on_top=True)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
layout = [[sg.Text('Window Snapshot', key='-T-', font='Any 20', justification='c')],
|
||||||
|
[sg.Listbox(values=[' '], size=(50, 20), select_mode=sg.SELECT_MODE_EXTENDED, font=('Courier', 12), key='-PROCESSES-')],
|
||||||
|
[sg.Checkbox('Show only Python programs', default=True, key='-PYTHON ONLY-')],
|
||||||
|
[sg.Checkbox('Crop image', default=True, key='-CROP-')],
|
||||||
|
[sg.Multiline(size=(63, 10), font=('Courier', 10), key='-ML-')],
|
||||||
|
[sg.Text('Output folder:'), sg.In(os.path.dirname(__file__), key='-FOLDER-'), sg.FolderBrowse()],
|
||||||
|
[sg.Button('Refresh'),
|
||||||
|
sg.Button('Snapshot', button_color=('white', 'DarkOrange2')),
|
||||||
|
sg.Exit(button_color=('white', 'sea green'))]]
|
||||||
|
|
||||||
|
window = sg.Window('Window Snapshot', layout, keep_on_top=True, auto_size_buttons=False, default_button_element_size=(12, 1), finalize=True)
|
||||||
|
|
||||||
|
window['-T-'].expand(True, False, False) # causes text to center by expanding the element
|
||||||
|
|
||||||
|
sg.cprint_set_output_destination(window, '-ML-')
|
||||||
|
show_list_by_name(window, '-PROCESSES-', True)
|
||||||
|
|
||||||
|
# ---------------- main loop ----------------
|
||||||
|
while True:
|
||||||
|
# --------- Read and update window --------
|
||||||
|
event, values = window.read()
|
||||||
|
if event in (sg.WIN_CLOSED, 'Exit'):
|
||||||
|
break
|
||||||
|
|
||||||
|
# --------- Do Button Operations --------
|
||||||
|
if event == 'Refresh':
|
||||||
|
show_list_by_name(window, '-PROCESSES-', values['-PYTHON ONLY-'])
|
||||||
|
elif event == 'Snapshot':
|
||||||
|
for title in values['-PROCESSES-']:
|
||||||
|
sg.cprint('Saving: ', end='', c='white on red')
|
||||||
|
sg.cprint(title)
|
||||||
|
output_filename = os.path.join(values['-FOLDER-'], f'{title}.png')
|
||||||
|
save_win(output_filename, title, values['-CROP-'])
|
||||||
|
window.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
version = __version__ = "4.24.0.1 Unreleased\nAdded k parameter to buttons, new text wrapping behavior for popups, new docstring for keys"
|
version = __version__ = "4.24.0.2 Unreleased\nAdded k parameter to buttons, new text wrapping behavior for popups, new docstring for keys, new single-string button_color format ('white on red')"
|
||||||
|
|
||||||
port = 'PySimpleGUI'
|
port = 'PySimpleGUI'
|
||||||
|
|
||||||
|
@ -2885,7 +2885,7 @@ class Button(Element):
|
||||||
:param auto_size_button: if True the button size is sized to fit the text
|
:param auto_size_button: if True the button size is sized to fit the text
|
||||||
:type auto_size_button: (bool)
|
:type auto_size_button: (bool)
|
||||||
:param button_color: of button. Easy to remember which is which if you say "ON" between colors. "red" on "green".
|
:param button_color: of button. Easy to remember which is which if you say "ON" between colors. "red" on "green".
|
||||||
:type button_color: Tuple[str, str] == (text color, background color)
|
:type button_color: Tuple[str, str] or (str) == (text color, background color)
|
||||||
:param disabled_button_color: colors to use when button is disabled (text, background). Use None for a color if don't want to change. Only ttk buttons support both text and background colors. tk buttons only support changing text color
|
:param disabled_button_color: colors to use when button is disabled (text, background). Use None for a color if don't want to change. Only ttk buttons support both text and background colors. tk buttons only support changing text color
|
||||||
:type disabled_button_color: Tuple[str, str]
|
:type disabled_button_color: Tuple[str, str]
|
||||||
:param use_ttk_buttons: True = use ttk buttons. False = do not use ttk buttons. None (Default) = use ttk buttons only if on a Mac and not with button images
|
:param use_ttk_buttons: True = use ttk buttons. False = do not use ttk buttons. None (Default) = use ttk buttons only if on a Mac and not with button images
|
||||||
|
@ -2914,7 +2914,16 @@ class Button(Element):
|
||||||
self.Widget = self.TKButton = None # type: tk.Button
|
self.Widget = self.TKButton = None # type: tk.Button
|
||||||
self.Target = target
|
self.Target = target
|
||||||
self.ButtonText = str(button_text)
|
self.ButtonText = str(button_text)
|
||||||
self.ButtonColor = button_color if button_color != None else DEFAULT_BUTTON_COLOR
|
# Button colors can be a tuple (text, background) or a string with format "text on background"
|
||||||
|
if button_color is None:
|
||||||
|
button_color = DEFAULT_BUTTON_COLOR
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
if isinstance(button_color,str):
|
||||||
|
button_color = button_color.split(' on ')
|
||||||
|
except Exception as e:
|
||||||
|
print('* cprint warning * you messed up with color formatting', e)
|
||||||
|
self.ButtonColor = button_color
|
||||||
self.DisabledButtonColor = disabled_button_color if disabled_button_color is not None else (None, None)
|
self.DisabledButtonColor = disabled_button_color if disabled_button_color is not None else (None, None)
|
||||||
self.ImageFilename = image_filename
|
self.ImageFilename = image_filename
|
||||||
self.ImageData = image_data
|
self.ImageData = image_data
|
||||||
|
@ -3155,7 +3164,7 @@ class Button(Element):
|
||||||
:param text: sets button text
|
:param text: sets button text
|
||||||
:type text: (str)
|
:type text: (str)
|
||||||
:param button_color: of button. Easy to remember which is which if you say "ON" between colors. "red" on "green"
|
:param button_color: of button. Easy to remember which is which if you say "ON" between colors. "red" on "green"
|
||||||
:type button_color: Tuple[str, str] == (text color, background color)
|
:type button_color: Tuple[str, str] or (str)
|
||||||
:param disabled: disable or enable state of the element
|
:param disabled: disable or enable state of the element
|
||||||
:type disabled: (bool)
|
:type disabled: (bool)
|
||||||
:param image_data: Raw or Base64 representation of the image to put on button. Choose either filename or data
|
:param image_data: Raw or Base64 representation of the image to put on button. Choose either filename or data
|
||||||
|
@ -3182,6 +3191,11 @@ class Button(Element):
|
||||||
self.TKButton.configure(text=text)
|
self.TKButton.configure(text=text)
|
||||||
self.ButtonText = text
|
self.ButtonText = text
|
||||||
if button_color != (None, None):
|
if button_color != (None, None):
|
||||||
|
if isinstance(button_color, str):
|
||||||
|
try:
|
||||||
|
button_color = button_color.split(' on ')
|
||||||
|
except Exception as e:
|
||||||
|
print('** Error in formatting your button color **', button_color, e)
|
||||||
if self.UseTtkButtons:
|
if self.UseTtkButtons:
|
||||||
if button_color[0] is not None:
|
if button_color[0] is not None:
|
||||||
button_style.configure(style_name, foreground=button_color[0])
|
button_style.configure(style_name, foreground=button_color[0])
|
||||||
|
@ -16534,7 +16548,7 @@ def main():
|
||||||
[Button('Button'), B('Hide Stuff', metadata='my metadata'),
|
[Button('Button'), B('Hide Stuff', metadata='my metadata'),
|
||||||
Button('ttk Button', use_ttk_buttons=True, tooltip='This is a TTK Button'),
|
Button('ttk Button', use_ttk_buttons=True, tooltip='This is a TTK Button'),
|
||||||
Button('See-through Mode', tooltip='Make the background transparent'),
|
Button('See-through Mode', tooltip='Make the background transparent'),
|
||||||
Button('Install PySimpleGUI from GitHub', button_color=('white', 'red') ,key='-INSTALL-'),
|
Button('Install PySimpleGUI from GitHub', button_color='white on red' ,key='-INSTALL-'),
|
||||||
Button('Exit', tooltip='Exit button')],
|
Button('Exit', tooltip='Exit button')],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue