Running raw_input on a pygtk application - python

I need to make a graphical application that reads data from the console to update some widgets, this will have to do with 2 threads, one for the GUI and one for the console. The problem is that raw_input function does not work and also freezes the application. Here is the code.
import pygtk
pygtk.require('2.0')
import gtk
import gobject
from time import sleep
import sys
import threading
class Worker (threading.Thread):
def __init__(self, app):
threading.Thread.__init__(self)
self.app = app
def run(self):
text = raw_input("Enter some text: ") #It freezes the application
#text = "Hola" #It Works
self.app.writeMessage(text, False)
class Application:
def __init__(self, title, xPos, yPos):
gtk.threads_init()
self.win = gtk.Window()
screen = self.win.get_screen()
screenW = screen.get_width()
screenH = screen.get_height()
windowW = int(screenW * 0.5)
windowH = int(screenH * 0.25)
if type(xPos) is float:
xPos = int(screenW * xPos)
if type(yPos) is float:
yPos = int(screenH * yPos)
self.messageArea = gtk.TextView()
self.scroll = gtk.ScrolledWindow()
self.scroll.add(self.messageArea)
self.win.set_size_request(windowW, windowH)
self.win.set_title(title)
self.win.add(self.scroll)
self.win.show_all()
self.win.move(xPos, yPos)
self.win.connect("destroy", gtk.mainquit)
def doOperation(self, function, *args, **kw):
def idle_func():
try:
gtk.threads_enter()
function(*args, **kw)
return False
finally:
gtk.threads_leave()
gobject.idle_add(idle_func)
def sleeper():
time.sleep(.001)
return 1 # don't forget this otherwise the timeout will be removed
def mainloop(self):
#Trick for running threads and pygtk on win32 enviroment
if sys.platform == 'win32':
gtk.timeout_add(400, self.sleeper)
gtk.threads_enter()
gtk.mainloop()
gtk.threads_leave()
def writeMessage(self, message, isMainThread):
if isMainThread:
buf = self.messageArea.get_buffer()
end_iter = buf.get_end_iter()
buf.insert(end_iter, message)
else:
self.doOperation(self.writeMessage, message, True)
if __name__ == "__main__":
app = Application("Hello", 0, 0)
worker = Worker(app)
app.doOperation(worker.start)
app.mainloop()
Curiously the code only works if you run it in eclipse pydev, but it doesn't is the intention, I must run it from console. So this is the question, how to execute raw_input function and GUI on separate threads?

take a look at this.It explains about absence of event loop support in python and you can disable pygtk event loop after importing it.

Related

Why while loop freeze api gui [duplicate]

