PySide QTextEdit or QPlainTextEdit update faster? - python

I am now trying to make a GUI on my PC communicate with a Server per sockets.
here is part of the code of GUI:
def listenToServer(self):
""" keep listening to the server until receiving 'All Contracts Finished' """
self.feedbackWindow.appendPlainText('--Executing the Contracts, Listening to Server--')
contentsListend = ''
while contentsListend != 'All Contracts Finished':
#keep listen from the socket
contentsListend = self.skt.recv(1024)
#make the GUI show the text
self.feedbackWindow.appendPlainText(contentsListend)
On the Other side, the server will send data one by one but with some interval. Here is the test code simulating the server:
for i in range(7):
print 'send back msg, round: ', i # this will be printed on the screen of the server, to let me know that the server works
time.sleep(1) # make some interval
# c is the connected socket, which can send messages
# just send the current loop number
c.send('send back msg' + str(i))
c.send('All Contracts Finished')
c.close()# Close the connection
Now, everything works except the problem that, the GUI will only show the received messages after the whole for loop in the server.
Once I run the server and the GUI. The server side print the messages onto the screen with correct speed one by one, but the GUI has no response, it does not update. Till the end of the program, all the 7 lines occurs all at once at GUI side. I want them to appear one by one, so that later I can inspect the state of the server with this GUI on my PC.
Can anybody help, thanks a lot!

This has nothing to do with "fast" or "slow".
The GUI runs on the same thread as your listenToServer method - so as long as it's running nothing can happen on the GUI thread. You'll notice that you can't move, resize or click anything in the GUI while you're waiting socket input.
You'll have to run your listenToServer method on a thread separate from the GUI. The proper way to do that would be to implement a Worker object that receives data from the socket and notifies you textEdit via a Signal->Slot connection that there's data ready to receive.
I answered a similar question a while back, that might help
https://stackoverflow.com/a/24821300/2319400
A really quick and dirty alternative would be to process all queued events when you've appended new data, via:
QApplication.processEvents()
This gives Qt time to e.g. repaint the GUI on the screen with new text.
Your GUI will however not respond to any events while python is waiting for data to come from the socket!

Related

How to apply safe multi-threading in tkinter?

I have a system that is connected with multiple hardware devices(cameras, router, sensors etc.). So I thought about having a separate GUI that pings the IP addresses of these devices almost every second in order to check whenever a device gets disconnected, and I need to ping them all together.
This is the ping script:
def testRouter(self):
response = os.popen(f"ping {self.router_ip} {self.count} 1").read()
if "Received = 1" in response:
self.router_status.configure(image=self.connected)
self.router_button.configure(command=self.clickedNone)
else:
self.router_status.configure(image=self.disconnected)
self.router_button.configure(command=self.clickedRouter)
self.root.after(5000, self.testRouter)
But the GUI freezes for more than a minute till it displays the content, and many other times it just freezes forever. So I tried to implement a thread for each ping but I came across the fact that tkinter is not a thread-safe library with an error RuntimeError: main thread is not in main loop
Any idea on how to implement this? (without using mtTkinter please)

Python Sockets Select is hanging - Doing other tasks while waiting for socket data?

I am rather a noob here, but trying to setup a script where I can poll a socket, and when no socket data has been sent, a loop continues to run and do other things. I have been playing with several examples I found using select(), but no matter how I organize the code, it seems to stop on or near the server.recv() line and wait for a response. I want to skip out of this if no data has been sent by a client, or if no client connection exists.
Note that this application does not require the server script to send any reply data, if it makes any difference.
The actual application is to run a loop and animate some LEDs (which needs root access to the I/O on a Raspberry Pi). I am going to send this script data from another separate script via sockets that will pass in control parameters for the animations. This way the external script does not require root access.
So far the sending and receiving of data works great, I just can't get loop to keep spinning in the absence of incoming data. It is my understanding that this is what select() was intended to allow, but the examples I've found don't seem to be working that way.
I have attempted adding server.setblocking(0) a few different places to no avail. (If I understand correctly a non-blocking instance should allow the code to skip over the recv() if no data has been sent, but I may be off on this).
I have based my code on an example here:
http://ilab.cs.byu.edu/python/select/echoserver.html
Here is the server side script followed by the client side script.
Server Code: sockselectserver.py
#!/usr/bin/env python
import select
import socket
import sys
server = socket.socket()
host = socket.gethostname()
port = 20568
size = 1024
server.bind((host,port))
server.listen(5)
input = [server,sys.stdin]
running = 1
while running:
inputready,outputready,exceptready = select.select(input,[],[])
for s in inputready:
if s == server:
# handle the server socket
client, address = server.accept()
input.append(client)
elif s == sys.stdin:
# handle standard input
junk = sys.stdin.readline()
running = 0
else:
# handle all other sockets
data = s.recv(size)
if data:
s.send(data)
else:
s.close()
input.remove(s)
print "looping"
server.close()
Client Code: skclient.py
#!/usr/bin/python # This is client.py file
import socket # Import socket module
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
port = 20568 # Reserve a port for your service.
s.connect((host, port))
data = "123:120:230:51:210:120:55:12:35:24"
s.send(data)
print s.recv(1024)
s.close # Close the socket when done
What I would like to achieve by this example is to see "looping" repeated forever, then when the client script sends data, see that data print, then see the "looping" resume printing over and over. That would tell me it's doing what is intended I can take it from there.
Interesting enough, when I test this as is, whenever I run the client, I see "looping" printed 3 times on the screen, then no more. I don't fully understand what is happening inside the select, but I'd assume it would only print 1 time.
I tried moving the inputready.. select.select() around to different places but found it appears to need to be called each time, otherwise the server stops responding (for example if it is called once prior to the endless while: loop).
I'm hoping this can be made simple enough that it can be taught to other hacker types in a maker class, so I'm hopeful I don't need to get too crazy with multi-threading and more elaborate solutions. As a last resort I'm considering logging all my parameters to mySQL from the external script then using this script to query them back out of tables. I've got experience there and would probably work, but it seems this socket angle would be a more direct solution.
Any help very much appreciated.
Great news. This was an easy fix, wanted to post in case anyone else needed it. The suggestion from acw1668 above got me going.
Simply added a timeout of "0" to the select.select() like this:
inputready,outputready,exceptready = select.select(input,[],[],0)
This is in the python docs but somehow I missed it. Link here: https://docs.python.org/2/library/select.html
Per the docs:
The optional timeout argument specifies a time-out as a floating point number in seconds. When the timeout argument is omitted the function blocks until at least one file descriptor is ready. A time-out value of zero specifies a poll and never blocks.
I tested the same code as above, adding a delay of 5 seconds using time.sleep(5) right after the print "looping" line. With the delay, if no data or client is present the code just loops every 5 seconds and prints "looping" to the screen. If I kick off the client script during the 5 second delay, it pauses and the message is processed the next time the 5 second delay ends. Occasionally it doesn't respond the very next loop, but rather the loop following. I assume this is because the first time through the server.accept is running and the next time through the s.recv() is running which actually exchanges the data.

