Creating Toplevel after receiveing some input on socket - python

I'm using this forum for some time, but first time asking question.
I have problem with one tkinter application. It's simple chat server - client program, where chat is something like Skype. I have a friend list, and when I select friend from list, click chat, new window (toplevel) opens. Then I can send messages to friend.
Problem is on the other side. It's working fine if chat window is opened on the other side, but if it's not, I'm trying to create in by calling function that creates new toplevel. And here program freezes (on the side of friend).
def bChatPress(self, event=None):
def closeChatClient():
chatClient.destroy()
del self.chatClients[friend]
if self.friend=='':
index = self.lbFriends.curselection()
if index:
friend = self.lbFriends.get(index)
if friend not in self.chatClients:
chatClient=ChatClient(self, self.user, friend)
chatClient.protocol("WM_DELETE_WINDOW", closeChatClient)
self.chatClients[friend] = chatClient
else:
chatClient=ChatClient(self, self.user, self.friend)
chatClient.protocol("WM_DELETE_WINDOW", closeChatClient)
self.chatClients[self.friend] = chatClient
self.friend=''
def receiveMessage(self):
def loop():
print('threadstart')
while self.loged:
try:
message = self.socket.recv(1024).decode('ascii')
print(message)
if '{LOGIN}' in message:
threading.Thread(target=self.login).start()
elif '{LOGOUT}' in message:
pass
elif '{CONNECT}' in message:
self.connect(message.replace('{CONNECT}',''))
elif '{DISCONNECT}' in message:
self.disconnect()
elif '{ADD FRIEND}' in message:
self.populateFriendsList(message.replace('{ADD FRIEND}',''))
elif '{DELETE FRIEND}' in message:
self.populateFriendsList(message.replace('{DELETE FRIEND}',''))
elif '{USER CONNECT}' in message:
self.checkOnline()
elif '{USER DISCONNECT}' in message:
self.checkOnline()
elif '{CHECK ONLINE}' in message:
self.populateFriendsList(message.replace('{CHECK ONLINE}',''))
elif '{MESSAGE}' in message:
self.processMessage(message.replace('{MESSAGE}',''))
except Exception as error:
pass
threading.Thread(target=loop).start()
This is function for creating chat window. It's working fine when I create window by clicking the button, but it's not working when I call this function from receiveMessage function (this is loop for listening socket)
Did anybody had this problem before?
Thanks in advance.

You cannot call tkinter functions or widget methods from any thread except the one that created the root window.

Related

pylutron_caseta help please with Lutron buttons

I'm using the pylutron_caseta python package for use with Lutron devices. At this stage I'm trying to listen for button presses. I'm able to pair with the bridge and get the buttons, but I'm unable to listen for button presses. Here's my code:
import asyncio
from pylutron_caseta.smartbridge import Smartbridge
from pylutron_caseta.pairing import async_pair
from os.path import exists
bridgeIp = "192.168.1.40"
async def pair(host: str):
def _ready():
print("Press the small black button on the back of the bridge.")
data = await async_pair(host, _ready)
with open("caseta-bridge.crt", "w") as cacert:
cacert.write(data["ca"])
with open("caseta.crt", "w") as cert:
cert.write(data["cert"])
with open("caseta.key", "w") as key:
key.write(data["key"])
print(f"Successfully paired with {data['version']}")
async def registerButton(bridge,button_id):
print("Press the small button on the button device.")
def printThis(x):
print(x)
async def connect():
bridge = Smartbridge.create_tls(bridgeIp, "caseta.key", "caseta.crt", "caseta-bridge.crt")
await bridge.connect()
buttons = bridge.get_buttons()
print (buttons)
for b in buttons:
print (b)
loopListen = asyncio.get_event_loop()
asyncio.ensure_future(listen(bridge,int(b)))
loopListen.run_forever()
async def listen(bridge,_buttonID):
while True:
bridge.add_button_subscriber(str(_buttonID), printThis)
#Program
if exists("caseta-bridge.crt"):
print("found pair files")
loop = asyncio.get_event_loop()
loop.run_until_complete(connect())
else:
loop = asyncio.get_event_loop()
loop.run_until_complete(pair(bridgeIp))
loop = asyncio.get_event_loop()
loop.run_until_complete(connect())
I expect that when I press a button on the Lutron Pico remote that I get some sort of response printed. I get nothing printed. I'm guessing I have the "listen" function incorrect, just not sure how.
Any help is appreciated!
I was able to make my Lutron Pico remotes work with a node js module called lutronpro found here: https://www.npmjs.com/package/lutronpro.
I had to upgrade to the pro lutron controller module to make it work. I would prefer to do this in Python, but at least I could get this to work, and know when a remote button was pressed and from there I could call a python web service to do the rest. I ultimately just made it start up this program on boot on my raspberry pi, and now I use my pico remote to control almost anything in the hous

Handling pyTelegramBotAPI floating keyboard value

