Como posso adicionar funcionalidade de recortar / copiar / colar à minha aplicação?

3

Estou desenvolvendo uma calculadora eleitoral ( link ) usando Python 2.7, Gtk + 3 e Glade e quero adicionar recortar / copiar / colar a funcionalidade ao meu aplicativo.

Eu quero dar ao usuário a oportunidade de cortar / copiar / colar texto usando itens de menu (Editar > Recortar, Editar > Copiar e Editar > Colar), botões da barra de ferramentas ou atalhos de teclado (Ctrl + X, Ctrl + C e Ctrl + V).

Como posso obter o texto selecionado para recortar / copiar? Existem muitos widgets de entrada de texto e o texto selecionado pode estar em qualquer um deles.

Como posso saber onde o cursor está, para poder colar o conteúdo da área de transferência?

Encontrei este exemplo: link

Mas enquanto neste exemplo há apenas um widget de entrada de texto, na minha aplicação há muitos deles.
Como posso saber onde está o texto selecionado (em qual widget de entrada de texto) para recortar / copiar?
Como posso saber onde o cursor está para a funcionalidade de colar?

O inglês não é minha primeira língua, por favor, perdoe meus erros.

Obrigado pela sua ajuda

EDIT:
Eu escrevi um exemplo com o trabalho de cortar, copiar e colar botões com base no código do Ian / Timo.
Obrigado a ambos, Timo e Ian B., pela sua ajuda. Eu realmente gostei disso.

Deixe-me saber se há algo errado no exemplo.

Os atalhos de teclado (Ctrl + X, Ctrl + C e Ctrl + V) funcionam automaticamente, sem adicionar código.

from gi.repository import Gtk, Gdk

class TwotextWindow(Gtk.Window):
    __gtype_name__ = "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 __name__ == '__main__':
    win = TwotextWindow()
    Gtk.main()
    
por Asier Iturralde Sarasola 27.07.2012 / 17:26

1 resposta

2

Que tal usar uma variável interna para armazenar o último widget ativo? Use o sinal de foco em evento da entrada (quando o teclado tiver o foco) para modificar essa variável com seu nome (pode usar um retorno de chamada comum para todas as entradas de texto). Então quando você precisar copiar ou colar algo, você pode usar essa variável para saber onde colocá-la (via um getattr). Aqui está um pequeno exemplo que eu cozinhei.

Código original editado para funcionar de forma independente e resolver questões

from gi.repository import Gtk, Gdk

class TwotextWindow(Gtk.Window):
    __gtype_name__ = "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 __name__ == '__main__':
    win = TwotextWindow()
    Gtk.main()

Não sei se há uma maneira melhor de fazer isso. Eu sou muito novo para isso também.

    
por Ian B. 27.07.2012 / 20:48