Python 3 Tkinter multiple functions running at once - user-interface

I have a chat window for the client portion of a chat application that uses Tkinter for the GUI:
import socket
import select
import time
from threading import Thread
from multiprocessing import Process
import sys
from tkinter import *
HOST = "localhost"
PORT = 5678
client_socket = socket.socket()
client_socket.settimeout(2)
try:
client_socket.connect((HOST, PORT))
except:
print("Connection failed.")
sys.exit()
print("Connected to [" + str(HOST) + "," + str(PORT) + "] successfully")
class ChatWindow:
def __init__(self):
form = Tk()
form.minsize(200, 200)
form.resizable(0, 0)
form.title("Chat")
box = Entry(form)
form.bind("<Return>", lambda x: self.sendmessage(self.textbox.get()))
area = Text(form, width=20, height=10)
area.config(state=DISABLED)
area.grid(row=0, column=1, padx=5, pady=5, sticky=W)
box.grid(row=1, column=1, padx=5, pady=5, sticky=W)
self.textbox = box
self.textarea = area
p1 = Process(target=updating)
p1.start()
p2 = Process(target=tryrecvmessage)
p2.start()
def addchat(self, msg, clear=False):
self.textarea.config(state=NORMAL)
self.textarea.insert(END, msg + "\n")
if clear:
# Option to clear text in box on adding
self.textbox.delete(0, END)
self.textarea.see(END)
self.textarea.config(state=DISABLED)
def sendmessage(self, msg):
data = str.encode(msg)
client_socket.send(data)
self.addchat("<You> " + msg, True)
def updating(self):
while True:
form.update()
form.update_idletasks()
time.sleep(0.01)
def tryrecvmessage(self):
while True:
read_sockets, write_sockets, error_sockets = select.select([client_socket], [], [])
for sock in read_sockets:
data = sock.recv(4096)
if data:
self.addchat(data)
else:
self.addchat("Disconnected...")
sys.exit()
if __name__ == "__main__":
window = ChatWindow()
I want the updating() function and the tryrecvmessage() function to run simultaneously, so that the GUI continues to update while the client still receives messages from the server. I've tried using the threading module as well, but I need to have the threads created below where the other functions are defined, but the other functions need to be defined below __init__(). What do I do?

You can attach the functions to the Tk event loop using the after method, as I explained in this question. Essentially the syntax for after goes like this:
after(ms, command = [function object])
What it does is attach the function object passed in as the command argument to the Tk event loop, repeating it each time ms milliseconds has passed.
One caveat here: you would want to remove the while True from the functions as after would be constantly repeating them anyway.

Related

running asyncio with streamlit dashboard

How do I create a streamlit dashboard that doesn't continuously append the new values from the asyncio.gather(firstWorker(),secondWorker()? The code below runs but will very quickly turn into a very long dashboard where I was hoping to figure out if I could just 2 fixed streamlit title or metric to represent workerOne workerTwo where only the val_one and val_two are updated on the dashboard. streamlit metric or text elements seem to all have the same behavior of continuously appending...any tips appreciated.
Am using python 3.10 on Windows 10 running the dashboard with: $ streamlit run app.py
import streamlit as st
import asyncio
import random as r
val_one = 0
val_two = 0
st.title("Hello World")
async def firstWorker():
global val_one
while True:
await asyncio.sleep(r.randint(1, 3))
val_one = r.randint(1, 10)
st.metric("First Worker Executed: ",val_one)
async def secondWorker():
global val_two
while True:
await asyncio.sleep(r.randint(1, 3))
val_two = r.randint(1, 10)
st.metric("Second Worker Executed: ",val_two)
async def main():
await(asyncio.gather(
firstWorker(),
secondWorker()
)
)
if __name__ == '__main__':
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
asyncio.run(main())
except KeyboardInterrupt:
pass
finally:
print("Closing Loop")
loop.close()
Trying to avoid if possible an infinite long dashboard as well as have the anyscio processes run in the background even if the streamlit dashboard isnt being utilized by a web browser.
Put the code after if __name__ == '__main__': into st.empty() container to overwrite the previous content whenever an update is made.
import streamlit as st
import asyncio
import random as r
val_one = 0
val_two = 0
st.title("Hello World")
async def firstWorker():
global val_one
while True:
await asyncio.sleep(r.randint(1, 3))
val_one = r.randint(1, 10)
st.metric("First Worker Executed: ",val_one)
async def secondWorker():
global val_two
while True:
await asyncio.sleep(r.randint(1, 3))
val_two = r.randint(1, 10)
st.metric("Second Worker Executed: ",val_two)
async def main():
await(asyncio.gather(
firstWorker(),
secondWorker()
)
)
if __name__ == '__main__':
with st.empty(): # Modified to use empty container
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
asyncio.run(main())
except KeyboardInterrupt:
pass
finally:
print("Closing Loop")
loop.close()
Output:
Version 2:
st.title("Hello World")
async def firstWorker():
await asyncio.sleep(r.randint(1, 3))
val_one = r.randint(1, 10)
st.metric("First Worker Executed: ", val_one)
async def secondWorker():
await asyncio.sleep(r.randint(1, 3))
val_two = r.randint(1, 10)
st.metric("Second Worker Executed: ", val_two)
async def main():
with st.empty():
while True:
left_col, right_col = st.columns(2)
with left_col:
await (asyncio.gather(firstWorker()))
with right_col:
await (asyncio.gather(secondWorker()))
if __name__ == '__main__':
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
asyncio.run(main())
except KeyboardInterrupt:
pass
finally:
print("Closing Loop")
loop.close()
Output:
I don't know why you use global variables. I got rid of them this time unless otherwise you need them.