I'm new on making Telegram chatbot using pyTelegramBotAPI. In this case, i have multiple choices, the 'Trapezoid' and 'Simpson'. Here is the following code
#bot.message_handler(commands=['calculate'])
def welcome(message):
print(message)
markup = types.ReplyKeyboardMarkup(one_time_keyboard=True)
markup.add('Trapezoid', 'Simpson')
reply = bot.reply_to(message, "Select computation method" ,reply_markup=markup)
if(reply.text == 'Trapezoid'):
bot.register_next_step_handler(reply, trapezoid_handler)
elif(reply.text == 'Simpson'):
bot.register_next_step_handler(reply, simpson_handler)
def trapezoid_handler(message):
bot.send_message(message.id, "Trapezoid Block")
def simpson_handler(message):
bot.send_message(message.id, "Simpson Block")
Here is a picture when i run the /calculate command
Here is picture when i press the 'Trapezoid' button
As you can see, when i press the 'Trapezoid' button, the trapezoid_handler was not executed.
The goal is, when i press either 'Trapezoid' or 'Simpson' button, it later move to the following button value. Am i access the floating keyboard value correctly? How do i access the floating keyboard value?
Thank you for your respond
Here, it returns reply text (i.e "Select computation method") So you're not getting actual value when you click buttons.
Fixed Code :
#bot.message_handler(commands=['caluculate'])
def welcome(message):
print(message)
markup = types.ReplyKeyboardMarkup(one_time_keyboard=True)
markup.add('Trapezoid', 'Simpson')
reply = bot.reply_to(message, "Select computation method" ,reply_markup=markup)
bot.register_next_step_handler(reply, markup_handler)
def markup_handler(message):
if(message.text == 'Trapezoid'):
bot.send_message(message.chat.id, "Trapezoid Block")
elif(message.text == 'Simpson'):
bot.send_message(message.chat.id, "Simpson Block")

How to terminate main program when thread ends? Still getting waiting for process to detach in python?

I am having a main program which is defined like this:
main.py
def main():
try:
registry.start_server()
except:
print("Shutting down the program")
pass
if __name__ == '__main__':
main()
registry.start_server() is the method in another module which looks like this:
def start_server():
t_server = threading.Thread(target=server.start)
t_server.start()
try:
t_server.join()
except KeyboardInterrupt:
print("Error")
raise ValueError
finally:
fp.close()
server.start is the method in another module which does some listening work in a while(True) manner. I am not sure how to stop the whole program when clicking Stop in PyCharm which is Ctrl + C (Signal). I tried with Event but without success. I get to the main.py by raising an exception when the signal gets caught but that does not terminate the whole program. It shows Waiting for program to detach. The only way is to use SIGKILL. I don't understand where does the program keeps hanging? I have also tried calling sys.exit(0) when the signal gets caught and creating the thread as Deamon but that didnt help either.
EDIT
While True method in another module
def start(self, event):
try:
while True:
if event.is_set():
if self.pubsub.channels:
print("It enters here")
message = self.pubsub.get_message(True)
if message:
.
.
.
else:
return
To solve the problem, all you need to do is:
let the child-thread exit, and
let main thread join the child-thread.

I can't get my error message box to work in pyqt

In my init function, i've defined an error message box like this:
self.error_msg = QtGui.QMessageBox()
self.error_msg.setIcon(QtGui.QMessageBox.critical)
self.error_msg.setWindowTitle("Error")
self.error_msg.setDetailedText("")
on a different method, I try to call the message box like this, by setting the error text:
def detectRoot(self):
euid = os.geteuid()
if euid != 0:
print "need to be root to run this program"
self.logger.error("Not root, program exited")
self.error_msg.setText("You need to be root to run this program")
self.error_msg.exec_()
exit(1)
However, I keep getting message a pyqt/python error:
self.error_msg.setIcon(QtGui.QMessageBox.critical)
TypeError: QMessageBox.setIcon(QMessageBox.Icon): argument 1 has unexpected type 'builtin_function_or_method'
According to the documentation:
QMessageBox::NoIcon: The message box does not have any icon.
QMessageBox::Question: An icon indicating that the message is asking a question.
QMessageBox::Information: An icon indicating that the message is nothing out of the ordinary.
QMessageBox::Warning: An icon indicating that the message is a warning, but can be dealt with.
QMessageBox::Critical: An icon indicating that the message represents a critical problem.
Change QtGui.QMessageBox.critical to QtGui.QMessageBox.Critical

Is there a way to destroy the tkinter messagebox without clicking OK?

I know you can use something like,
self.root.after(1000, self.update_clock)
But could I some how replace that second function with a function that's similar to messagebox.showinfo.destroy()? I'm basically trying to put these message boxes on a timer so that the user will see them but won't have to do anything themselves.
response = tkinter.messagebox.showinfo("Warning!", "New artist object has been created: "
+ "\n" + "$oid: " + str(self.artistObjectId))
if response == "ok":
self.currentState += 1
self.states[self.currentState](importedTracks[self.currentTrack])
Maybe a message box is not what you require in this context. If you would just like to show a message then have it automatically disappear you could use a new TopLevel or frame and then destroy the frame after a timeout. In terms of user interaction and experience, message boxes are designed to wait for user input?
This is a good example of using a new TopLevel
closing tkmessagebox after some time in python
I found this page that describes what can be done to customise message boxes, though what I could find is somewhat limited.
http://effbot.org/tkinterbook/tkinter-standard-dialogs.htm
The small function below will do the job. By setting the type you can choose for: info, warning or error message box, the default is 'Info'. You can set also the timeout, the default is 2.5 seconds.
def showMessage(message, type='info', timeout=2500):
import tkinter as tk
from tkinter import messagebox as msgb
root = tk.Tk()
root.withdraw()
try:
root.after(timeout, root.destroy)
if type == 'info':
msgb.showinfo('Info', message, master=root)
elif type == 'warning':
msgb.showwarning('Warning', message, master=root)
elif type == 'error':
msgb.showerror('Error', message, master=root)
except:
pass
Call the function as follow:
For message type 'Info' and timeout of 2.5 seconds:
showMessage('Your message')
Or by your own settings for type message 'Error' and timeout 4 seconds:
showMessage('Your message', type='error', timeout=4000)

Categories