2 Threads, Irc connection on second thread, want first thread to tell thread to send a message

So I am writting a irc chat bot with a pygtk gui. This bot has its gui running on a loop in the main script. When I press a button on the gui it starts a thread wich opens a socket and connect to a irc channel, when I press it again it pauses the thread, and when I press it yet again it resumes the thread.
Until here all good.
But I want it to when I press a button in the gui (main loop) to read a text box and tell the thread to send the text trough the irc connection.
My problem is I can't get the main loop to tell the thread to send the text. I tried something like(to test it out):
def botSendMessage(button):
thread.sendMessage(irc, "test")
handlers = {
"on_bot_send_button_clicked": botSendMessage,
}
builder.connect_signals(handlers)
I was alredy able to achieve what I was looking for. I used global variables.
I would suggest using a Queue object that is available in both threads (passed in at creation time) to pass messages between them.
In the main loop of the irc thread, do a nonblocking check for items in the queue that need to be sent.

Control python program with django

Hej,
I have written a little music player like winamp in python. It has a GUI (Songname, Play/Pause, Next, Previous, time progress bar), I can open a folder and the audio files are played one after the other.
Now I really like to add a remote control through a webserver hosted on the same machine. My idea is to have the same buttons and outputs (also a time progress bar) as in the GUI on a webpage.
Scenario: I start my music player on my computer (it also automatically starts a webserver), I choose my folder with songs and skip two songs by clicking on the GUI on my desktop. Now I decide to sit on the couch and read a book. After a while the music annoys me and I want to pause it. I grab my phone, visit the webpage and tap on the pause button. The music stops and also the desktop GUI reacts (stops the time progress bar and displays the play button instead of the pause button).
I know how to create a django server and how to run it, but I do not know how to let the django views communicate with my music player on my desktop.
I have googled and read some stuff but I have no idea which way to go:
signals: don't know if this makes any sense since the two processes are totally detached
communicate over a database, save the state of the music player in a database row and let both processes update the entry whenever a button is pressed: don't like this idea because I'd like the two processes to commuicate without interpreter
maybe use UDP/TCP: but why, the processes are on the same machine
If I had to program it right now, I'd choose the database approach or is there any other solution I haven't stumbled upon yet? Shall I use flask instead of django?
If this is a common question and task, I am sorry for repeating, but I just could not find anything stating how to solve this.
What you are looking for is IPC (inter process communication). My instinct would be to have the music player open a socket, bind to a port, and to listen for commands.
Then in the Django view you open a socket connection to the player, send the command and return a response to the browser.
I you want full two way communication to the browser then you would need to also have a process waiting for output from the music player and sending it back to the browser via a web socket connection. The standard socket tutorial is very handy.

Tkinter wait for tcp input/output

I wrote a networked chatroom server and client and it works in a simple Terminal environment just fin, and just today started to translate it to over to a GUI form using Tkinter. The sending of messages is fine as I can handle them with button press event handlers and key handles, but the problem is receiving messages. I need to be able to check to see if data has been received while still in the Tkinter window. Is there a nice way of doing something like this? I've tried checking every second using the root.action(time,event) call, but that didn't seem to work, and have just tried running loops in different spots (against my better judgement).
What can I do to have Tkinter listen to something outside of itself, but still be listening to the events going on within my Tkinter window?
See
How do you run your own code alongside Tkinter's event loop?
In particular, the comment about setting the timeout to 0 in the Tk().after() call, so you have non-blocking, outside the Tk event loop code handling possibilities.
Hope that helps.

Categories

Resources