I want to have a select all checkbox in my PySimpleGUI. When the select all checkbox is selected, all other checkboxes should change to True, and if any other box is unchecked, the select all checkbox should change to false state?
I can do it through button clicks, but I couldn't find a way to update checkboxes based on values selected in an another checkbox?
import PySimpleGUI as sg
layout = [
[sg.Checkbox ('select all', key = 'checkbox')],
[sg.Checkbox ('value 1', key='check_value1')],
[sg.Checkbox ('value 2',key='check_value2')],
[sg.Button ('ON', key = 'ON')],
[sg.Button ('OFF', key = 'OFF')]
]
window = sg.Window ('Sample GUI', layout) .Finalize ()
while True: # Event Loop
event,values=window.read()
if event in (None, 'Exit'):
break
elif event == 'ON':
window ['checkbox']. Update (value = True)
elif event == 'OFF':
window ['checkbox']. Update (value = False)
print(event,values)
window.close ()
Is there any way to implement this?
Option value or first argument in method upgrade if True checks the checkbox, False clears it,
Demo code,
import PySimpleGUI as sg
sg.theme('DarkBlue')
layout = [
[sg.Checkbox('All checked', enable_events=True, key='Check_All'),
sg.Checkbox('All unchecked', enable_events=True, key='Uncheck_All')],
[sg.HorizontalSeparator()]] + [
[sg.Checkbox(f'check ({j}, {i})', enable_events=True, key=f'check{j}{i}')
for i in range(5)] for j in range(4)
]
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 == 'Check_All':
for j in range(4):
for i in range(5):
window[f'check{j}{i}'].update(True)
window['Uncheck_All'].update(False)
elif event == 'Uncheck_All':
for j in range(4):
for i in range(5):
window[f'check{j}{i}'].update(False)
window['Check_All'].update(False)
elif event.startswith('check'):
if not values[event]:
window['Check_All'].update(False)
else:
window['Uncheck_All'].update(False)
window.close ()
Update Of the method Value Switch parameters.
In the example below, if you press the ON button, a check will be entered, and if you press the OFF button, the check will be removed.
import PySimpleGUI as sg
from PySimpleGUI import Checkbox, Button
layout = [
[sg.Checkbox ('checkbox', key = 'checkbox')],
[sg.Button ('ON', key = 'ON')],
[sg.Button ('OFF', key = 'OFF')]
]
window = sg.Window ('Sample GUI', layout) .Finalize ()
while True: # Event Loop
event, values = window.read (timeout = 100)
if event in (None, 'Exit'):
break
elif event == 'ON':
window ['checkbox']. Update (value = True)
elif event == 'OFF':
window ['checkbox']. Update (value = False)
window.close ()
For more you can refer to this docs also https://pysimplegui.readthedocs.io/en/latest/call%20reference/#checkbox-element
Related
So this code loads all the data from database and puts it in my table and works perfectly fine
it gets the data.
and if it is a combobox uses setCellWidget, and for normal text uses setItem:
output = LoadData(sql)
if output == []:
return False
for row in output:
row_pos = self.table.rowCount()
self.table.insertRow(row_pos)
for i, column in enumerate(row, 0):
normal_widget_item = True
item = QtWidgets.QTableWidgetItem(str(column))
# The 12 col is always a combobox
if i == 12:
item = QtWidgets.QComboBox()
item.addItems(self.all_messager_types)
item.setCurrentIndex(self.all_messager_types.index(column))
normal_widget_item = False
if i == 15:
flags = QtCore.Qt.ItemFlags()
flags != QtCore.Qt.ItemIsEnabled
item.setFlags(flags)
if normal_widget_item:
self.table.setItem(row_pos, i, item)
else:
self.table.setCellWidget(row_pos,i,item)
self.table.resizeColumnsToContents()
but when I try to use it in a different thread it creates new windows for every widget.
my thread class:
class load_table_thread(threading.Thread):
def __init__(self,target,sql=""):
super().__init__()
self.sql = sql
self.target = target
def run(self):
output = LoadData(self.sql)
if output == []:
return False
for row in output:
row_pos = self.target.table.rowCount()
self.target.table.insertRow(row_pos)
for i, column in enumerate(row, 0):
normal_widget_item = True
item = QtWidgets.QTableWidgetItem(str(column))
if i == 12:
item = QtWidgets.QComboBox()
item.addItems(self.target.all_messager_types)
item.setCurrentIndex(self.target.all_messager_types.index(column))
normal_widget_item = False
if i == 15:
flags = QtCore.Qt.ItemFlags()
flags != QtCore.Qt.ItemIsEnabled
item.setFlags(flags)
if normal_widget_item:
self.target.table.setItem(row_pos, i, item)
else:
self.target.table.setCellWidget(row_pos,i,item)
self.target.table.resizeColumnsToContents()
and this is the way I call it:
th = load_table_thread(self,sql)
th.start()
there is not errors in runtime but the program creates new windows for every combo box ( ignore the text, just look how many windows are open for the combobox ):
See the issue image
I used the pyqt threading system too but the same problem happens.
Tic-tac-toe game using python tkinter is not working correctly.
Tic-tac-toe structure is correct. I just want to change the click event.
Only button9 output shown when click to any button
Every time I click any button this output is shown
from tkinter import *
bclick = True
tk = Tk()
tk.title("Tic Tac toe")
tk.geometry("300x400")
n = 9
btns = []
def ttt(button):
global bclick
print(button)
if button["text"] == "" and bclick == True:
print("if")
button.config(text="X")
bclick = False
elif button["text"] == "" and bclick == False:
print("else")
button["text"] = "0"
bclick = True
for i in range(9):
btns.append(Button(font=('Times 20 bold'), bg='white', fg='black', height=2, width=4))
row = 1
column = 0
index = 1
print(btns)
buttons = StringVar()
for i in btns:
i.grid(row=row, column=column)
i.config(command=lambda: ttt(i))
print(i, i["command"])
column += 1
if index % 3 == 0:
row += 1
column = 0
index += 1
tk.mainloop()
Common misstake. The lambda function is using the last value assigned to i so every lambda will use i=.!button9. change the lambda function to:
i.config(command=lambda current_button=i: ttt(current_button))
which will make lambda use the value of i when the lambda was created.
I'm trying to display the keyboard input on the screen using python3 but here's some issues with the code.
If I type rapidly, the letters get repeated. For example: If I type in zo quickly, the screen output is zozz but if I type slowly, it outputs zo
The shift key isn't working as expected. For example: If I press Left (or right) shift and z, it outputs Z but after I release Left shift and type z, it still outputs Z and the next time when I press z it outputs z. I don't know why this happening because I reset the shift flag at the end to 0
The capslock key isn't working as expected either. Once I press capslock, the output is all uppercase but when I press it again, the output does go into lowercase, it remains uppercase. I know here that the capsLock flag isn't working but I'm not able to debug it.
Any ideas on how to get past these issues?
import pygame
from pygame.locals import *
pygame.init()
def getch_mod():
inputStr = ''
shift = 0
capsLock = 0
a = 30
screen = pygame.display.set_mode((1000, 1000))
pygame.display.set_caption("Key Press Test")
f1=pygame.font.SysFont("comicsansms",24)
while True:
events = list(pygame.event.get())
for ev in events:
screen.fill((255,255,255))
text = f1.render('Enter password:', True, (0,0,0))
screen.blit(text,(10,10))
text = f1.render(inputStr, True, (0,0,0))
screen.blit(text, (100,a))
if (ev.type == pygame.QUIT):
return
if pygame.key.get_focused():
press = pygame.key.get_pressed()
for i in range(0,len(press)):
if (press[i] == 1):
name = pygame.key.name(i)
if (name == 'left shift' or name == 'right shift'):
shift = 1
break
if (name == 'caps lock'):
if (not capsLock):
capsLock = 1
else:
capsLock = 0
break
if (name != 'return' and name != 'left shift' and name != 'right shift' and name != 'caps lock'):
if (shift or capsLock):
name = name.upper()
inputStr += str(name)
shift = 0
pygame.display.update()
c = getch_mod()
Your code is very complex for what you're trying to do.
All you have to do is iterate over the event list and add the characters unicode representation to the string. Avoid calling pygame.key.get_pressed() since it doesn't take the order of the key press into account.
Also, don't have your logic in the event loop unless it's acting on a single event. Currently you're blitting the text for every event that happen, instead of for every frame.
Having pygame.key.get_focused in the event loop is unnecessary, since if a key event has been put in the event loop then the window have to have user focus.
Here's a short example on how to blit key input:
import pygame
pygame.init()
screen = pygame.display.set_mode((480, 720))
input_str = ''
comic_sans_font = pygame.font.SysFont("comicsansms", 24)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == pygame.KEYDOWN:
input_str += event.unicode
text = comic_sans_font.render(input_str, True, (0, 0, 0))
screen.fill((255, 255, 255))
screen.blit(text, (100, 200))
pygame.display.update()
Right now the code executes executes the following "if statement" under the computer_move function *. I want it to wait for the player to click another button. Right now, the code places the x before the player clicks a button to place an "o".
import tkinter as tk
board = tk.Tk()
def player_move(widget):
if widget["o"] not in ("o", "x"):
widget["text"] = "o"
widget["state"] = "disabled"
computer_move()
def computer_move():
if i["text"] == "Open Space":
i["text"] = "x"
i["state"] = "disabled"
else:
c["text"] = "x"
c["state"] = "disabled"
if a["text"] and c["text"] == "x" or "o": # *
b["text"] = "x"
b["state"] = "disabled"
board.geometry("400x500")
board.title("Board")
buttons = []
a = tk.Button(board, text="x", state = "disabled")
a["command"] = lambda x=a:player_move(x)
a.grid(row=0, column = 0)
buttons.append(a)
board.mainloop()
Code doesn't set x but you do it in line
a = tk.Button(board, text="x", state= "disabled")
so remove text="x", state="disabled"
BTW:
widget["o"] is incorrect - button doesn't have property with name "o".
It has property "text" - widget["text"] - which may have value "o" or "x"
if a["text"] and c["text"] == "x" or "o": is rather incorrent. Especially
c["text"] == "x" or "o"
It has to be
c["text"] == "x" or c["text"] == "o"
or
c["text"] in ("x", "o")
I think you try to do
if a["text"] in ("x", "o") and c["text"] in ("x", "o"):
It is better to keep button on list - you can use for loop to check all buttons in computer_move
import tkinter as tk
# --- functions ---
def player_move(btn):
# if button is empty
if btn["text"] not in ("o", "x"):
# then set `o` and disable button
btn["text"] = "o"
btn["state"] = "disabled"
# and make comuter move
computer_move()
def computer_move():
# check all buttons
for btn in buttons:
# if button is empty
if btn["text"] not in ("o", "x"):
# then set `x` and disable button
btn["text"] = "x"
btn["state"] = "disabled"
# and skip checking other buttons
break
# --- main ---
board = tk.Tk()
board.geometry("400x500")
board.title("Board")
buttons = []
for row in range(3):
for col in range(3):
btn = tk.Button(board, width=1)
btn["command"] = lambda x=btn:player_move(x)
btn.grid(row=row, column=col)
buttons.append(btn)
board.mainloop()
I'm attempting to make a store in my game, but am having issues with pygame.mouse.get_pressed(). When the user clicks on a button, the program thinks that they clicked on it more than once, therefore using more credits than the user intended. I would like to add a delay so that the game doesn't do this. I would like 1 click to represent them buying one object. I have tried reducing the framerate for that window, but the result is the same. Here is the code I currently have.
This is where all the mouse action occurs.
def button(x, y, w, h, ic, ac, action = None):
global paused
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x + w > mouse[0] > x and y + h > mouse[1] > y:
pygame.draw.rect(gameDisplay, ac, (x, y, w, h))
if click[0] == 1 and action == Game:
Game()
if click[0] == 1 and action == quitgame:
sys.exit()
if click[0] == 1 and action == None:
paused = False
if click[0] == 1 and action == StartScreen:
save()
StartScreen()
if click[0] == 1 and action == LootScreen:
LootScreen()
if click[0] == 1 and action == open_common_drop:
open_common_drop()
if click[0] == 1 and action == open_rare_drop:
open_rare_drop()
else:
pygame.draw.rect(gameDisplay, ic, (x, y, w, h))
This is where the loot store is currently at.
def LootScreen():
global current_drops
loot = True
while loot:
for event in pygame.event.get():
if event.type == pygame.QUIT:
save()
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_t:
open_common_drop()
elif event.key == pygame.K_y:
open_rare_drop()
if event.key == pygame.K_ESCAPE:
StartScreen()
gameDisplay.fill(gray)
title('Loot Chests!')
button(400, 150, 260, 50, blue, bright_blue, open_common_drop)
button(695, 150, 260, 50, red, bright_red, open_rare_drop)
button(display_width * 0.42, display_height / 1.15, 255, 50, red, bright_red, StartScreen)
game_display_text('Open Common Chest (T)', 407, 165)
game_display_text('Open Rare Chest (Y)', 725, 165)
game_display_text('You Got: %s' % current_drops, 50, display_height / 2)
game_display_text('Credits: %.2f' % player_loot_data['credit_count'], 15, 15)
game_display_text('Main Menu', display_width * 0.47, display_height / 1.13)
game_display_text('Janus\': %s' % player_loot_data['loot_data_one'] , 950, 500)
game_display_text('Peace of Minds: %s' % player_loot_data['loot_data_two'], 950, 535)
pygame.display.update()
clock.tick(30)
You will need to use a bool switch in your button function. Here I re-worked the function in a way that should work.
def button(x, y, w, h, ic, ac, action = None, held):
global paused
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x + w > mouse[0] > x and y + h > mouse[1] > y:
pygame.draw.rect(gameDisplay, ac, (x, y, w, h))
if click[0] == 1:
if held == False:
if action == Game:
Game()
elif action == quitgame:
sys.exit()
elif action == None:
paused = False
elif action == StartScreen:
save()
StartScreen()
elif action == LootScreen:
LootScreen()
elif action == open_common_drop:
open_common_drop()
elif action == open_rare_drop:
open_rare_drop()
held = True
else:
held = False
else:
pygame.draw.rect(gameDisplay, ic, (x, y, w, h))
return held
As you see, there is a new variable held added to the function to process whether the button is held or not. Held is taken and returned here, so it won't reset every time the function is called.
With that down, let me show you why I wrote it that way, and just how this logic works at its core.
import pygame
#
display = pygame.display.set_mode((800,600))
clock = pygame.time.Clock()
#
held = False # Variable to handle if mouse button is held
#
RUNNING = True
while RUNNING:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
RUNNING = False
#
button = pygame.mouse.get_pressed() # Get mouse state
if button[0]: # Check if left mouse button is pressed
if held == False: # Check if button is held down
print(True) # If button is not held down, print true
held = True # Set held eqaual to true for next iteration
else: # If left mouse button is not pressed
held = False # held is set to false, alowing event to happen again
#
display.fill((0,0,0))
#
pygame.display.flip()
#
pygame.quit()
The above is a very simple stand alone program that also implements the held variable to monitor if the mouse button is held. In this program, the variable held is first declared as False as the mouse is not being pressed. Then, within the main loop, pygame.mouse.get_pressed() is called to get the mouse input, and is immediately followed by a check for the left mouse button. If the left mouse button is pressed, a check for held will happen. If it is false, the program will print True. held is then set to True for the next iteration. The else: statement will fire if the left mouse button is not held down and reset held to its default False state.
I would suggest a timed bool switch. Here's an example that should help out.
import time
boolswitch = False
timer = 0.0
clock = time.time()
x = time
while True:
if timer > 0.25:
boolswitch = True
timer = 0.0
else:
x = time.time()
timer += (x-clock)
clock = x
if boolswitch:
click = pygame.mouse.get_pressed()
if click[0] == 1:
boolswitch = False
clock = time.time()