Update Background Color of Checkbox in PySimpleGuiQT - python-3.x

Im trying to update the background color of my checkbox when it is clicked. However, the moment i call the update method, somehow another event on the same element is triggered, resulting in unexpected behavior. Can somebody tell me how to achieve that?!
My minimal Code is as follows:
import PySimpleGUIQt as sg
layout = [
[sg.Checkbox('test', enable_events=True, key='test', background_color="green",default=True)]
]
window = sg.Window('Sample GUI', layout, finalize=True)
while True: # Event Loop
event, values = window.read(timeout=100)
if event == sg.WINDOW_CLOSED:
break
elif event == "test":
if not values[event]:
window[event].update(background_color="red")
else:
window[event].update(background_color="green")
window.close()

Qt port is still under revision, not everything work fine.
Try also to set the value at the same time for the checkbox when you set the background_color.
import PySimpleGUIQt as sg
layout = [[sg.Checkbox('test', enable_events=True, key='test', background_color="green",default=True)]]
window = sg.Window('Sample GUI', layout, finalize=True)
while True: # Event Loop
event, values = window.read()
if event == sg.WINDOW_CLOSED:
break
elif event == "test":
value = values[event]
if not value:
window[event].update(value=value, background_color="red")
else:
window[event].update(value=value, background_color="green")
window.close()

Related

How To Secure Collapsible / Expandable Frames

Dears,
How To Secure Collapsible / Expandable Frames with password.
I have used the Script shared in : https://github.com/PySimpleGUI/PySimpleGUI/issues/295
Here's a reduced part of it, just to clarify my query :
import PySimpleGUI as sg
layout1 = [[sg.Text('This is layout 1 - It is all Checkboxes')],
*[[sg.CB(f'Checkbox {i}')] for i in range(3)]]
layout2 = [[sg.Text('This is layout 2')],
[sg.Input(key='-IN-')],
[sg.Input(key='-IN2-')]]
layout = [[sg.Column(layout1, key='-COL1-'), sg.Column(layout2, visible=False, key='-COL2-')],
[sg.Button('1'), sg.Button('2'), sg.Button('Exit')]]
window = sg.Window('Swapping the contents of a window', layout)
while True:
event, values = window.read()
print(event, values)
if event in (sg.WIN_CLOSED, 'Exit'):
break
elif event in '123':
window[f'-COL{layout}-'].update(visible=False)
layout = int(event)
window[f'-COL{layout}-'].update(visible=True)
window.close()
What should be the event to be added , so that , once we click on Button "2" , it will ask for User/Password to be able to access inside that frame. Thanks in advance

Python 3.x - Multi mouse button activated auto clicker

