使用TextBuffer pyGtk

问题描述

我当时正在与pygtk一起构建我的小项目,该项目使用gtk,基本上有一个窗口,在此窗口中,我有一个树视图,在树视图中有一个gtk.liststore。

Here is a image with the window and its values

一切都很酷,直到我意识到我需要一些标签,看到了许多使用pango的示例,并且它可以正常工作,至少直到选择的行被更改为止。

我用不太优雅的东西解决了这个问题, here a link to the complete code

    def on_toolbar_button_clicked(self,widget,tag):
        bounds_front    = self.text_buffer_front.get_selection_bounds()
        bounds_back     = self.text_buffer_back.get_selection_bounds()

        if len(bounds_front) != 0:

            (start,end)        = bounds_front
            selection_front      = self.text_buffer_front.get_text(start,end,True)
            get_insert_front     = self.text_buffer_front.get_insert()

            self.text_buffer_front.delete(start,end)

            iter_front           = self.text_buffer_front.get_iter_at_mark(get_insert_front)
            self.text_buffer_front.insert(iter_front,tag[0] + selection_front + tag[1])

基本上,当我单击工具栏的下划线按钮时,此方法会将 放在单词周围,其值将放置在列表存储中,并使用textview显示该值。如果至少set_text检测到这些语法,那将是完美的。

因此,我要实现的目标是在textview上显示标记的单词,当我更改该行并返回上一个标记的行时,它仍然显示标记的单词,例如,如果我在单词下划线,当我回来时它仍然强调,并且如果解决方案涉及使用pango,我如何从中获取值以供以后使用。

到目前为止,我一直在尝试弄乱textbuffer.serialize和textbuffer.deserialized,但是它并没有按照我的意愿工作。

编辑

就像这里我在“纸”上应用下划线标签一样,将文本缓冲区序列化,将其放入变量中,但是如何将其传递回缓冲区?

exported = self.text_buffer_front.serialize( self.text_buffer_front,format,start_iter_front,end_iter_front )

打印变量'exported'我得到一个字节值:

b'GTKTEXTBUFFERCONTENTS-0001\x00\x00\x00w <text_view_markup>\n <tags>\n </tags>\n<text>A
At the first comes rock!  Rock,<apply_tag name="underline">paper</apply_tag>,scissors!

编辑2

这可能是显而易见的,但对我而言不是,如果我将序列化了,接下来要做的就是将其“反序列化”,为此有gtk.TextBuffer.deserialize

语法应如下所示:

        self.dict_any_tags = {str(key): value[1] for key,value in enumerate(self.sub_list_store)}

    def item_selected(self,*args):
        try:
            iter_start_front        = self.text_buffer_front.get_start_iter()
            iter_end_front          = self.text_buffer_front.get_end_iter()
            path                    = self.selected_row.get_selected_rows()[1][0]

            try:
                self.text_buffer_front.deserialize(self.text_buffer_front,self.text_buffer_front.register_deserialize_tagset(),self.text_buffer_front.get_start_iter(),self.dict_any_tags[str(path)])
            except:
                self.text_buffer_front.set_text(self.sub_list_store[path][1])
        except IndexError:
            pass

    def on_toolbar_button_clicked(self,tag):
        bounds_front    = self.text_buffer_front.get_selection_bounds()
        bounds_back     = self.text_buffer_back.get_selection_bounds()
        path            = self.selected_row.get_selected_rows()[1][0]

        if len(bounds_front) != 0:

            (start,end)        = bounds_front
            selection_front     = self.text_buffer_front.get_text(start,True)
            get_insert_front    = self.text_buffer_front.get_insert()

            self.text_buffer_front.apply_tag(tag,start,end)

            start_iter_front    = self.text_buffer_front.get_start_iter()
            end_iter_front      = self.text_buffer_front.get_end_iter()
            format              = self.text_buffer_front.register_serialize_tagset()
            exported            = self.text_buffer_front.serialize( self.text_buffer_front,end_iter_front)

            self.dict_any_tags[str(path)] = exported

问题是,当我尝试将反序列化放在错误的位置之前,它没有做任何事情。现在,我可以更轻松地跟踪标记在哪里,等等。我只需要运行更多测试。

解决方法

