Monitor mouse coordinates in real-time in Linux - python

I need a python coding to monitor mouse coordinates in real-time in Linux. I found below coding and it works well, but the mouse coordinates information will be shown in a pops up GUI window. Now I don't need it show in a GUI window, just need save the mouse coordinates information to a text file(Log file). Does anyone can help me that? Thanks! Plus, it would be great if it can save mouse coordinates information by hourly.
#!/usr/bin/env python
"""
Corrected, the thread stops now.
"""
import sys
import os
from time import sleep
import gtk
gtk.gdk.threads_init()
import threading
# uses the package python-xlib
# from http://snipplr.com/view/19188/mouseposition-on-linux-via-xlib/
# or: sudo apt-get install python-xlib
from Xlib import display
old_stdout = sys.stdout
sys.stdout = open(os.devnull, 'w')
def mousepos():
"""mousepos() --> (x, y) get the mouse coordinates on the screen (linux, Xlib)."""
data = display.Display().screen().root.query_pointer()._data
return data["root_x"], data["root_y"]
class MouseThread(threading.Thread):
def __init__(self, parent, label):
threading.Thread.__init__(self)
self.label = label
self.killed = False
def run(self):
try:
while True:
if self.stopped():
break
text = "{0}".format(mousepos())
self.label.set_text(text)
sleep(0.01)
except (KeyboardInterrupt, SystemExit):
sys.exit()
def kill(self):
self.killed = True
def stopped(self):
return self.killed
class PyApp(gtk.Window):
def __init__(self):
super(PyApp, self).__init__()
self.set_title("Mouse coordinates 0.1")
self.set_size_request(250, 50)
self.set_position(gtk.WIN_POS_CENTER)
self.connect("destroy", self.quit)
label = gtk.Label()
self.mouseThread = MouseThread(self, label)
self.mouseThread.start()
fixed = gtk.Fixed()
fixed.put(label, 10, 10)
self.add(fixed)
self.show_all()
def quit(self, widget):
self.mouseThread.kill()
gtk.main_quit()
if __name__ == '__main__':
app = PyApp()
gtk.main()

Going over the code you provide. The information you want comes from def mousepos(). So with just
from Xlib import display
data = display.Display().screen().root.query_pointer()._data
data["root_x"], data["root_y"]
You get the current mouse position, put this in a loop and write/append to a file.
That should do the trick.

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.

How can I detect when one window occludes another in PyQt5?