I am having troubles with the python code i am trying to write. I am attempting to create an auto-clicker that when I hold down left click and one of the side buttons, left click gets triggered every 0.1 seconds. If I let go of either button, the auto-clicker stops. I have searched through the PyAutoGUI, PyNput, and the PyGame libraries, as well as many of stack overflow posts on the topic of mouse detection. Here is the code I have put together so far. (note, a majority of this code is not mine, I simply do not remember where I grabbed the code snippits otherwise they would be linked below.
from pynput import mouse
from pynput.mouse import Button, Controller
import threading
import time
control = Controller()
running = False
leftPressed=False
rightPressed=False
def process():
print('start')
count = 0
while running:
print(count)
count += 1
control.click(Button.left,1)
print("test")
time.sleep(.05)
print('stop')
def on_click(*args):
global running, leftPressed, rightPressed
if args[-1]:
# mouse key pressed
if args[-2].name == "left":
leftPressed = True
print("Left click")
elif args[-2].name == "x2":
rightPressed = True
if leftPressed and rightPressed:
# if both left and right are pressed
running = True
threading.Thread(target=process).start()
elif not args[-1]:
# mouse key released
if args[-2].name == "x1":
leftPressed = False
elif args[-2].name == "x2":
rightPressed = False
# as one key has been released, both are no longer pressed
running = False
with mouse.Listener(on_click=on_click) as listener:
listener.join()
Any help with this project would be greatly appreciated, I've come to realize the biggest issue is that since the "on click" event is expecting a left click to run the thread, left clicking inside of the thread is more than not ideal, however if it is possible to program it in such a way where this isn't an issue it would be greatly appreciated.
The pseudocode for what I am looking for would be:
if Button.x2 == pressed and Button.left == pressed:
bothPressed = True
else:
bothPressed = False
while bothPressed:
Button.left.click()
I have tried using multiple methods of obtaining the mouse inputs through PyGame and PyNput. However I've found that I understand PyNput the best and would prefer to stick with it.

PySimpleGUI - not show background when window change

In my application I have multiple windows that change based on events(one close and another open) and show only one window at a time. During one window close and another open its take some time since fetch data from database and prepare for window.
Here problem is that during the time of one window close and another open user can see and feel that one is being open and another is being close by seeing the background.
What I want, until second screen is not fully loaded, first window be visible on the screen.
My current code is something like,
import PySimpleGUI as sg
layout = [[sg.Button('Users', key='show_user_list')]]
window = sg.Window('users').Layout(layout)
while True:
event, values = window.Read()
if event == 'show_user_list':
window.Close()
# code ommited here for simplicity
# do mysql stuff to fetch data
# layout2 = ...
# window2 = sg.Window('user listing').Layout(layout2)
# while True:
# event, values = window2.Read()
# ...
# like that I have multiple windows
else:
pass
How I can give users feel like the window content is changing not one window closes and another opens?
Sure, you can make sure the background is not seen by first opening your Window 2, which will be created on top of Window 1, THEN closing your Window 1.
To do this, add a .Finalize() onto the Window 2 creation. This will cause the window to immediate show up. Then on the next line, close Window 1.
import PySimpleGUI as sg
layout = [[sg.Button('Users', key='show_user_list')]]
window = sg.Window('users').Layout(layout)
while True:
event, values = window.Read()
if event == 'show_user_list':
# code ommited here for simplicity
# do mysql stuff to fetch data
# layout2 = ...
# window2 = sg.Window('user listing').Layout(layout2).Finalize()
# window.Close()
# while True:
# event, values = window2.Read()
# ...
# like that I have multiple windows
else:
pass
The key to making this kind of window update work is to create the windows at the same location. The default is to make windows that are centered on the screen. This means if your windows are not the same size then you'll likely notice a small "blip" as you change from one to the other. But it shouldn't look bad because it'll happen so quickly.
If you really want to get fancy, you can add another step which will make the switch between the windows even smoother. This new step involves creating window 2 with Alpha=0, meaning that it's invisible, then after it's fully formed (using Finalize()) you change the Alpha to 1 which will make the window appear.
import PySimpleGUI as sg
layout = [[sg.Text('Example of window-replacement')],
[sg.Combo(['abdeffg', 'rrrfwwew'], size=(10, 4))],
[sg.B('Enable Filter'), sg.B('Warning'), sg.B('Reopen')],]
window = sg.Window('My Text Editor', layout)
while True: # Event Loop
event, values = window.Read()
if event is None:
break
print(event, values)
if event == 'Reopen':
layout2 = [[sg.Text('This is a completely different window')],
[sg.Combo(['abdeffg', 'rrrfwwew'], size=(10, 4))],
[sg.B('Enable Filter'), sg.B('Warning'), sg.B('Reopen')], ]
window2 = sg.Window('My Text Editor', layout2, alpha_channel=0).Finalize()
window2.SetAlpha(1)
window.Close()
window = window2
window.Close()
This removed some of the "painting" of the window that I was seeing. That shouldn't happen because I use this same trick when creating the window to begin with. Alpha is used to hide the window while it's being created.

unexpected behaviour of return_keyboard_events in PySimpleGUI

import PySimpleGUI as sg
layout = [[sg.Button("OK1", key='1', bind_return_key=True)],
[sg.Button("OK2", key='2', bind_return_key=True)],
[sg.Button("OK3", key='3', bind_return_key=True)]]
window = sg.Window("Keyboard Test", return_keyboard_events=True).Layout(layout)
while True:
event, values = window.Read()
print(event)
if event == None:
break
When I run the above code and perform mouse click operation, I get the output as following that is as expected,
clicking on OK1 Button print in the console as: 1
clicking on OK2 Button print in the console as: 2
clicking on OK3 Button print in the console as: 3
But, when I perform keyboard event means, I visit on the button through tab key of keyboard and press Enter on that Button via keyboard it return the same key on all these three button,
Visit on these button one by one via tab key and then press Enter on each I get the result as,
Press Enter on OK1 Button print in the console as: 1
Press Enter on OK2 Button print in the console as: 1
Press Enter on OK3 Button print in the console as: 1
That is not expected output. What I want it should also print their own key same as mouse click event.
What is my intention:
When user press Enter button over OK1, It should print('Hello, OK1 pressed.')
When user press Enter button over OK2, It should print('Hello, OK2 pressed.')
When user press Enter button over OK3, It should print('Hello, OK3 pressed.')
When user click on OK1, It should print('Hello, OK1 pressed.')
When user click on OK2, It should print('Hello, OK2 pressed.')
When user click on OK3, It should print('Hello, OK3 pressed.')
How to achieve this?
I finally understood the question and wrote this as a solution. It's been turned into a Demo Program for the project because people do expect the ENTER key to click a button and yet tkinter and Qt both seem to not work this way. They select buttons using the spacebar.
This source code works for both PySimpleGUI and PySimpleGUIQt. Just use the correct import statement at the top.
import PySimpleGUI as sg
# import PySimpleGUIQt as sg
QT_ENTER_KEY1 = 'special 16777220'
QT_ENTER_KEY2 = 'special 16777221'
layout = [ [sg.T('Test of Enter Key use')],
[sg.In(key='_IN_')],
[sg.Button('Button 1', key='_1_')],
[sg.Button('Button 2', key='_2_')],
[sg.Button('Button 3', key='_3_')], ]
window = sg.Window('My new window', layout,
return_keyboard_events=True)
while True: # Event Loop
event, values = window.Read()
if event is None:
break
if event in ('\r', QT_ENTER_KEY1, QT_ENTER_KEY2): # Check for ENTER key
elem = window.FindElementWithFocus() # go find element with Focus
if elem is not None and elem.Type == sg.ELEM_TYPE_BUTTON: # if it's a button element, click it
elem.Click()
# check for buttons that have been clicked
elif event == '_1_':
print('Button 1 clicked')
elif event == '_2_':
print('Button 2 clicked')
elif event == '_3_':
print('Button 3 clicked')
Out of all of the code above, the part that implements this feature is contained in these 4 lines of code. Add these lines of code to your event loop and then your window will behave such that the ENTER key will click a button. The rest of the code does things with the clicks, is the layout, etc. It's really these statements that implement it.
if event in ('\r', QT_ENTER_KEY1, QT_ENTER_KEY2): # Check for ENTER key
elem = window.FindElementWithFocus() # go find element with Focus
if elem is not None and elem.Type == sg.ELEM_TYPE_BUTTON: # if it's a button element, click it
elem.Click()
I don't fully understand what your goal is. What behavior do you want?
When a button has the focus, pressing the return key doesn't seem to trigger buttons by default. The space bar will though.
Here is some code that will click a button based on a user's keyboard input. I THINK that was what you described after I re-read your question a few times.
import PySimpleGUI as sg
layout = [[sg.Button("OK1", key='_1_', )],
[sg.Button("OK2", key='_2_', )],
[sg.Button("OK3", key='_3_', )]]
window = sg.Window("Keyboard Test", layout, return_keyboard_events=True)
while True:
event, values = window.Read()
# window.Maximize()
print('event: ', event)
if event == None:
break
if event == '1':
window.Element('_1_').Click()
elif event == '2':
window.Element('_2_').Click()
elif event == '3':
window.Element('_3_').Click()
window.Close()
If you want to control the buttons using the keyboard, then what you'll have to do is collect the keyboard key presses and then convert those into whatever behavior you want.
Pressing ENTER when a button has focus (is highlighted) does NOT generate a button click, a SPACE BAR does. You can see this demonstrated in this tkinter program:
import tkinter as tk
def write_slogan():
print("Tkinter is easy to use!")
root = tk.Tk()
frame = tk.Frame(root)
frame.pack()
button = tk.Button(frame,
text="QUIT",
fg="red",
command=quit)
button.pack(side=tk.LEFT)
slogan = tk.Button(frame,
text="Hello",
command=write_slogan)
slogan.pack(side=tk.LEFT)
root.mainloop()
[EDIT - sorry about the edits but I'm experimenting... ]

Getting dict value from for loop in Python

tl;dr:
I have a Scene class and scene01 and scene02, both instances of Scene. scene01 have a button.
This button is inside a dictionary named buttons, e.g. {button_next : scene02}
The for loop goes like this:
def loop(self): #SCENE LOOP
while True:
for event in pg.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pg.quit()
sys.exit()
for k, v in self.buttons.items():
if 'click' in k.handleEvent(event):
self.goto(v)
pg.display.update()
'click' in k.handleEvent(event) is from the PygButton widget. It return when there is a mouse click over the button. Button being an instance of the PygButton() class.
goto() checks if the value from the key-value pair is 'quit' (calling the app to quit) or an instance of Scene, e.g. scene01, calling the scene loop, drawing the new screen and new buttons.
The app starts, the first scene is there as is its buttons, but there is no response from a click on them. Escape quits the app so the loop is working. And exiting the app through the escape doesn't return anything from the IDLE.
I think the problem is on the goto() method and/or how I'm calling the value from the dictionary, but I'm stuck.
Help?
Your indentation seems off. Are you sure you want the second for loop to run only if the user quits because that is how you have set it up. Try this instead:
def loop(self): #SCENE LOOP
while True:
for event in pg.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pg.quit()
sys.exit()
for k, v in self.buttons.items():
if 'click' in k.handleEvent(event):
self.goto(v)
pg.display.update()

Resources