关键是创建另一个迭代器(我使用了字典)来跟踪序列化的文本,然后当我单击一行时,如果值是字节,它将尝试使用反序列化功能,因为不是,它将简单地正常设置文本带有set_text。

同样重要的是,在反序列化之前,将文本设置为no set_text(''),否则缓冲区的先前值将放置在缓冲区当前值的前面。

对于文本的更改,我使用了connect方法来连接'changed'信号,并对更改进行序列化,然后将序列化的值传递给字典。这就是我得到的:

        # dictionary to track the tags
        self.dict_any_change_front  = {str(key): value[1] for key,value in enumerate(self.sub_list_store)}
        self.dict_any_change_back   = {str(key): value[1] for key,value in enumerate(self.sub_list_store_back)}

    def deserialize(self,text_buffer,exported):
        text_buffer.set_text('')
        text_buffer.deserialize( text_buffer,text_buffer.register_deserialize_tagset(),text_buffer.get_start_iter(),exported )

    def item_selected(self,*args):
        #   Need this try/except to silent a indexerror that will occur case the second window close and if opened again,# merely cosmetic as it will always occur,just select any row and all good.
        #   The get_selected_rows()[1] will return a empty list at first try when reopening the second window,I just don't know why

        try:
            path                    = self.selected_row.get_selected_rows()[1][0]

            exported_front          = self.dict_any_change_front[str(path)]
            exported_back           = self.dict_any_change_back[str(path)]

            try:
                if isinstance(exported_front,bytes):
                    self.deserialize(self.text_buffer_front,exported_front)
                else:
                    self.text_buffer_front.set_text(self.sub_list_store[path][1])
                if isinstance(exported_back,bytes):
                    self.deserialize(self.text_buffer_back,exported_back)
                else:
                    self.text_buffer_back.set_text(self.sub_list_store_back[path][1])
            except:
                self.text_buffer_front.set_text(self.sub_list_store[path][1])
                self.text_buffer_back.set_text(self.sub_list_store_back[path][1])

            self.text_buffer_front.connect('changed',self.editingCard)
            self.text_buffer_back.connect('changed',self.editingCardBack)

        except IndexError:
            pass

    def editingCard(self,text_buffer):
        path                                = self.selected_row.get_selected_rows()[1][0]
        start_iter_front                    = text_buffer.get_start_iter()
        end_iter_front                      = text_buffer.get_end_iter() 

        self.sub_list_store[path][1]        = text_buffer.get_text(start_iter_front,end_iter_front,True)

        format                              = text_buffer.register_serialize_tagset()
        exported                            = text_buffer.serialize(    text_buffer,format,start_iter_front,end_iter_front )
        
        self.dict_any_change_front[str(path)] = exported

    def editingCardBack(self,text_buffer):
        path                                = self.selected_row.get_selected_rows()[1][0]
        start_iter_back                     = text_buffer.get_start_iter()
        end_iter_back                       = text_buffer.get_end_iter() 

        self.sub_list_store_back[path][1]   = text_buffer.get_text(start_iter_back,end_iter_back,True)

        format              = text_buffer.register_serialize_tagset()
        exported            = text_buffer.serialize(    text_buffer,start_iter_back,end_iter_back   )
        self.dict_any_change_back[str(path)] = exported

    def on_toolbar_button_clicked(self,widget,tag_front,tag_back):
        bounds_front    = self.text_buffer_front.get_selection_bounds()
        bounds_back     = self.text_buffer_back.get_selection_bounds()
        path            = self.selected_row.get_selected_rows()[1][0]

        ##### FRONT
        if len(bounds_front) != 0:
            (start,end)        = bounds_front
            selection_front     = self.text_buffer_front.get_text(start,end,True)
            get_insert_front    = self.text_buffer_front.get_insert()

            self.text_buffer_front.apply_tag(tag_front,start,end)

            start_iter_front    = self.text_buffer_front.get_start_iter()
            end_iter_front      = self.text_buffer_front.get_end_iter()
            format              = self.text_buffer_front.register_serialize_tagset()
            exported            = self.text_buffer_front.serialize( self.text_buffer_front,end_iter_front )
            self.dict_any_change_front[str(path)] = exported


        ###### BACK
        if len(bounds_back) != 0:
            (start,end)        = bounds_back
            selection_back      = self.text_buffer_back.get_text(start,True)
            get_insert_back     = self.text_buffer_back.get_insert()

            self.text_buffer_back.apply_tag(tag_back,end)

            start_iter_back     = self.text_buffer_back.get_start_iter()
            end_iter_back       = self.text_buffer_back.get_end_iter()
            format              = self.text_buffer_back.register_serialize_tagset()
            exported            = self.text_buffer_back.serialize(  self.text_buffer_back,end_iter_back )
            self.dict_any_change_back[str(path)] = exported

