【问题标题】:Scrolling to the bottom of the TextView in gtkmm在 gtkmm 中滚动到 TextView 的底部
【发布时间】:2021-02-23 08:30:40
【问题描述】:

布局如下: 有一个Gtk::ScrollWindow,里面是Gtk::TextView,后者是一个名为TextArea的派生类。

作为一个测试,有一个按钮可以在 TextView 中同时添加一些 texgt 并尝试立即滚动到底部。

代码:

void MainWindow::onButtonPress()
{
    Glib::RefPtr<Gtk::TextBuffer::Tag> boldTag = Gtk::TextBuffer::Tag::create();
    boldTag->property_weight()=800;

    textarea->get_buffer()->get_tag_table()->add(boldTag);

    textarea->get_buffer()->insert_with_tag(textarea->get_buffer()->end(), "\ntest text", boldTag);

    auto iter = textarea->get_buffer()->end();
    iter.set_line_offset(0);
    textarea->scroll_to(iter);
}

有趣的是滚动确实发生了,但不是到最后一行,而是到倒数第二行。添加-1 作为偏移量的愚蠢尝试会立即产生错误,因为该值必须为非负数。

【问题讨论】:

    标签: c++ gtk gtk3 gtkmm gtkmm3


    【解决方案1】:

    我相信您的问题是您使用迭代器在插入文本的缓冲区中移动。作为documentation suggests:

    迭代器不是无限期有效的;每当修改缓冲区时 以影响缓冲区中字符数的方式,所有 未完成的迭代器变得无效。

    我建议不要使用迭代器,而是使用 Gtk::TextBuffer::Mark 来引用缓冲区的末尾。与迭代器不同,标记表示:

    缓冲区中的一个位置,在缓冲区修改时保留。

    Gtk::TextView 小部件还具有处理标记的 scroll_to 方法的重载,其中之一是:

    void Gtk::TextView::scroll_to(const Glib::RefPtr< TextBuffer::Mark >& mark,
                                  double within_margin = 0 
                                 )  
    

    您可以在以下简化示例中看到它的实际效果:

    #include <iostream>
    #include <string>
    #include <gtkmm.h>
    
    // Move mark to the right of newly added text (see below):
    constexpr bool RIGHT_GRAVITY = false;
    
    class MyWindow : public Gtk::ApplicationWindow
    {
    
    public:
    
        MyWindow()
        {
            m_button.signal_clicked().connect([this](){OnButtonPressed();});
    
            // Create a mark that "points" to the end of the buffer. This
            // mark will be updated accordinly as the buffer is modified:
            m_endMark = m_textArea.get_buffer()->create_mark(m_textArea.get_buffer()->end(), RIGHT_GRAVITY);
    
            m_scrolledWindow.add(m_textArea);
    
            m_layout.attach(m_scrolledWindow, 0, 0, 1, 1);
            m_layout.attach(m_button, 0, 1, 1, 1);
    
            add(m_layout);
        }
    
        void OnButtonPressed()
        {
            // Insert new line at the end of the Gtk::TextView:
            static int lineNumber = 0;
            m_textArea.get_buffer()->insert(m_textArea.get_buffer()->end(), "\n" + std::to_string(lineNumber) +" - test text");
            ++lineNumber;
    
            // Scroll down to the mark:
            m_textArea.scroll_to(m_endMark);
        }
    
    private:
    
        Gtk::Grid m_layout;
    
        Gtk::ScrolledWindow m_scrolledWindow;
        Gtk::TextView m_textArea;
    
        Glib::RefPtr<Gtk::TextBuffer::Mark> m_endMark;
    
        Gtk::Button m_button{"Add line at the end..."};
    
    };
    
    int main(int argc, char* argv[]) 
    {
        auto app = Gtk::Application::create(argc, argv, "so.question.q66329582");
    
        MyWindow window;
        window.show_all();
    
        return app->run(window);
    }
    

    【讨论】:

    • 效果很好,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-26
    • 2016-01-30
    • 2014-12-12
    • 2016-07-22
    • 1970-01-01
    • 2020-02-11
    • 1970-01-01
    相关资源
    最近更新 更多