This question already has answers here:
Equivalent to time.sleep for a PyQt application
(5 answers)
Closed 1 year ago.
I trying create GUI Api. First i build python script with only print information in console.
So I wanted to rebuild applications into applications with an interface. I decided to use PyQt5
Like this:
To(first look):
I ran into a problem with the loop While. Aplication just freeze when while is runing
I prepared a short script simulating the problem. The main program looks different
import sys
from PyQt5.QtWidgets import *
from PyQt5 import QtWidgets
from termcolor import colored
import time
class App(QMainWindow):
def __init__(self):
super().__init__()
self.title = 'API NORD'
self.left = 0
self.top = 0
self.width = 300
self.height = 200
self.setWindowTitle(self.title)
self.resize(800, 600)
self.center()
self.table_widget = MyTableWidget(self)
self.setCentralWidget(self.table_widget)
self.show()
def center(self):
# geometry of the main window
qr = self.frameGeometry()
# center point of screen
cp = QDesktopWidget().availableGeometry().center()
# move rectangle's center point to screen's center point
qr.moveCenter(cp)
# top left of rectangle becomes top left of window centering it
self.move(qr.topLeft())
class MyTableWidget(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
self.layout = QVBoxLayout(self)
self.pushButton1 = QPushButton("Run")
self.layout.addWidget(self.pushButton1)
self.pushButton1.clicked.connect(self.button2_clicked)
self.textedit = QtWidgets.QTextEdit(readOnly=True)
self.layout.addWidget(self.textedit)
self.textedit.setText("STATUS")
def onClicked(self):
radioButton = self.sender()
if radioButton.isChecked():
x=0
# print("Shop is %s" % (radioButton.shop))
self.Sklep=radioButton.shop
self.l1.setText(self.Sklep)
return
def checkBulkStatus(self):
Status = "Start"
x=0
self.textedit.setText("Start")
while x < 5:
print("Aktualny Status:", colored(Status,"yellow"))
Status="Running"
self.textedit.append(Status)
if Status=="FAILED":
print("Error")
break
time.sleep(2.5)
x+=1
print("Aktualny Status: ", colored("COMPLETED", "green"))
self.textedit.setText("COMPLETED")
def button2_clicked(self):
self.checkBulkStatus()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
In main program I ussing while to check status of BULK request in GraphQL:
def checkBulkStatus(self):
self.url = self.auth(self.Sklep)["url_auth"]
print(self.url)
Status = "Start"
self.textedit.setText("Start")
while Status != "COMPLETED":
print("Aktualny Status:", colored(Status,"yellow"))
checking = self.Core.callShopifyGraphQL(self.Core.CheckQuery,self.url)
result = checking.json()
Status=result["data"]["currentBulkOperation"]["status"]
self.textedit.append(Status)
if Status=="FAILED":
print(result["data"]["currentBulkOperation"])
break
time.sleep(2.5)
print("Aktualny Status: ", colored("COMPLETED", "green"))
URL_bulk=result["data"]["currentBulkOperation"]["url"]
The problem is that the gui runs in the same thread as the script, so when you run the script it freezes the interface. To prevent this from happening, you need to run the script in a thread, as this way you can share variables with the main thread.
I hope it helps you, greetings.

Can't invoke button click function() outside pyQT based GUI

I am trying to enhance the existing pyQT based GUI framework. The GUI is a multithread GUI based out of pyQT. I have taken some portion of it here to explain the problem
GUI.py - main python script that invokes function to create Tab on GUI
from TabWidgetClass import ConstructGUITabs
class mainWindow(QtGui.QMainWindow):
def __init__(self,**kwargs):
super().__init__()
self.dockList = []
#Lets build&run GUI
self.BuildRunGUI() ### initialize GUI
def BuildRunGUI(self):
### frame, status definition
### tab definition
self.mainWidget = QtGui.QTabWidget(self)
self.setCentralWidget(self.mainWidget)
self.GUIConnect = ConstructGUITabs(docklist=self.dockList, parent_widget=self.mainWidget,mutex=self.mutex)
self.show()
if __name__ == "__main__":
try:
mW = mainWindow()
mW.setGeometry(20, 30, 1920*0.9,1080*0.9)
mW.setTabPosition(QtCore.Qt.AllDockWidgetAreas, QtGui.QTabWidget.North)
#mW.show()
TabWidgetClass.py - Script to create tabs & widgets
from SerialInterface import SerialInterface
from BackQThread import BackQThread
class ConstructGUITabs():
def __init__():
super().__init__() #init!!
#Thread Variables
self.main_thread = None
self.background_thread = None
# Let's define each tab here
self.ADD_CALIBRATE_TAB()
############## Start of ADD_CONNECT_TAB##################################################
def ADD_CALIBRATE_TAB(self, tec_layout):
#Create threads here. Main to handle update in GUI & Background thread for few specific
#time consuming operation
self.main_thread = SerialInterface()
self.background_thread = BackQThread()
#Get button connect to get_value through main thread
self.get_button = QtGui.QLabel(self)
self.set_button = QtGui.QPushButton('Set')
self.set_button.clicked.connect(self.set_value)
#Set button connect to Set_value through background_thread
self.get_button = QtGui.QLabel(self)
self.get_button = QtGui.QPushButton('Get')
self.get_button.clicked.connect(self.get_new_value)
self.pwr_disp_val = QtGui.QLineEdit(self)
self.pwr_disp_val.setText('')
#add the layout
#connect signal for backgrund thread
self.background_thread.read_info_flash.connect(self.update_info_from_flash)
def set_value(self):
self.main_thread.setvalue()
def get_new_value(self):
self.background_thread.call_update_info_bg_thread(flag = 'ReadSignalInfo',
list=[var1, var2])
def update_info_from_flash(self,flashData):
self.pwr_disp_val.setText(flashData)
The 2 library modules SerialInterface & BackQThread are as below:
SerialInterface.py
import pyftdi.serialext
class LaserSerialInterface(object):
def __init__():
self.port = pyftdi.serialext.serial_for_url('COM1',
baudrate=9600,
timeout=120,
bytesize=8,
stopbits=1,
parity='N',
xonxoff=False,
rtscts=False)
def setValue(self, value):
self.port.write(value)
def readvalue(self,value):#nITLA
return (value * 100)
BackQThread.py
from SerialInterface import SerialInterface
class BackQThread(QtCore.QThread):
signal = QtCore.pyqtSignal(object)
read_info_flash = QtCore.pyqtSignal(object)
def __init__(self):
self.serial = SerialInterface()
def call_update_info_bg_thread(self,flag,**kwargs): #nITLA
self.flag = flag
self.kwargs = kwargs
def update_info_bg_thread(self, Signallist): #nITLA
flashData = []
for index in range(0, len(Singnallist)):
flashData.append(self.serial.readvalue(Signallist[index]))
self.read_info_flash.emit(flashData)
def run(self):
while True:
time.sleep(0.1)
if self.flag == None:
pass
elif self.flag == 'ReadSignalInfo':
self.update_info_bg_thread(Signallist = self.kwargs['Signallist'])
self.flag = False
All above interface works without issues.
The new requirement is to do automation on GUI. In such way that, execute GUI options without manually doing clicks. Script should get an access to ConstructGUITabs() class, to invoke the click events.
Here is sample test script which works fine, if I invoke click events.
GUI.py - script is modified to declare GUIConnect as global variables using 'import globfile'
from TabWidgetClass import ConstructGUITabs
import globfile
class mainWindow(QtGui.QMainWindow):
def __init__(self,**kwargs):
super().__init__()
self.dockList = []
#Lets build&run GUI
self.BuildRunGUI() ### initialize GUI
def BuildRunGUI(self):
### frame, status definition
### tab definition
self.mainWidget = QtGui.QTabWidget(self)
self.setCentralWidget(self.mainWidget)
globfile.GUIConnect = ConstructGUITabs(docklist=self.dockList, parent_widget=self.mainWidget,mutex=self.mutex)
........
Test_Script.py
import globfile
globfile.GUIConnect.get_button.click() #this invokes get_new_value
globfile.GUIConnect.set_button.click()# this set_value
As you see here, through *click() function we are again doing mouse click events. I dont want to do this.
So i tried
globfile.GUIConnect.set_value()# this set_value
# This set_Value() would work as we are using only single & main thread
globfile.GUIConnect.get_new_value() #this invokes get_new_value
# This function call wont' get completed. It would stuck at 'self.read_info_flash.emit(flashData)' in BackQThread.py script. Hence, background thread fails to run update function 'update_info_from_flash'.
Can anyone tell me, what is the wrong in invoking directly functions rather than click() events. Why multithread alone fails to complete.

Cyclic label update in Python

I'm trying to get dynamic cyclic (every half a second) label updates from a Webservice in Python where I parse a JSON string and return its contents to the GUI (made with Glade 3.8.1).
I have started from a basic example and the code I've written so far looks like this:
import sys
import json
import urllib2
import time
try:
import pygtk
pygtk.require("2.0")
except:
pass
try:
import gtk.glade
import gtk
except:
sys.exit(1)
class cRioHMI():
def on_MainWindow_destroy(self, data = None):
print "quit with cancel"
gtk.main_quit()
def on_gtk_quit_activate(self, data = None):
print "quit from menu"
gtk.main_quit()
def on_btnTest_clicked(self, widget):
print "Button Pressed"
def on_gtk_about_activate(self, data = None):
print "About Page Accessed"
self.response = self.about.run()
self.about.hide()
def __init__(self):
self.gladefile = "Assets/HMI.glade"
self.builder = gtk.Builder()
self.builder.add_from_file(self.gladefile)
self.builder.connect_signals(self)
self.window = self.builder.get_object("MainWindow")
self.about = self.builder.get_object("AboutDialogue")
self.templable = self.builder.get_object("lbl_Temperature")
self.window.show()
def update_Values(self, data = None):
response = urllib2.urlopen('http://10.10.10.11:8001/WebUI/Temperatures/GetTemperatures')
data = json.load(response)
temperature = data['Temperature2'][1]
self.templable.set_text(str(temperature))
time.sleep(.5)
if __name__ == "__main__":
HMI = cRioHMI()
gtk.main()
When I use the code from the update_Values method on a click event, the code performs as expected
def on_btnTest_clicked(self, widget):
response = urllib2.urlopen('http://10.10.10.11:8001/WebUI/Temperatures/GetTemperatures')
data = json.load(response)
temperature = data['Temperature2'][1]
self.templable.set_text(str(temperature))
time.sleep(.5)
print "Button Pressed"
but I would like to update multiple labels in a cyclic manner and still have event driven actions.
What is the best way to do that? Please note, that I'm new to python.
You can use gobject.timeout_add (see the documentation here).
So in your __init__ you would have something like gobject.timeout_add(1000, self.updateValues). If you return False the timeout will not be called again.
You should also not use time.sleep. This is a blocking call. That means your GUI will freeze as it cannot handle incoming events. The same thing will happen with the urllib2.urlopen call, if it takes too much time. To prevent this you can run updateValues in a separate Thread. Then you would have to use gobject.idle_add to set the text of the label (see documentation).
Here is a small example. It is just a counter (and would not need threading) but I marked the place where your urllib2.urlopen would go with a comment:
#!/usr/bin/env python2
from threading import Thread
from pygtk import gtk, gobject
class Window(gtk.Window):
def __init__(self):
gtk.Window.__init__(self)
self.connect('delete-event', gtk.main_quit)
self.label = gtk.Label('1')
self.add(self.label)
gobject.timeout_add_seconds(1, self.threaded)
def threaded(self):
thread = Thread(target=self.updateValues)
thread.start()
return True
def updateValues(self):
# urllib.urlopen calls
n = int(self.label.get_text())
gobject.idle_add(self.label.set_text, str(n + 1))
win = Window()
win.show_all()
gobject.threads_init()
gtk.main()

GTK::Socket and Gtk::Plug unexpected behaviour under Gnome and FVWM2

The following code works fine if run within FVWM2. But if you change desktop to Gnome, then the embedded window is destroyed instead of being embedded.
Why is that? What am I missing?...
The code follows but basically all it does is fork. In the child, we create a VPython window an let it idle forever. In the parent, we create a GTK window, find out what the window ID of the child window is, and try to embed it vis a GTK::Socket.
Note that the VPython part maybe irrelevant to this.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import subprocess
import sys
import os
import re
import time
from visual import *
def find_window_id (title):
"""Gets the OpenGL window ID."""
pattern = re.compile('0x[0-9abcdef]{7}')
proc = subprocess.Popen(['xwininfo', '-name', title],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
errors = proc.stderr.readlines()
if errors:
return None
for line in proc.stdout.readlines():
match = pattern.findall(line)
if len(match):
return long(match[0], 16)
return None
class Setting ():
"""VPython/OpenGL class."""
def __init__ (self, w=256, h=256, title='OpenGL via VPython'):
"""Initiator."""
self.width = w
self.height = h
self.title = title
self.scene = display.get_selected()
self.scene.title = self.title
self.scene.width = self.width
self.scene.height = self.height
self.sphere = sphere()
class GTKDisplay ():
def __init__ (self, winID):
"""Initiator: Draws the GTK GUI."""
import gtk
import pygtk
self.OpenGLWindowID = winID
window = gtk.Window()
window.show()
socket = gtk.Socket()
socket.show()
window.add(socket)
window.connect("destroy", lambda w: gtk.main_quit())
socket.add_id(long(self.OpenGLWindowID))
gtk.main()
def main ():
"""Main entry point."""
name = 'sphere OpenGL window'
child_pid = os.fork()
if 0 == child_pid:
sut = Setting(title=name)
else:
winID = None
while not winID:
time.sleep(.1)
winID = find_window_id(name)
try:
gui = GTKDisplay(winID)
except KeyboardInterrupt, err:
print '\nAdieu monde cruel!'
if __name__ == "__main__":
main()
PS: Yes, this is a follow up from this question.

GTK window capture: VPython (OpenGL) application

Having read the documentation for VPython and GTK threading, it seems to me that it would be possible to embed VPython graphics within a gtk GUI. I know that it is possible with wx on Windows but I am on Linux and using PyGTK. Now, I have managed to get part of the way. I can embed a VPython window provided that it is spawned a separate process. What I would like is to embed it as a thread. The latter would make GUI events that control the OpenGL easier to implement -- via a thread instead of a socket and network calls.
Edit: Apparently nobody knows anything about this... Meh.
Here is the code I have. Uncomment the two commented out lines and comment a few obvious others and you can get to the process spawning code.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
from visual import *
import threading
import Queue
import gtk
import pygtk
import re
import subprocess
class OPenGLThreadClass (threading.Thread):
"""Thread running the VPython code."""
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
self.name = 'OpenGLThread'
def run (self):
gtk.threads_enter()
self.scene = display.get_selected()
self.scene.title = 'OpenGL test'
s = sphere()
gtk.threads_leave()
#P = subprocess.Popen(['python', 'opengl.py'])
time.sleep(2)
self.queue.put(self.find_window_id())
self.queue.task_done()
def find_window_id (self):
"""Gets the OpenGL window ID."""
pattern = re.compile('0x[0-9abcdef]{7}')
P = subprocess.Popen(['xwininfo', '-name', self.scene.title],
#P = subprocess.Popen(['xwininfo', '-name', 'Visual WeldHead'],
stdout=subprocess.PIPE)
for line in P.stdout.readlines():
match = pattern.findall(line)
if len(match):
ret = long(match[0], 16)
print("OpenGL window id is %d (%s)" % (ret, hex(ret)))
return ret
class GTKWindowThreadClass (threading.Thread):
"""Thread running the GTK code."""
def __init__ (self, winID):
threading.Thread.__init__(self)
self.OpenGLWindowID = winID
self.name = 'GTKThread'
def run (self):
"""Draw the GTK GUI."""
gtk.threads_enter()
window = gtk.Window()
window.show()
socket = gtk.Socket()
socket.show()
window.add(socket)
window.connect("destroy", lambda w: gtk.main_quit())
print("Got winID as %d (%s)" % (self.OpenGLWindowID, hex(self.OpenGLWindowID)))
socket.add_id(long(self.OpenGLWindowID))
gtk.main()
gtk.threads_leave()
def main ():
thread = {}
print("Embedding OpenGL/VPython into GTK GUI")
queue = Queue.Queue()
thread['OpenGL'] = OPenGLThreadClass(queue)
thread['OpenGL'].start()
winID = queue.get()
print("Got winID as %d (%s)" % (winID, hex(winID)))
gtk.gdk.threads_init()
thread['GTK'] = GTKWindowThreadClass(winID)
thread['GTK'].start()
if __name__ == "__main__":
main()
This is the code that works in case anyone cares.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import subprocess
import sys
import os
import re
import time
from visual import *
def find_window_id (title):
"""Gets the OpenGL window ID."""
pattern = re.compile('0x[0-9abcdef]{7}')
proc = subprocess.Popen(['xwininfo', '-name', title],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
errors = proc.stderr.readlines()
if errors:
return None
for line in proc.stdout.readlines():
match = pattern.findall(line)
if len(match):
return long(match[0], 16)
return None
class Setting ():
"""VPython/OpenGL class."""
def __init__ (self, w=256, h=256, title='OpenGL via VPython'):
"""Initiator."""
self.width = w
self.height = h
self.title = title
self.scene = display.get_selected()
self.scene.title = self.title
self.scene.width = self.width
self.scene.height = self.height
self.sphere = sphere()
class GTKDisplay ():
def __init__ (self, winID):
"""Initiator: Draws the GTK GUI."""
import gtk
import pygtk
self.OpenGLWindowID = winID
window = gtk.Window()
window.show()
socket = gtk.Socket()
socket.show()
window.add(socket)
window.connect("destroy", lambda w: gtk.main_quit())
socket.add_id(long(self.OpenGLWindowID))
gtk.main()
def main ():
"""Main entry point."""
name = 'sphere OpenGL window'
child_pid = os.fork()
if 0 == child_pid:
sut = Setting(title=name)
else:
winID = None
while not winID:
time.sleep(.1)
winID = find_window_id(name)
try:
gui = GTKDisplay(winID)
except KeyboardInterrupt, err:
print '\nAdieu monde cruel!'
if __name__ == "__main__":
main()
Note: This does not work under Gnome but works under fvwm2. Go figure...

Categories

Resources