Get notified on clipboard change via D-Bus - python

Is there a way to get notified of clipboard change in KDE/GNOME via D-Bus? How can I capture/eavesdrop/subscribe to clipboard selection (esp. in PyGTK)? I have gtk.Clipboard.wait_for_text() method available but it returns clipboard contents immediately while I need to invoke it only when clipboard changes.

Got that pretty much here: python and gtk3 clipboard onChange
The core of the problem is:
self.clipboard = gtk.Clipboard()
self.clipboard.connect("owner-change", self.renderText)
It's black magic to me where this owner-change signal came from or how to find what signal is responsible for particular event (understood as gui phenomena) but it works:
#!/usr/bin/env python
import gtk, glib
class ClipboardParse:
def __init__(self):
window = gtk.Window()
window.set_title("example")
window.resize(600,400)
box = gtk.HBox(homogeneous = True, spacing = 2)
self.buf = gtk.TextBuffer()
textInput = gtk.TextView(self.buf)
self.lbl = gtk.Label()
box.add(self.lbl)
window.add(box)
window.connect("destroy", gtk.main_quit)
window.show_all()
self.clipboard = gtk.Clipboard()
self.clipboard.connect("owner-change", self.renderText)
def renderText(self, clipboard, event):
print 'C {0} | E {1}'.format(clipboard, event)
txt = self.clipboard.wait_for_text()
self.lbl.set_text(txt)
print txt
return False
if __name__ == '__main__':
ClipboardParse()
gtk.main()

Related

How to show My Labels and activate respective Shortcut in Pyqt5?

