GTK-Clipboard mit QT?

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
BernieBln
User
Beiträge: 4
Registriert: Sonntag 8. November 2009, 17:31

Hallo zusammen,

ich komme aus der Java-Ecke und kenne mich leider noch nicht so gut mit Python/QT aus.

Ich habe einen Dialog in QT4 erstellt, mittels pyuic4 übersetzt und auch schon einige Slots implementiert.

Nun würde ich gerne die Funktion set_with_data des GTK-Clipboard-Objektes verwenden. Genaugenommen benötige ich diese bloß, um ein Signal zu erhalten, wenn ein Programm auf die von mir befüllte Zwischenablage zugegriffen hat. Das ist mit dieser Methode möglich, da man ein Funktionshandle mitgibt.

Mir scheint, dass das QT-Clipboard eine solche Möglichkeit nicht bietet. Falls doch, hätte sich damit meine Frage bereits erledigt!

Da es aber nicht so scheint, wollte ich in meiner QT-Anwendung das GTK-Clipboard benutzen.

Das scheint aber nicht zu gehen, solange man nicht die gtk.main()-Methode aufruft, die dann aber natürlich das Programm blockiert, so dass der Aufruf der QtGui.QApplication.exec_() nicht mehr passiert und damit auch der Dialog nicht angezeigt wird.

Selbt das Auslagern des gtk.main()-Aufrufes in einen separaten Thread scheint nichts zu bringen, das Programm wird (bei Aufruf der start()-Methode des Threads) trotzdem blockiert.

Darüber hinaus erhalte ich die folgende Meldung:

Code: Alles auswählen

/usr/lib/pymodules/python2.6/gtk-2.0/gtk/__init__.py:127: RuntimeWarning: PyOS_InputHook is not available for interactive use of PyGTK
  set_interactive(1)
Das liegt vermutlich daran, dass ich kein GTK-Fenster erstellt habe, und scheint mir schon ein Hinweis darauf zu sein, dass meine Verwendungsweise eigentlich nicht vorgesehen ist.

Weiß jemand, ob es eine saubere Möglichkeit gibt, in einer QT-Applikation das GTK-Clipboard zu verwenden, oder mit QT-Boardmitteln ein Signal zu erhalten, wenn die Zwischenablage abgefragt wurde?

Besten Dank im Voraus,

Bernhard
franzf
User
Beiträge: 78
Registriert: Samstag 29. August 2009, 10:21

Hast du es schonmal komplett ohne eigenem Starten der gtk-Eventloop versucht? Wenn ich hier bei meinen Programmen (C++) debugge, sehe ich oft den GLib-EventDispatcher samt g_main auftauchen, obwohl ich das nicht selber anstoße.
Qt4 hat ja seit geraumer Zeit Phonon mit an Bord und verwendet unter Linux GStreamer als Backend, welches aber die gtk-EventLooop benötigt. Drum denke ich die (bei entsprechend einkompilierten Support in Qt) wird bei dir auch schon laufen...
Google liefert nämlich auch kaum aktuelle Treffer.
BernieBln
User
Beiträge: 4
Registriert: Sonntag 8. November 2009, 17:31

Hi,

vielen Dank für Deine Antwort!
franzf hat geschrieben:Hast du es schonmal komplett ohne eigenem Starten der gtk-Eventloop versucht? Wenn ich hier bei meinen Programmen (C++) debugge, sehe ich oft den GLib-EventDispatcher samt g_main auftauchen, obwohl ich das nicht selber anstoße.
Ja, habe ich - das Ergebnis ist leider ein Programmabsturz mit Meldung "Segmentation Fault".
franzf hat geschrieben:Qt4 hat ja seit geraumer Zeit Phonon mit an Bord und verwendet unter Linux GStreamer als Backend, welches aber die gtk-EventLooop benötigt. Drum denke ich die (bei entsprechend einkompilierten Support in Qt) wird bei dir auch schon laufen...
Google liefert nämlich auch kaum aktuelle Treffer.
Hm, klingt interessant. Ich muss zugeben, dass ich meine Libs vom Ubuntu Paket-Manager habe installieren lassen (9.10), aber python-qt-phonon war da bereits mit dabei (und libqt4 ist in der Version 4.5.2 bzw. python-qt4 in Version 4.6 sind auch nicht gerade superalt...)

So konnte ich problemlos das Beispiel unter

http://techbase.kde.org/Development/Tut ... ion/Python

verwenden (ein ganz einfacher Audio-Player in Python, der Phonon verwendet), der Sound war zu hören, aber als ich in diesen Code meinen Code für die Zwischenablage hinzugefügt habe, gab es wieder einen Segmentation Fault.

Glaubst Du, es könnte trotzdem funktionieren? Ich bin leider ein wenig ratlos...

Bernhard
lunar

Zeige bitte ein kleinstmögliches Beispiel, dass den Absturz reproduziert. Möglicherweise hast Du ein "gobject.init()" vergessen.
BernieBln
User
Beiträge: 4
Registriert: Sonntag 8. November 2009, 17:31

