Gtk3TextBuffer.serialize文本缓冲区()返回带有格式标记的文本,即使在视觉上没有

2024-10-01 04:55:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我在我的项目中使用了Gtk TextView/TextBuffer,用户可以通过选择正确的切换按钮输入富文本(粗体/斜体/下划线)。在

问题是,如果我将下划线或斜体Pango标志应用于TextView中的文本,然后关闭italic/underline并再键入一些,然后通过TextBuffer.serialize()获得带有这些标志的文本,则返回未格式化文本(在TextView中明显是未格式化的)并在其周围添加下划线/斜体标记。在

您可以在这里看到这一点:(注意,为了可读性,我使用BeautifulSoup将标记简化为HTML对应的标记,但是实际位置/类型根本没有被编辑过。)

代码如下(Python3需要安装Gtk3和BS4):

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()

这是editor.glade文件:

^{pr2}$

有人知道为什么TextBuffer.serialize()语句(第23行)在下划线/斜体标记中返回明显的非格式化字符吗?在

我似乎找不到任何模式,当发生这种情况时,它似乎随机决定是否返回带有标记的文本。在

编辑:我已经用pdb(Python调试器)一步一步地检查了代码,但仍然没有看到任何可能导致这种情况的东西。在

编辑:我发现了一个有趣的模式——如果你同时打开斜体和下划线,那么输入一些,然后同时关闭它们,然后输入,serialize()调用返回正确的字符串。在

但是,如果一次应用一个,为每个新标记键入一个位,则返回错误。在


Tags: textnameselfgetondeftagbuffer
1条回答
网友
1楼 · 发布于 2024-10-01 04:55:50

我已经能够用C中的minimal example来重现这个问题,因此我强烈怀疑这是GTK中的一个bug。发问者因此opened a bugreport upstream。在

作为一种解决方法,我建议您尝试自己实现序列化。forward_to_tag_toggle应该对这一点有帮助。请注意,您不能使用使用register_serialize_format注册自己的序列化程序然后调用serialize的明显路径,因为虽然GtkTextBufferSerializeFunc应该返回一个字符串,但在GObject存储库it is apparently recorded as a function returning a single integer中。(由于另一个错误。)相反,完全从代码中执行序列化,即获取一个start iter,然后遍历文本缓冲区。在

相关问题 更多 >