Sto lavorando con un TextView/TextBuffer Gtk nel mio progetto in cui l'utente è in grado di digitare il testo RTF (grassetto/corsivo/sottolineato)) selezionando i pulsanti di commutazione corretti.Gtk3 TextBuffer.serialize() restituisce il testo con i tag di formato, anche quando non c'è visivamente nessuno
Il problema è che se applico la sottolineatura o il flag di Pango in corsivo in testo all'interno di TextView, disattivi il corsivo/sottolineatura e ne scrivo un po 'e poi ottengo il testo con quei flag tramite TextBuffer.serialize()
, il testo non formattato (visibilmente non formattato in TextView) viene restituito con i tag Underline/Italic che lo circondano.
Potete vedere questo qui: (Nota, ho semplificato i tag alle loro controparti HTML con BeautifulSoup per migliorare la leggibilità, ma l'attuale posizioni/tipo non sono stati modificati a tutti.)
Ecco il codice (richiede GTK3 e BS4 per python3 per essere installato):
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, Pango
import smtplib, mimetypes
from bs4 import BeautifulSoup
class Handler():
def __init__(self):
global html
self.state = 0
def onDeleteWindow(self, *args):
Gtk.main_quit(*args)
def onSendClicked(self, button):
start, end = textBodyBuffer.get_bounds()
self.content = textBodyBuffer.get_text(start, end, True)
# Below is the serialization code for exporting with format tags
format = textBodyBuffer.register_serialize_tagset()
exported = textBodyBuffer.serialize(textBodyBuffer, format, start, end)
exported = exported.decode("latin-1")
exported = exported.split('<text_view_markup>', 1)
del exported[0]
exported[0] = '<text_view_markup>' + str(exported[0])
exported = exported[0].split('</tags>', 1)
del exported[0]
exported = exported[0].split('</text_view_markup>', 1)
exported = str(exported[0]).replace('\n', ' ')
soup = BeautifulSoup(exported)
soupTags = soup.find_all('apply_tag')
for tag in soupTags:
if tag['name'] == 'bold':
tag.name = 'b'
del tag['name']
elif tag['name'] == 'italic':
tag.name = 'em'
del tag['name']
elif tag['name'] == 'underline':
tag.name = 'u'
del tag['name']
print (soup)
def bold(self, button):
global tags_on
name = button.get_name()
if button.get_active(): # Button is "down"/enabled
tags_on.append('bold')
elif button.get_active() != True: # Button is "up"/disabled
del tags_on[tags_on.index('bold')]
def italic(self, button):
global tags_on
name = button.get_name()
if button.get_active(): # Button is "down"/enabled
tags_on.append('italic')
elif button.get_active() != True: # Button is "up"/disabled
del tags_on[tags_on.index('italic')]
def underline(self, button):
global tags_on
name = button.get_name()
if button.get_active(): # Button is "down"/enabled
tags_on.append('underline')
elif button.get_active() != True: # Button is "up"/disabled
del tags_on[tags_on.index('underline')]
def alignToggled(self, radiobutton):
pass
def undo(self, button):
pass
def redo(self, button):
pass
def keyHandler(self, widget, event):
global html
if Gdk.ModifierType.CONTROL_MASK & event.state:
if Gdk.keyval_name(event.keyval) == 'q': # Quit the program
w.destroy()
Gtk.main_quit()
def get_iter_position(buffer):
return buffer.get_iter_at_mark(buffer.get_insert())
def text_inserted(buffer, iter, char, length):
global tags_on
if len(tags_on) >= 0:
iter.backward_chars(length)
for tag in tags_on:
w.queue_draw()
if tag == 'bold':
buffer.apply_tag(tag_bold, get_iter_position(buffer), iter)
elif tag == 'italic':
buffer.apply_tag(tag_italic, get_iter_position(buffer), iter)
elif tag == 'underline':
buffer.apply_tag(tag_underline, get_iter_position(buffer), iter)
if __name__ == '__main__':
global text, html
# Gtk tag globals
global tag_bold, tag_italic, tag_underline, tags_on
tags_on = []
text = ''
html = '<html><body><p>'
builder = Gtk.Builder()
builder.add_from_file('editor.glade')
builder.connect_signals(Handler())
buttonSend = builder.get_object('buttonSend')
textBody = builder.get_object('textviewBody')
textBodyBuffer = textBody.get_buffer()
textBodyBuffer.connect_after('insert-text', text_inserted)
tag_bold = textBodyBuffer.create_tag("bold", weight=Pango.Weight.BOLD)
tag_italic = textBodyBuffer.create_tag("italic", style=Pango.Style.ITALIC)
tag_underline = textBodyBuffer.create_tag("underline", underline=Pango.Underline.SINGLE)
w = builder.get_object('window1')
w.show_all()
Gtk.main()
Ecco il file editor.glade
:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">mail-send</property>
</object>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Keyboard Mail - Edit Message</property>
<property name="modal">True</property>
<property name="type_hint">dialog</property>
<signal name="delete-event" handler="onDeleteWindow" swapped="no"/>
<signal name="key-press-event" handler="keyHandler" swapped="no"/>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkButton" id="buttonSend">
<property name="label" translatable="yes">Send</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">image1</property>
<property name="relief">none</property>
<property name="image_position">top</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="onSendClicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkToolbar" id="toolbar1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="toolbar_style">icons</property>
<property name="show_arrow">False</property>
<child>
<object class="GtkToggleToolButton" id="buttonBold">
<property name="name">bold</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Make the selected text bold</property>
<property name="icon_name">format-text-bold</property>
<signal name="toggled" handler="bold" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToggleToolButton" id="buttonItalic">
<property name="name">italic</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">format-text-italic</property>
<signal name="toggled" handler="italic" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToggleToolButton" id="buttonUnderline">
<property name="name">underline</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">format-text-underline</property>
<signal name="toggled" handler="underline" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkTextView" id="textviewBody">
<property name="width_request">500</property>
<property name="height_request">100</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="wrap_mode">word</property>
<property name="left_margin">5</property>
<property name="right_margin">5</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
Qualcuno sa perché l'istruzione TextBuffer.serialize()
(riga 23) restituisca i caratteri visibilmente non formattati all'interno dei tag underline/italic?
Non riesco a trovare alcun motivo quando questo si verifica, sembra decidere in modo casuale di restituire il testo con i tag o meno.
Modifica: Ho seguito il codice passo dopo passo con pdb
(debugger Python) e non ho ancora visto nulla che possa causare questo.
Edit: modello interessante che ho capito - se si attiva sia corsivo e sottolineato in una sola volta, quindi digitare alcuni, poi girare entrambi fuori in una sola volta, e il tipo, la chiamata serialize()
restituisce la stringa corretta.
Tuttavia, se li si applica uno alla volta, digitando un bit per ogni nuovo tag, viene restituito in modo errato.
@ace Fatto. Ho aggiunto uno snippet di codice in linea. Il problema è che mettere il file .glade renderebbe la domanda troppo lunga, quindi ho dovuto mantenere il collegamento a una pagina PasteBin per quello. –
@ace Ah. Proverò a ridurlo un po 'di più. L'ho già abbattuto un po ', ma vedrò di più che posso tagliare. –
@ace Fatto. È un esempio più appropriato? –