Hallo,
lunar hat geschrieben:Zeige bitte ein kleinstmögliches Beispiel, dass den Absturz reproduziert. Möglicherweise hast Du ein "gobject.init()" vergessen.
hier ist ein funktionierendes Beispiel (verwende GTK für Fenster und für Clipboard):

Code: Alles auswählen

#!/usr/bin/python

import pygtk
pygtk.require('2.0')
import gtk

class HelloWorld:
    
    i = 0;

    def docopy(self, widget, data=None):
        self.my_set_text("Hallo!")

    def destroy(self, widget, data=None):
       gtk.main_quit()

    def __init__(self):
       self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)

       self.window.connect("destroy", self.destroy)
       self.window.set_border_width(10)
       self.button = gtk.Button("Dynamic Copy")
       self.button.connect("clicked", self.docopy, None)
       self.window.add(self.button)
       self.button.show()
       self.window.show()
       
    def my_set_text(self, text, len=-1):
        targets = [ ("STRING", 0, 0),
                  ("TEXT", 0, 1),
                  ("COMPOUND_TEXT", 0, 2),
                  ("UTF8_STRING", 0, 3) ]
        def text_get_func(clipboard, selectiondata, info, data):
            if self.i == 0:
                selectiondata.set_text("One")
                self.i=self.i+1
            else:
                selectiondata.set_text("Two")
                
            return
          
        def text_clear_func(clipboard, data):
          del data
          return

        self.i = 0
        self.clipbrd.set_with_data(targets, text_get_func, text_clear_func, text)
        return


    def main(self):
       self.clipbrd=gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD)
       gtk.main()

hello = HelloWorld()
hello.main()
Wenn man das Programm startet, kann man auf "Dynamic Copy" klicken, und wenn man woanders zweimal einfügt (mit STRG+V), werden zwei verschiedene Strings gepastet.

Und hier eins, welches QT für das Fenster verwendet, und GTK für das Clipboard, allerdings ohne die gtk.main()-Methode aufzurufen (da diese sonst alles blockiert):

Code: Alles auswählen

#!/usr/bin/python

import sys
from PyQt4 import QtGui, QtCore
import gtk

class Button(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Copy test')
        
        quit = QtGui.QPushButton('Copy', self)
        quit.setGeometry(10, 10, 60, 35)

        self.connect(quit, QtCore.SIGNAL('clicked()'), self.copy)
        # get gtk clipboard
        self.clipbrd = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD)


    def my_set_text(self, text, len=-1):
        targets = [ ("STRING", 0, 0),
                  ("TEXT", 0, 1),
                  ("COMPOUND_TEXT", 0, 2),
                  ("UTF8_STRING", 0, 3) ]
        def text_get_func(clipboard, selectiondata, info, data):
            if self.i == 0:
                selectiondata.set_text("One")
                self.i=self.i+1
            else:
                selectiondata.set_text("Two")
                
            return
          
        def text_clear_func(clipboard, data):
          del data
          return
        self.i = 0
        self.clipbrd.set_with_data(targets, text_get_func, text_clear_func, text)
        return
        
    def copy(self):
        self.my_set_text('xx')


app = QtGui.QApplication(sys.argv)
qb = QuitButton()
qb.show()
sys.exit(app.exec_())
Das zweite Beispiel funktioniert so weit, man kann sogar auf "Kopieren" klicken, ohne dass etwas (schlimmes) passiert, aber wenn man das Kopierte dann woanders via STRG+V einfügen möchte, gibt es den Segmantation Fault.

Ich frage mich fast, ob es klüger wäre, direkt mit der XLib von Python zu programmieren, leider sieht die ziemlich kompliziert aus...

Bernhard
franzf
User
Beiträge: 78
Registriert: Samstag 29. August 2009, 10:21

Schon mal den BT angeschaut?

Code: Alles auswählen