postmessage return The data area passed to a system call is too small

i'm trying to send input to specific game using postmessage from win32api. i already try many way to do this like pynput, pyautogui, pydirectinput, direct input using ctypes all of them are not working. only this show the error message. This is the code that i using for test it:
import win32gui, win32ui, win32con, win32api
def main():
window_name = "SealOnline Plus Vibes "
hwnd = win32gui.FindWindow(None, window_name)
win = win32ui.CreateWindowFromHandle(hwnd)
win.PostMessage(win32con.WM_CHAR, ord(`A`), 0)
win.PostMessage(win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
win.PostMessage(win32con.WM_KEYUP, win32con.VK_RETURN, 0)
win.PostMessage(win32con.WM_CHAR, ord(`B`), 0)
def list_window_names():
def winEnumHandler(hwnd, ctx):
if win32gui.IsWindowVisible(hwnd):
print(hex(hwnd), `"` + win32gui.GetWindowText(hwnd) + `"`)
win32gui.EnumWindows(winEnumHandler, None)
def get_inner_windows(whndl):
def callback(hwnd, hwnds):
if win32gui.IsWindowVisible(hwnd) and win32gui.IsWindowEnabled(hwnd):
hwnds[win32gui.GetClassName(hwnd)] = hwnd
return True
hwnds = {}
win32gui.EnumChildWindows(whndl, callback, hwnds)
return hwnds
main()
and it return like this
win.PostMessage(win32con.WM_CHAR, ord(`A`), 0)
win32ui.error: CWnd::PostMessage failed - The data area passed to a system call is too small.
how do i fix it ?

discord.py not finding commands within a class

If I use .join in discord with the code below, I get the following error:
Ignoring exception in command None:
discord.ext.commands.errors.CommandNotFound: Command "join" is not found
I'm not sure how to fix this (this is turning into being part of a music bot). Here is the relevant code:
import discord
import discord.voice_client
from discord import utils
from discord.ext import commands
from discord.utils import *
import discord.utils
import lavalink
bot = commands.Bot(command_prefix= ".", intents=intents)
class MusicCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.bot.music = lavalink.Client(self.bot.user.id)
self.bot.music.add_node('localhost', 7000, 'testing', 'na' , 'music-node')
self.bot.add_listener(self.bot.music.voice_update_handler, 'on-socket-response')
self.bot.music.add_event_hook(self.track_hook)
#commands.command(name= 'Join')
async def join(self, ctx):
print("join command worked")
member = utils.find(lambda m: m.id == ctx.author.id, ctx.guild.members)
if member is not None and member.voice is not None:
vc = member.voice.channel
player = self.bot.music.player_manager.create(ctx.guild.id, endpoint= str(ctx.guild.region))
if not player.is_connected:
player.store('channel', ctx.channel.id)
await self.connect_to(ctx.guild.id, str(vc.id))
#commands.command(name= "Play")
async def play(self, ctx, *, query):
try:
player = self.bot.music.player_manager.get(ctx.guild.id)
query = f'ytsearch: {query}'
results = await player.node.get_tracks(query)
tracks = results['tracks'][0:10]
i = 0
query_result = ''
for track in tracks:
i = i + 1
query_result = query_result + f'{i}) {track["info"]["title"]} - {track["info"]["url"]}\n'
show_songs = discord.Embed(
title= None,
description= None,
colour= discord.Colour.blue()
)
show_songs.description = query_result
await ctx.channel.send(embed= show_songs)
def check(m):
return m.author.id == ctx.author.id
response = await self.bot.wait_for('message', check=check)
track = tracks[int(response.conetent)-1]
player.add(requester = ctx.author.id, track = track)
if not player.is_playing:
await player.play()
except Exception as error:
print(error)
async def track_hook(self, event):
if isinstance(event, lavalink.events.QueueEndEvent):
guild_id = int(event.player.guild.id)
await self.connect_to(guild_id, None)
async def connect_to(self, guild_id: int, channel_id: str):
ws = self.bot._connection._get_websocket(guild_id)
await ws.voice_state(str(guild_id), channel_id)
def setup(bot):
bot.add_cog(MusicCog(bot))
I've tried changing #commands.command to #bot.command, which didn't end up working, and I'm almost certain the indentation is correct throughout the code, so at this point, I'm not sure how to fix it. Any help would be appreciated!
By default, commands are case sensitive so you'd have to type .Join or .Play in order to invoke your them.
If you want your commands to be case insensitive, simply type :
bot = commands.Bot(command_prefix='.', intents=intents, case_insensitive=True)
PS : the name argument in the commands.command() decorator refers to what needs to be typed after your prefix to invoke the function.

Asychronous server hanging in python

Am currently using python asynchronous server to server some clients , the server works well at first then eventually hangs without showing if it is receiving and requests from clients, when I press ctr-c it then shows that it receives the requests from the clients and it does not stop, it just continues to revieve requests .
I don't where this bug is emanating from.
Thank u in advance
import asyncio, json
from collections import Coroutine
from typing import Any
import Engine
import struct
header_struct = struct.Struct("!Q") # messages up to 2**64 - 1 in length
async def recvall(reader, length):
blocks = []
while length:
block = await reader.read(length)
if not block:
raise EOFError('socket closed with {} bytes left in this block'.format(length))
length -= len(block)
blocks.append(block)
return b''.join(blocks)
async def get_block(reader):
data = await recvall(reader, header_struct.size)
(block_length,) = header_struct.unpack(data)
return await recvall(reader, block_length)
async def put_block(writer, message):
block_length = len(message)
writer.write(header_struct.pack(block_length))
writer.write(message)
# await writer.drain()
async def handle_conversation(reader, writer):
address__ = writer.get_extra_info("peername")
print("Accepted connection from {}".format(address__))
while True:
# ************************try to check if there data to send*********************************
try:
block = await get_block(reader)
# decode the data
data = block.decode()
decoded_data = json.loads(data)
# dont forget to make this synchronous
answer = await Engine.get_answer(decoded_data["Task"], decoded_data["content"])
# don't forget to check in there is necessary data to push and making sure data is conveyed
await put_block(writer, answer)
print(answer)
except Exception as e:
raise
if __name__ == '__main__':
address = Engine.parse_command_line("asyncio server using coroutine")
# loop = asyncio.get_event_loop()
# coro = asyncio.start_server(handle_conversation, *address)
async def main():
server = await asyncio.start_server(
handle_conversation, *address)
addr = server.sockets[0].getsockname()
print(f'Serving on {addr}')
async with server:
await server.serve_forever()
asyncio.run(main(), debug=True)
Engine Code
import argparse
import json
import time
import upload_pic_and_search
import accept_connections
import connect
import opinion_poll
import share
import zmq
from jsonrpclib import Server
context = zmq.Context()
aphorisms = {"share": share.share_,
"poll": opinion_poll.add_poll,
"add_profile_pic": upload_pic_and_search.profile_pic,
"connect": connect.connect,
"accept_connection": accept_connections.accept_connection}
def sighn_up(doc):
"""this function will connect to sighn up """
proxy = Server('http://localhost:7002')
answer = proxy.sighn_up(doc)
return answer
def Verification(doc):
"""Code verification routine"""
proxy = Server('http://localhost:7002')
answer = proxy.verify(doc)
return answer
def login(doc):
"""This function handkes authetication"""
proxy = Server('http://localhost:7002')
answer = proxy.autheticate(doc)
return answer
def post(doc):
"""connect to server that handles posts"""
proxy = Server('http://localhost:6700')
answer = proxy.post(doc)
return answer
def comment(doc):
"""connect to the server that stores comments"""
proxy = Server('http://localhost:6701')
answer = proxy.comments_(doc)
return answer
def reply(doc):
"""store the reply"""
proxy = Server('http://localhost:6702')
answer = proxy.reply(doc)
return answer
def share(doc):
"""share the post"""
proxy = Server('http://localhost:6703')
answer = proxy.share(doc)
return answer
def likes(doc):
"""connect to the likes queue"""
zcontext = zmq.Context()
osock = zcontext.socket(zmq.PUSH)
osock.connect("tcp://127.0.0.1:6704")
osock.send_json(doc)
return {"Task": "like", "like": True}
def follow(doc):
"""handles the follow coroutine"""
zcontext = zmq.Context()
osock = zcontext.socket(zmq.PUSH)
osock.connect("tcp://127.0.0.1:6705")
osock.send_json(doc)
def connect(doc):
"""connect to routine for connection"""
zcontext = zmq.Context()
osock = zcontext.socket(zmq.PUSH)
osock.connect("tcp://127.0.0.1:6706")
osock.send_json(doc)
def accept_connection(doc):
"""the queue responsible accepting connections"""
zcontext = zmq.Context()
osock = zcontext.socket(zmq.PUSH)
osock.connect("tcp://127.0.0.1:6707")
osock.send_json(doc)
def add_profile_pic(doc):
"""Add the profile pic of the user"""
proxy = Server('http://localhost:7006')
answer = proxy.profile_pic(doc)
return answer
def search(doc):
"""search the user in the database"""
proxy = Server('http://localhost:7006')
answer = proxy.search(doc)
return answer
def profile(doc):
"""search the user in the database"""
proxy = Server('http://localhost:7006')
answer = proxy.profile(doc)
return answer
async def get_answer(aphorism, content):
"""Return the response to particular question"""
# time.sleep(0.0)
# fetch responsible function
# function = aphorisms.get(aphorism, "Error:Unknown aphorism.")
function = eval(aphorism)
answer = function(content)
return send(answer)
def send(data):
"""Prepare the data to be sent via socket"""
json_data = json.dumps(data)
data_bytes = json_data.encode()
return data_bytes
def parse_command_line(description):
"""arse command line and return a socket address."""
parser = argparse.ArgumentParser(description=description)
parser.add_argument('host', help="IP or hostname")
parser.add_argument("-p", metavar='port', type=int, default=1060, help="TCP port (default 1060)")
args = parser.parse_args()
address = (args.host, args.p)
return address
def recv_untill(sock, suffix):
"""Receive bytes over socket `sock` until we receive the `suffix`."""
message = sock.recv(4096)
if not message:
raise EOFError("Socket closed")
while not message.endswith(suffix):
data = sock.recv(4096)
if not data:
raise IOError('received {!r} then socket closed'.format(message))
message += data
return message

python3 tkinter gui not reacting on execution

I'm using tkinter for my python3 GUI. The script I wrote, when executing in IDLE. But when I try to execute it without the GUI is not responding.
Here's the code:
#! python3
from tkinter import *
import tkinter as tk
class Program:
nameC = ""
master = ""
varC = ""
def callback(self):
self.nameC= filedialog.askopenfilename()
def __init__(self):
self.master = Tk()
self.varC = StringVar(self.master)
l1 = Label(text="Open file", relief=RIDGE,width=15)
l1.grid(row=0,column=0)
b1 = Button(text='Open', command=self.callback)
b1.grid(row=0,column=1)
program = Program()
mainloop()
So far I have a button and a label. If I click on the button, a filedialog is opened using the callback function
EDIT: fixed one error in the code
If it helps, I'm using windows
So after running the script in the console ( as mentioned not IDLE) I figured out that I would have to import filedialog:
#! python3
from tkinter import *
from tkinter import filedialog # this is what I needed
import tkinter as tk
class Program:
nameC = ""
master = ""
varC = ""
def callback(self):
self.nameC= filedialog.askopenfilename()
def __init__(self):
self.master = Tk()
self.varC = StringVar(self.master)
l1 = Label(text="Open file", relief=RIDGE,width=15)
l1.grid(row=0,column=0)
b1 = Button(text='Open', command=self.callback)
b1.grid(row=0,column=1)
program = Program()
mainloop()

Resources