web-dev-qa-db-fra.com

Comment puis-je ajouter une fonctionnalité couper / copier / coller à mon application?

Je développe un calculateur électoral ( https://launchpad.net/electoralcalculator ) en utilisant Python 2.7, Gtk + 3 et Glade et je souhaite ajouter des options couper/copier/coller fonctionnalité à mon application.

Je souhaite donner à l'utilisateur la possibilité de couper/copier/coller du texte à l'aide des éléments de menu (Edition> Couper, Edition> Copier et Edition> Coller> Coller), de boutons de barre d'outils ou de raccourcis clavier (Ctrl + X, Ctrl + C et Ctrl + V).

Comment puis-je obtenir le texte sélectionné pour le couper/le copier? Il existe de nombreux widgets de saisie de texte et le texte sélectionné peut figurer dans n’importe lequel d’eux.

Comment savoir où se trouve le curseur pour pouvoir y coller le contenu du presse-papiers?

J'ai trouvé à propos de cet exemple:
http://python-gtk-3-tutorial.readthedocs.org/en/latest/clipboard.html

Mais bien que dans cet exemple, il n'y ait qu'un seul widget de saisie de texte, dans mon application, il y en a beaucoup.
Comment savoir où se trouve le texte sélectionné (dans quel widget de saisie de texte) pour le couper/le copier?
Comment savoir où se trouve le curseur pour la fonctionnalité de collage?

L'anglais n'est pas ma langue maternelle, veuillez pardonner mes erreurs.

Merci de votre aide

MODIFIER:
J'ai écrit un exemple avec des boutons de coupe, copie et collage fonctionnels basés sur le code de Ian/Timo.
Merci à vous deux, Timo et Ian B., pour votre aide. J'apprécie vraiment cela.

Faites-moi savoir s'il y a quelque chose qui ne va pas dans l'exemple.

Les raccourcis clavier (Ctrl + X, Ctrl + C et Ctrl + V) fonctionnent automatiquement sans ajouter de code.

from gi.repository import Gtk, Gdk

class TwotextWindow(Gtk.Window):
    __gtype_= "TwotextWindow"

    def __init__(self):
        super(TwotextWindow, self).__init__()
        self.connect('delete-event', Gtk.main_quit)

        self.vbox = Gtk.VBox(False, 8)
        for x in range(4):
            self._build_entry()

        button_cut = Gtk.Button(label='Cut')
        button_cut.connect('clicked', self.on_cut_clicked)
        self.vbox.pack_start(button_cut, False, False, 0)

        button_copy = Gtk.Button(label='Copy')
        button_copy.connect('clicked', self.on_copy_clicked)
        self.vbox.pack_start(button_copy, False, False, 0)

        button_paste = Gtk.Button(label='Paste')
        button_paste.connect('clicked', self.on_paste_clicked)
        self.vbox.pack_start(button_paste, False, False, 0)

        self.add(self.vbox)
        self.show_all()

        # Code for other initialization actions should be added here.
        self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)

    def _build_entry(self):
        entry = Gtk.Entry(text='Hello, World!')
        entry.connect('focus-in-event', self.on_entry_focus)
        self.vbox.pack_start(entry, False, False, 0)

    def on_cut_clicked(self, widget):
        # Get the bounds of the selected text
        bounds = self.focus.get_selection_bounds()

        # if the bounds of the selection are not an empty Tuple,
        # put the selection in the variable chars
        # and copy it to the clipboard
        # (get_selection_bounds returns an empty Tuple if there is no selection)
        # then delete the selection
        if bounds:
            chars = self.focus.get_chars(*bounds)
            print "Copying '%s' from: %s" % (chars, self.focus)
            self.clipboard.set_text(chars, -1)
            print "Deleting text selection: characters from position %s to %s" % (bounds[0], bounds[1])
            self.focus.delete_text(bounds[0], bounds[1])
        else:
            print "Can't cut if you don't select text"

    def on_copy_clicked(self, widget):
        # Get the bounds of the selected text
        bounds = self.focus.get_selection_bounds()

        # if the bounds of the selection are not an empty Tuple,
        # put the selection in the variable chars
        # and copy it to the clipboard
        # (get_selection_bounds returns an empty Tuple if there is no selection)
        if bounds:
            chars = self.focus.get_chars(*bounds)
            print "Copying '%s' from: %s" % (chars, self.focus)
            self.clipboard.set_text(chars, -1)
        else:
            print "Can't copy if you don't select text"

    def on_paste_clicked(self, widget):
        # Get the text from the clipboard
        text = self.clipboard.wait_for_text()

        if text != None:
            # If there's text selected in the target
            # delete it and paste the contents of the clipboard
            bounds = self.focus.get_selection_bounds()
            if bounds:
                print "Deleting text selection: characters from position %s to %s" % (bounds[0], bounds[1])
                self.focus.delete_text(bounds[0], bounds[1])
                print "Pasting '%s' into: '%s' at the position %s" % (text, self.focus, bounds[0])
                self.focus.insert_text(text, bounds[0])

            # else insert the text in the current position of the cursor in the target
            else:
                pos = self.focus.get_position()
                #print "Cursor position in the target: %s" % pos
                print "Pasting '%s' into: '%s' at the position %s" % (text, self.focus, pos)
                self.focus.insert_text(text, pos)
        else:
            print "No text on the clipboard."

    def on_entry_focus(self, widget, event):
        print "Focused:", widget
        self.focus = widget


if __== '__main__':
    win = TwotextWindow()
    Gtk.main()
3

Pourquoi ne pas utiliser une variable interne pour stocker le dernier widget actif? Utilisez le signal événement-focus de l'événement de l'entrée (lorsque le clavier prend le focus) pour modifier cette variable avec son nom (peut utiliser un rappel commun pour toutes les entrées de texte). Ensuite, lorsque vous devez copier ou coller quelque chose, vous pouvez utiliser cette variable pour savoir où le mettre (via un getattr). Voici un petit exemple que j'ai concocté.

Code original édité pour fonctionner de manière autonome et résoudre des questions

from gi.repository import Gtk, Gdk

class TwotextWindow(Gtk.Window):
    __gtype_= "TwotextWindow"

    def __init__(self):
        super(TwotextWindow, self).__init__()
        self.connect('delete-event', Gtk.main_quit)

        self.vbox = Gtk.VBox(False, 8)
        for x in range(4):
            self._build_entry()

        button = Gtk.Button(label='Copy')
        button.connect('clicked', self.on_copy_clicked)
        self.vbox.pack_start(button, False, False, 0)

        self.add(self.vbox)
        self.show_all()

        # Code for other initialization actions should be added here.
        self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)

    def _build_entry(self):
        entry = Gtk.Entry(text='Hello, World!')
        entry.connect('focus-in-event', self.on_entry_focus)
        self.vbox.pack_start(entry, False, False, 0)

    def on_copy_clicked(self, widget):
        bounds = self.focus.get_selection_bounds()
        chars = self.focus.get_chars(*bounds)
        print "Copying '%s' from: %s" % (chars, self.focus)
        #TODO: do the actual copying

    def on_entry_focus(self, widget, event):
        print "Focused:", widget
        self.focus = widget


if __== '__main__':
    win = TwotextWindow()
    Gtk.main()

Je ne sais pas s'il existe un meilleur moyen de le faire. Je suis assez nouveau pour cela aussi.

2
Ian B.