(gdb) bt                                                                
#0  0x00007ffff7e2d3fa in PyObject_Call () from /usr/lib/libpython2.6.so.1.0
#1  0x00007ffff7eb6d72 in PyEval_CallObjectWithKeywords () from /usr/lib/libpython2.6.so.1.0
#2  0x00007ffff29e3e1a in clipboard_get_func () from /usr/lib64/python2.6/site-packages/gtk-2.0/gtk/_gtk.so
#3  0x00007ffff4b9133e in g_closure_invoke () from /usr/lib/libgobject-2.0.so.0                            
#4  0x00007ffff4ba61ec in signal_emit_unlocked_R () from /usr/lib/libgobject-2.0.so.0                      
#5  0x00007ffff4ba7556 in g_signal_emit_valist () from /usr/lib/libgobject-2.0.so.0                        
#6  0x00007ffff4ba788f in g_signal_emit_by_name () from /usr/lib/libgobject-2.0.so.0                       
#7  0x00007ffff261d31b in gtk_selection_invoke_handler () from /usr/lib/libgtk-x11-2.0.so.0                
#8  0x00007ffff261d6c4 in _gtk_selection_request () from /usr/lib/libgtk-x11-2.0.so.0                      
#9  0x00007ffff25c03e8 in _gtk_marshal_BOOLEAN__BOXED () from /usr/lib/libgtk-x11-2.0.so.0                 
#10 0x00007ffff4b9133e in g_closure_invoke () from /usr/lib/libgobject-2.0.so.0                            
#11 0x00007ffff4ba5ecc in signal_emit_unlocked_R () from /usr/lib/libgobject-2.0.so.0                      
#12 0x00007ffff4ba73ea in g_signal_emit_valist () from /usr/lib/libgobject-2.0.so.0                        
---Type <return> to continue, or q <return> to quit---                                                     
#13 0x00007ffff4ba7a63 in g_signal_emit () from /usr/lib/libgobject-2.0.so.0                               
#14 0x00007ffff26c023f in gtk_widget_event_internal () from /usr/lib/libgtk-x11-2.0.so.0                   
#15 0x00007ffff25b9b97 in gtk_main_do_event () from /usr/lib/libgtk-x11-2.0.so.0                           
#16 0x00007ffff247f59c in gdk_event_dispatch () from /usr/lib/libgdk-x11-2.0.so.0                          
#17 0x00007ffff50c791b in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0                        
#18 0x00007ffff50cb220 in g_main_context_iterate () from /usr/lib/libglib-2.0.so.0                         
#19 0x00007ffff50cb350 in g_main_context_iteration () from /usr/lib/libglib-2.0.so.0                       
#20 0x00007ffff5902fd3 in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib64/qt4/libQtCore.so.4
#21 0x00007ffff5ae45ae in QGuiEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib64/qt4/libQtGui.so.4
#22 0x00007ffff58d8f42 in QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib64/qt4/libQtCore.so.4            
#23 0x00007ffff58d931d in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib64/qt4/libQtCore.so.4                     
#24 0x00007ffff58dcf43 in QCoreApplication::exec() () from /usr/lib64/qt4/libQtCore.so.4
#25 0x00007ffff677028a in meth_QApplication_exec_ () from /usr/lib64/python2.6/site-packages/PyQt4/QtGui.so
---Type <return> to continue, or q <return> to quit---
#26 0x00007ffff7ebcc08 in PyEval_EvalFrameEx () from /usr/lib/libpython2.6.so.1.0
#27 0x00007ffff7ebe4e5 in PyEval_EvalCodeEx () from /usr/lib/libpython2.6.so.1.0
#28 0x00007ffff7ebe5c2 in PyEval_EvalCode () from /usr/lib/libpython2.6.so.1.0
#29 0x00007ffff7ed825c in run_mod () from /usr/lib/libpython2.6.so.1.0
#30 0x00007ffff7ed8330 in PyRun_FileExFlags () from /usr/lib/libpython2.6.so.1.0
#31 0x00007ffff7ed969f in PyRun_SimpleFileExFlags () from /usr/lib/libpython2.6.so.1.0
#32 0x00007ffff7ee5611 in Py_Main () from /usr/lib/libpython2.6.so.1.0
#33 0x00007ffff6fe9bbd in __libc_start_main () from /lib/libc.so.6
#34 0x0000000000400249 in _start ()
Also, die GTK-EventLoop läuft. Es wird gedispatcht, usw. Aber es segfaultet.
Es hat sicherlich was mit dem set_interactive zu tun. Nur hab ich wenig Ahnung, wann man "interactive" braucht...
(Hab jetzt mal kurz set_interactive auskommentiert, und ebenso auf False gesetzt, segfault mit dem gleichen Backtrace)

Was ich mich aber frage: Warum verwendest du nicht gleich nur PyGTK, wenn das Feature wichtig ist? Dann kannst du dir das XLib schenken...
Oder mit PyQt4 auf das Feature verzichten.

Aber vllt. wirst du aus dem Backtrace schlau und findest eine Lösung :)
BernieBln
User
Beiträge: 4
Registriert: Sonntag 8. November 2009, 17:31

Hi!
Also, die GTK-EventLoop läuft. Es wird gedispatcht, usw. Aber es segfaultet.
Es hat sicherlich was mit dem set_interactive zu tun. Nur hab ich wenig Ahnung, wann man "interactive" braucht...
(Hab jetzt mal kurz set_interactive auskommentiert, und ebenso auf False gesetzt, segfault mit dem gleichen Backtrace)
Hm...da habe ich leider auch keine Ahnung :)
Was ich mich aber frage: Warum verwendest du nicht gleich nur PyGTK, wenn das Feature wichtig ist? Dann kannst du dir das XLib schenken...
Oder mit PyQt4 auf das Feature verzichten.
Naja, ich bin Einsteiger, und fand die Oberflächengestaltung mit dem QT-Designer super...während ich hingegen GTK etwas umständlich finde. Muss mich aber noch etwas weiter reinfuchsen.

Auf das Feature wll ich auf keinen Fall verzichten, das mit der XLib ist aber auch sehr umständlich -> Läuft wohl auf eine GTK-Form heraus :)
Aber vllt. wirst du aus dem Backtrace schlau und findest eine Lösung :)
Leider nein :)

Ich denke, ich werde die Anwendung auf GTK umwandeln, das wird das einfachste sein.

Vielen herzlichen Dank für Deine Mühe!

Bernhard
Antworten