按我想要的方式工作:)。

修改

我调整了代码以在开始时将所有内容序列化并放在字典中,而不是在字典中放入字符串,也不像编辑文本那样将文本序列化并放入字典中,因此可以删除一些if / else和尝试/例外。

我还创建了对事物进行序列化和反序列化的函数,并将这些函数放在另一个文件中,我认为这种方法更好。

  • myhandlerfile.py:
...

from myfuncfile import serializeIt,deserializeIt

...
        # dictionary to track the tags
        self.dict_any_change_front  =   {str(key): serializeIt(text_buffer=self.text_buffer_front,tmp_string=value[1]) \
                                        for key,value in enumerate(self.sub_list_store)}

        self.dict_any_change_back   =   {str(key): serializeIt(text_buffer=self.text_buffer_back,value in enumerate(self.sub_list_store_back)}

    def item_selected(self,*args):
        #   Silencing a indexerror that will occur in case the window was hided and rised again
        # it is not important,can be ignored

        try:
            path                    = self.selected_row.get_selected_rows()[1][0]

            exported_front          = self.dict_any_change_front[str(path)]
            exported_back           = self.dict_any_change_back[str(path)]

            deserializeIt(self.text_buffer_front,exported_front)
            deserializeIt(self.text_buffer_back,exported_back)

            self.text_buffer_front.connect('changed',text_buffer_front):
        #   Silencing a indexerror that will occur in case the window was hided and rised again
        # it is not important,can be ignored
        try:
            path                                    = self.selected_row.get_selected_rows()[1][0]
            start_iter_front                        = text_buffer_front.get_start_iter()
            end_iter_front                          = text_buffer_front.get_end_iter() 

            self.sub_list_store[path][1]            = text_buffer_front.get_text(start_iter_front,True)

            exported                                = serializeIt(text_buffer=text_buffer_front)
            self.dict_any_change_front[str(path)]   = exported
        except IndexError:
            pass

    def editingCardBack(self,text_buffer_back):
        #   Silencing a indexerror that will occur in case the window was hided and rised again
        # it is not important,can be ignored
        try:
            path                                    = self.selected_row.get_selected_rows()[1][0]
            start_iter_back                         = text_buffer_back.get_start_iter()
            end_iter_back                           = text_buffer_back.get_end_iter() 

            self.sub_list_store_back[path][1]       = text_buffer_back.get_text(start_iter_back,True)

            exported                                = serializeIt(text_buffer=text_buffer_back)
            self.dict_any_change_back[str(path)]    = exported

        except IndexError:
            pass

    def on_toolbar_button_clicked(self,end)

            exported                                = serializeIt(text_buffer=self.text_buffer_front)
            self.dict_any_change_front[str(path)]   = exported


        ###### BACK
        if len(bounds_back) != 0:
            (start,end)

            exported                                = serializeIt(text_buffer=self.text_buffer_back)
            self.dict_any_change_back[str(path)]    = exported
...
  • myfuncfile.py:
...

def serializeIt(text_buffer,tmp_string=None):
    if tmp_string:
        text_buffer.set_text(tmp_string)
        tmp_start_iter  = text_buffer.get_start_iter()
        tmp_end_iter    = text_buffer.get_end_iter()
        tmp_format      = text_buffer.register_serialize_tagset()
        tmp_exported    = text_buffer.serialize( text_buffer,tmp_format,tmp_start_iter,tmp_end_iter )
        return tmp_exported
    else:
        start_iter  = text_buffer.get_start_iter()
        end_iter    = text_buffer.get_end_iter()
        format      = text_buffer.register_serialize_tagset()
        exported    = text_buffer.serialize( text_buffer,start_iter,end_iter )
        return exported

def deserializeIt(text_buffer,exported):
    text_buffer.set_text('')
    text_buffer.deserialize(text_buffer,exported )
...