Here is my code, How to show My Labels and activate respective QShortcut?. Want to show my labels(both instances) and assign respective shortcut keys to labels and activate it.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class Create_workingDict(QWidget):
def __init__(self,lblname,lblscut):
super(). __init__()
self.lblname = lblname
self.lblscut = lblscut
lbl_1 = QLabel()
lbl_1.setText(self.lblname)
lbl_2 = QLabel()
lbl_2.setText(self.lblscut)
vbox = QVBoxLayout()
vbox.addWidget(lbl_1)
vbox.addWidget(lbl_2)
self.setLayout(vbox)
self.msgSc = QShortcut(QKeySequence(f'{self.lblscut}'), self)
self.msgSc.activated.connect(lambda: QMessageBox.information(self,'Message', 'Ctrl + M initiated'))
class Mainclass(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Sample Window")
x = Create_workingDict("Accounts","Alt+A")
y = Create_workingDict("Inventory", "Ctrl+B")
def main():
app = QApplication(sys.argv)
ex = Mainclass()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Shortcuts work based on the context (and visibility) of the parent widget: as long as the parent is visible and the context is compatible, they will be triggered, otherwise they will not even be considered.
Be aware that the visibility is of the parent widgets (note the plural) is mandatory, no matter of the context: Qt has no API for a "global" shortcut, not only external to the application, but also within it: there is no shortcut that can automatically work anywhere in the app if (any of) its parent(s) is hidden. The context only ensures that the shortcut can only be activated if the active widget is part of the application (ApplicationShortcut), if the current active window is an ancestor of the shortcut parent (WindowShortcut), if any of the grand[...]parent widgets has focus (WidgetWithChildrenShortcut) or the current parent has it (WidgetShortcut).
Long story short: if the shortcut's parent is not visible (at any level), it will not be triggered.
Not only. In your code, both x and y are potentially garbage collected (they are not due to the fact that the lambda scope avoids destruction, but that's just "sheer dumb luck"), so that code would be actually prone to fail anyway if the activated signal would have been connected to an instance method.
If you want them to be available to the visible window, you must add their parent widgets to that window, even if they're not shown. Otherwise, just add the shortcuts to that window.
For instance:
class Mainclass(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Sample Window")
x = Create_workingDict("Accounts","Alt+A")
y = Create_workingDict("Inventory", "Ctrl+B")
layout = QVBoxLayout(self)
layout.addWidget(x)
layout.addWidget(y)
The only and automatic way to access a global application shortcut from any window of the application is to create a QKeySequence that is checked within an event filter installed on the application.
This is a possible, but crude implementation, so, take it as it is and consider its consequences:
class ShortCutFilter(QObject):
triggered = pyqtSignal(QKeySequence)
def __init__(self, shortcuts=None):
super().__init__()
self.shortcuts = {}
def addShortcut(self, shortcut, slot=None):
if isinstance(shortcut, str):
shortcut = QKeySequence(shortcut)
slots = self.shortcuts.get(shortcut)
if not slots:
self.shortcuts[shortcut] = slots = []
if slot is not None:
slots.append(slot)
return shortcut
def eventFilter(self, obj, event):
if event.type() == event.KeyPress:
keyCode = event.key()
mods = event.modifiers()
if mods & Qt.ShiftModifier:
keyCode += Qt.SHIFT
if mods & Qt.MetaModifier:
keyCode += Qt.META
if mods & Qt.ControlModifier:
keyCode += Qt.CTRL
if mods & Qt.ALT:
keyCode += Qt.ALT
for sc, slots in self.shortcuts.items():
if sc == QKeySequence(keyCode):
self.triggered.emit(sc)
for slot in slots:
try:
slot()
except Exception as e:
print(type(e), e)
return True
return super().eventFilter(obj, event)
def main():
app = QApplication(sys.argv)
shortcutFilter = ShortCutFilter()
app.installEventFilter(shortcutFilter)
shortcutFilter.addShortcut('alt+b', lambda:
QMessageBox.information(None, 'Hello', 'How are you'))
shortcutFilter.triggered.connect(lambda sc:
print('triggered', sc.toString())
ex = Mainclass()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
This, obviously, means that any key press event will pass through the known python bottleneck. A better solution would be to create global QActions and addAction() to any possible top level window that could accept it.
While this approach might seem more complex, it has its benefits; for instance, you have more control on the context of the shortcut: in the case above, you could trigger Alt+B from any window, including the one shown after previously triggering it, which is clearly not a good thing.
Add the layout in main widget.
Then pass the layout to the function where you are creating labels and add them to layout.
Below is the modified code.
Find the details as comments in below code.
Your main window class
class Mainclass(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Sample Window")
#CREATE THE LAYOUT HERE IN MAIN WINDOW
vbox = QVBoxLayout()
x = Create_workingDict("Accounts","Alt+A",vbox) #PASS THE LAYOUT OBJECT (vbox) AS AN ARGUMENT
y = Create_workingDict("Inventory", "Ctrl+B",vbox) #PASS THE LAYOUT OBJECT (vbox) AS AN ARGUMENT
#SET THE LAYOUT TO MAIN WINDOW
self.setLayout(vbox)
Your function where labels created.
Observe that the functions vbox = QVBoxLayout() and self.setLayout(vbox) are moved out of this function to main window.
class Create_workingDict(QWidget):
def __init__(self,lblname,lblscut,vbox): #RECEIVE LAYOUT (vbox) ARGUMENT
super(). __init__()
self.lblname = lblname
self.lblscut = lblscut
lbl_1 = QLabel()
lbl_1.setText(self.lblname)
lbl_2 = QLabel()
lbl_2.setText(self.lblscut)
vbox.addWidget(lbl_1)
vbox.addWidget(lbl_2)
self.msgSc = QShortcut(QKeySequence(f'{self.lblscut}'), self)
self.msgSc.activated.connect(lambda: QMessageBox.information(self,'Message', 'Ctrl + M initiated'))

PyQt4 QMessageBox text change

I am using this simple code to show warning boxes:
w = QWidget()
result = QMessageBox.warning(w, 'a', x, QMessageBox.Ok)
Is there any way to change MESSAGE dynamically? I want to make a popup which will inform user abut progress of a task that is running in background.
Edit:
Well I tried to do so making this script for testing:
def handleButton(self):
self.msgBox = QMessageBox(self)
self.msgBox.setWindowTitle("Title")
self.msgBox.setIcon(QMessageBox.Warning)
self.msgBox.setText("Start")
self.msgBox.show()
x = 0
for x in range (100):
x = x + 1
print (x)
self.msgBox.setText(str(x))
self.msgBox.show()
time.sleep(1)
The text only shows after finishing the 'for loop', why?
Instead of using a static method you could create an object of the class.
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Widget(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.msgBox = QMessageBox(self)
self.msgBox.setWindowTitle("Title")
self.msgBox.setIcon(QMessageBox.Warning)
self.msgBox.setText("Start")
self.msgBox.show()
timer = QTimer(self)
timer.timeout.connect(self.onTimeout)
timer.start(1000)
def onTimeout(self):
self.msgBox.setText("datetime: {}".format(QDateTime.currentDateTime().toString()))
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
Update:
The problem in your example is the use of time.sleep(). Qt is executed in an eventloop, this eventloop allows you to handle the events of the mouse, keyboard, redraw, etc. but the time.sleep() blocks the eventloop, this you can check trying to change the size of the window, you will see that you can not do it.
Assuming you use time.sleep() to pause, then you must use QEventLoop with QTimer that does not block the Qt eventloop.
def handleButton(self):
self.msgBox = QMessageBox(self)
self.msgBox.setWindowTitle("Title")
self.msgBox.setIcon(QMessageBox.Warning)
self.msgBox.setText("Start")
self.msgBox.show()
for x in range(100):
self.msgBox.setText(str(x+1))
loop = QEventLoop()
QTimer.singleShot(1000, loop.quit)
loop.exec_()

How to properly show and hide GTK window in python

So I have the following code (python 2.7) that checks for a combination of keypresses and shows/hides a gtk window with a few gtk entry boxes. The show/hide works until the window locks up and stops responding, and the inner part of the window turns black. I have to kill the process and start it up again once that window turns black. I've tried all different combinations of show_all() and returning True after hiding the window to no avail. I'm not sure what I'm doing wrong here.
In the end I'd like to be able to press this key combination and show/hide this window without the contents going away.
#!/usr/bin/python
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
import pyxhook
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Configurator")
self.box = Gtk.Box(spacing=6)
self.add(self.box)
self.ipEntry = Gtk.Entry()
self.ipEntry.set_text("IP Address")
self.maskEntry = Gtk.Entry()
self.maskEntry.set_text("NetMask")
self.gatewayEntry = Gtk.Entry()
self.gatewayEntry.set_text("gatewayEntry")
self.button1 = Gtk.Button(label="Save")
self.button1.connect("clicked", self.on_button1_clicked)
self.box.pack_start(self.ipEntry, True, True, 0)
self.box.pack_start(self.maskEntry, True, True, 0)
self.box.pack_start(self.gatewayEntry, True, True, 0)
self.box.pack_start(self.button1, True, True, 0)
#catch window destroy event and stop it from happening
self.connect('delete-event', self.on_destroy)
def on_button1_clicked(self, widget):
print("Hello")
def on_destroy(self, widget=None, *data):
print("tried to destroy")
self.hide()
return True
#list of ascii keypresses to test if a certain combination of keys is pressed
keypresses = []
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
win.set_keep_above(True)
def OnKeyboardEvent(event):
#ascii 227 is l_control, ascii 225 is l_shift, ascii 120 is x
#bring the following external variables into the scope of this function
global keypresses
global win
#check if gtk window is hidden or visible
isVisible = win.get_property("visible")
#store our keypress if it is worthy of being stored (we started with a control character)
if event.Ascii == 227 or ( len(keypresses) >= 1 and keypresses[0] == 227 ):
print("here" + str(len(keypresses)))
keypresses.append(event.Ascii)
#check if we have three items in keypresses to compare, then see if it's the right combination
if len(keypresses) == 3 and keypresses[0] == 227 and keypresses[1] == 225 and keypresses[2] == 120:
#show/hide our window
if isVisible:
win.hide()
del keypresses[:]
keypresses = []
else:
win.show_all()
#clear out our list to compare again
del keypresses[:]
keypresses = []
elif len(keypresses) >= 3:
del keypresses[:]
keypresses = []
#create instance of hook manager
HookManager = pyxhook.HookManager()
#define our callback to fire when a key is pressed
HookManager.KeyDown = OnKeyboardEvent
#hook the keyboard
HookManager.HookKeyboard()
#start our listener
HookManager.start()
Gtk.main()
#close the hook listener when gtk main loop exits
HookManager.cancel()
Here is a small hack that tests the window show/hide when pressing F5. When you press it a second window will show or hide and i've tested for sometime without problems. Maybe it's the HookManager that somehow is messing with the Gtk/Glib mainloop. Nonetheless my method only works if there is a window to grab the key presses, so you will need, indeed, some form of grabbing key presses if your goal is to have no GUI:
#!/usr/bin/python
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
#import pyxhook
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Configurator")
self.box = Gtk.Box(spacing=6)
self.add(self.box)
self.ipEntry = Gtk.Entry()
self.ipEntry.set_text("IP Address")
self.maskEntry = Gtk.Entry()
self.maskEntry.set_text("NetMask")
self.gatewayEntry = Gtk.Entry()
self.gatewayEntry.set_text("gatewayEntry")
self.button1 = Gtk.Button(label="Save")
self.button1.connect("clicked", self.on_button1_clicked)
self.box.pack_start(self.ipEntry, True, True, 0)
self.box.pack_start(self.maskEntry, True, True, 0)
self.box.pack_start(self.gatewayEntry, True, True, 0)
self.box.pack_start(self.button1, True, True, 0)
#catch window destroy event and stop it from happening
self.connect('delete-event', self.on_destroy)
self.connect('key-press-event', self.on_keypress)
def on_keypress(self, widget, event):
global w
if event.keyval == Gdk.KEY_F5:
isVisible = w.get_property("visible")
if (isVisible):
w.hide()
else:
w.show()
print("Keypress")
def on_button1_clicked(self, widget):
print("Hello")
def on_destroy(self, widget=None, *data):
print("tried to destroy")
self.hide()
return False
w = MyWindow()
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
win.set_keep_above(True)
Gtk.main()

Python - Gtk - paste from clipboard

While building a simple GUI video downloader in python and with Glade3 I am stuck with pasting into a text entry box using an icon.
The application, and paste icon.
The python code:
# !/usr/python
import sys
import os
import subprocess as sp
try:
from gi.repository import Gtk, Gdk
except:
print('Gtk not available')
sys.exit(1)
try:
import pyGtk
pyGtk.require('2.0')
except:
pass
class VideoDownloader:
def on_mainwindow_destroy(self, object, data=None):
print "quit with cancel"
Gtk.main_quit()
def __init__(self):
self.gladefile = "lib/videodownloder.glade"
self.builder = Gtk.Builder()
self.builder.add_from_file(self.gladefile)
self.builder.connect_signals(self)
self.go = self.builder.get_object
self.window = self.go("mainwindow")
self.window.show()
self.okbtn = self.go("okbutton")
self.cancelbtn = self.go("cancelbutton")
#self.restartswitch = self.go("restartswitch")
self.contswitch = self.go("contswitch")
self.vlcswitch = self.go("vlcswitch")
self.urlentry = self.go("urlentry")
self.filechooser = self.go("filechooser")
self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
def on_urlentry_activate(self, widget):
url = self.urlentry.get_text()
print("the url is:" + url)
def on_urlentry_icon_press(self):
text = self.clipboard.set_text(self.urlentry.get_text(), -1)
print("the urlentry paste icon was clicked | 'text' ")
def on_urlentry_icon_press(self):
text = self.clipboard.wait_for_text()
print("the urlentry paste icon was clicked | 'text' ")
if text != None:
self.urlentry.set_text(text)
print(" 'text' has been pasted to the urlentry")
else:
print("No text on the clipboard")
def on_filechooser_file_activated(self, widget):
myfile = self.filechooser.get_uri()
print("the file is: " + myfile)
def on_vlcswitch_activate(self, widget):
print("VLC Switch has been activated")
def on_contswitch_activate(self, widget):
print("Continue switch has been acivated")
def on_quitbutton_clicked(self, button):
print("quit with the close button")
Gtk.main_quit()
def on_okbutton_clicked(self, button):
myfile = self.filechooser.get_uri()
url = self.urlentry.get_text()
wgetcmd = ("wget -O 'myfile ' 'url' ")
print("ok button has been clicked")
print("wget will now be run with your args: " +myfile+url)
os.system(wgetcmd)
if __name__ == "__main__":
print("videodownloader is running")
notify = os.system("notify-send --expire-time=5000 --icon='img/vid-down-logo.png' --app-name=VideoDownloader 'VideoDownloader' 'The VideoDownloader app is now running and ready!'")
notify
main = VideoDownloader()
Gtk.main()
print("videodownloader has stopped running")
When I run the code it mostly works but when I click the paste icon I get an error:
TypeError: on_urlentry_icon_press() takes exactly 1 argument (4 given)
I am fairly new to python and glade so I am probably making an elementary mistake but I do not know what is wrong and what the error means. I have searched but found only advice that didn't help.
Such as this..
Any suggestions on how to fix this please?
Your current on_urlentry_icon_press method only takes the self argument but it should take more than one because it is connected to the icon-press signal.
In the documentation you can see that it takes:
entry (a reference to the Gtk.Entry)
position (whether it is the primary or secondary icon)
event (e.g. whether it was a double click)
So it should look like this:
def on_urlentry_icon_press(self, entry, position, event):
print('urlentry icon clicked')

How do I add colour to this and make it look better for the user?

I can Add boxs and Tables
Also the Quit button does not work can someone edit that part of the code please
import gtk
class helloworld:
def close(self,widget):
print "I'm outta here"
gtk.main_quit()
def printit(self,widget,lab1):
print lab1.get_text()
def filllab(self,widget,lab1):
lab1.set_text(widget.get_text())
def __init__(self):
window = gtk.Window()
window.set_size_request(300,400)
vbox = gtk.VBox()
window.add(vbox)
lab1 = gtk.Label("shazbut")
# entry widget
ent1 = gtk.Entry()
ent1.connect("activate",self.filllab,lab1)
# quit
quitb = gtk.Button("quit",gtk.STOCK_QUIT)
quitb.set_size_request(50,100)
quitb.connect("destroy", gtk.main_quit)
printb = gtk.Button("print")
printb.connect("clicked",self.printit,lab1)
# Pack widgets in the vbox
vbox.add(ent1)
vbox.add(lab1)
vbox.add(quitb)
vbox.add(printb)
window.show_all()
helloworld()
gtk.main()
The "quit" button doesn't work because you connected the "destroy" signal to the button instead of the clicked signal
quitb.connect("clicked", gtk.main_quit)
Also, you forgot to connect the window destroy event (so the program will never exit when you click the window close button). Add
window.connect("destroy", gtk.main_quit)
To change the label properties use the pango attributes
def _add_attributes_to_label(self,label):
attr = pango.AttrList()
fg_color = pango.AttrForeground(65535, 0, 0,0,-1)
strike = pango.AttrStrikethrough(True,0,-1)
size = pango.AttrSize(30000, 0, -1)
attr.insert(fg_color)
attr.insert(size)
attr.insert(strike)
label.set_attributes(attr)
In your init function call the previous function like this:
self._add_attributes_to_label(lab1)
Follow this tutorial to know more about pango attributes.

Categories