I'm using PyQt5 to create an app with multiple main windows. I want to be able to allow the user to save and load window sizes and window positions. That's easy with, e.g., QMainWindow.saveGeometry() and QMainWindow.loadGeometry() or the corresponding .saveState() and .loadState() variants. These work great for position and size, but if the user moves or resizes one window so that it occludes another, I want to also restore this positioning. I don't mind writing my own code to save the info for each window, but I can't see any way to detect the relative Z order of windows. Am I missing it in the docs, or is this not possible?
To see what I mean, try this:
from PyQt5.QtWidgets import QApplication, QMainWindow, QPlainTextEdit
from PyQt5.QtCore import QSettings
from PyQt5.QtGui import QCloseEvent
'''
context: Linux Mint 19.3 Tricia x86_64
Python 3.9
PyQt5 5.15.1
'''
class RememberWin(QMainWindow):
def __init__(self, win_name: str):
super(RememberWin, self).__init__()
self.win_name = win_name
self.setWindowTitle(win_name)
self.can_close = False
def restore_window(self) -> bool:
try:
settings = QSettings("PyQtExamples", "RememberWinTest")
self.restoreGeometry(settings.value(f'{self.win_name} Geometry'))
self.restoreState(settings.value(f'{self.win_name} State'))
return True
except:
return False
def closeEvent(self, event: QCloseEvent):
if not self.can_close:
event.ignore()
else:
settings = QSettings("PyQtExamples", "RememberWinTest")
settings.setValue(f'{self.win_name} Geometry', self.saveGeometry())
settings.setValue(f'{self.win_name} State', self.saveState())
QMainWindow.closeEvent(self, event)
class ControlWindow(RememberWin):
def __init__(self, win_name: str = "ControlWindow"):
super(ControlWindow, self).__init__(win_name=win_name)
self.can_close = True
self.window1 = RememberWin(win_name='WindowOne')
self.window2 = RememberWin(win_name='WindowTwo')
self.text = QPlainTextEdit(self)
s = "Try making Window1 wide enough to cover Window2.\n" \
"Then close this window (auto closes others).\n" \
"Re-run the app and you'll notice that Window2\n" \
"is not on top of Window1 which means that this\n" \
"info isn't getting saved."
self.text.setPlainText(s)
self.setCentralWidget(self.text)
if not self.restore_window():
self.setGeometry(100, 390, 512, 100)
if not self.window1.restore_window():
self.window1.setGeometry(100, 100, 512, 384)
if not self.window2.restore_window():
self.window2.setGeometry(622, 100, 512, 384)
self.window1.show()
self.window2.show()
def closeEvent(self, event: QCloseEvent):
for win in (self.window1, self.window2):
win.can_close = True
win.close()
super(ControlWindow, self).closeEvent(event)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = ControlWindow(win_name='ControlWindow (You can only close this one)')
window.show()
sys.exit(app.exec_())
The simplest way to do what you want to achieve is to keep track of the current focused widget, or, to be precise, the top level window of the last focused widget.
You can store the focused windows in the settings as a list, using a unique objectName for each window (you are already doing this, so you just need to use setObjectName()), then restore the window by showing them in the correct order as long as the object name matches.
class RememberWin(QMainWindow):
def __init__(self, win_name: str):
super(RememberWin, self).__init__()
self.win_name = win_name
self.setObjectName(win_name)
self.setWindowTitle(win_name)
self.can_close = False
# ...
class ControlWindow(RememberWin):
def __init__(self, win_name: str = "ControlWindow"):
# ...
self.settings = QSettings("PyQtExamples", "RememberWinTest")
self.zOrder = []
QApplication.instance().focusObjectChanged.connect(self.focusChanged)
windowOrder = self.settings.value('windowOrder', type='QStringList')
topLevelWindows = QApplication.topLevelWidgets()
if windowOrder:
for objName in windowOrder:
for win in topLevelWindows:
if win.objectName() == objName:
win.show()
else:
self.window1.show()
self.window2.show()
def focusChanged(self, obj):
if not obj or obj.window() == self.window():
return
if obj.window() in self.zOrder[:-1]:
self.zOrder.remove(obj.window())
self.zOrder.append(obj.window())
def closeEvent(self, event: QCloseEvent):
for win in (self.window1, self.window2):
win.can_close = True
win.close()
self.settings.setValue('windowOrder',
[w.window().objectName() for w in self.zOrder])
super(ControlWindow, self).closeEvent(event)

Running raw_input on a pygtk application

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.

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()

PyGTK leave-notify-event shouldn't be triggered if enter children

Please see this code example:
import gtk
class MenuBox(gtk.EventBox):
def __init__(self):
super(MenuBox, self).__init__()
self.set_visible_window(False)
self.connect('enter-notify-event', self._on_mouse_enter)
self.connect('leave-notify-event', self._on_mouse_leave)
btn = gtk.Button('x')
btn.set_border_width(12)
self.add(btn)
def _on_mouse_enter(self, wid, event):
print '_on_mouse_enter'
def _on_mouse_leave(self, *args):
print '_on_mouse_leave'
def main():
win = gtk.Window()
win.connect('destroy', gtk.main_quit)
win.add(MenuBox())
win.show_all()
gtk.main()
if __name__ == '__main__':
main()
I want that the enter and leave events are not triggered if I am going from parent to child and back. I know that in this particular case I can filter these events with event.detail. But this does not work if there is no border. If I remove the border the events aren't triggered at all.
In my real code I have a more complex widget (based on gtk.Fixed) which has border at the beginning but not at the end. So just moving the event to the child wouldn't do the trick either.
# self.set_visible_window(False)
self.connect('enter-notify-event', self._on_mouse_enter)
self.connect('leave-notify-event', self._on_mouse_leave)
btn = gtk.Button('x')
# btn.set_border_width(12)
Is that what you need?

Categories

Resources