如何在 GTK TextView 中自动滚动到底部

问题描述 投票:0回答:2

我在 GTK textview 中发现了奇怪的异常,希望有人能解释一下。

有一个简单的功能可以滚动到窗口底部:

richTextBox.ScrollToIter(richTextBox.Buffer.EndIter, 0, true, 0, 0);

这可能应该在大多数情况下都有效。但有时它会因 MemoryAccessViolation(Linux 中的 SIGSEGV)而导致整个应用程序崩溃

每次我向 TreeView 插入文本时,我的应用程序都会调用此函数,以便我可以始终处于关闭状态(您正在向某个窗口插入文本,并且想要查看最新的文本,例如在聊天中)

文本仅从主线程插入,并且该函数也仅在主线程中调用,因此这与我自己的应用程序中的多线程无关,但是我发现 TextView 与应用程序的其余部分异步渲染文本。就像负责绘制和处理文本的线程实际上不是主线程一样。例如,如果我将大量文本加载到 TextView 中,即使 TextView 以某种方式加载文本,我的应用程序也会响应。

因此,我相信 TextView 实际上正在使用自己的单独线程,并且当我尝试滚动窗口时,该线程正在更改文本。更改的文本会使 iter 无效,因此在将

richTextBox.Buffer.EndIter
传递给 TextView ScrollToBottom 函数的 IL 代码中的某处,文本可能被此外部线程更改并且 iter 无效,这就是我收到此内存访问异常的原因。

这甚至可能是 GTK 中的一个错误,但我使用的是非常稳定的版本(2.1.20),该版本随所有 Mono 版本一起提供,直到 Mono3,甚至适用于所有 Windows gtk# 版本。

有没有其他方法可以“安全”地向下滚动

c# gtk
2个回答
6
投票

这似乎有效:

连接滚动到

SizeAllocated
事件的函数:

this.tv.SizeAllocated += new SizeAllocatedHandler(Scroll2);

创建滚动功能

public void Scroll2(object sender, Gtk.SizeAllocatedArgs e)
{
    tv.ScrollToIter(tv.Buffer.EndIter, 0, false, 0, 0);
}

我不知道它是否正确,但到目前为止它对我来说还没有崩溃,而且渲染完成后它总是滚动到底部


0
投票

在 GtkAda 中,这也适用于 C(可能还有所有其他语言),重要的是使用

Add
函数,而不是 Add_With_Viewport 函数,因为
Add_With_Viewport
将添加一个视口,其中(看来)Gtk.Text_View 不需要,并且在任何情况下,使用视口,滚动命令将不起作用。
我的初始化代码(用例看起来像这样(注意这是 Ada):

终端类型声明(在包规范中):

type Gtk_Terminal_Buffer_Record is new Gtk.Text_Buffer.Gtk_Text_Buffer_Record with record master_fd : Interfaces.C.int; -- <further record elements in here> parent : Gtk.Text_View.Gtk_Text_View; end record; type Gtk_Terminal_Buffer is access all Gtk_Terminal_Buffer_Record'Class; -- Other declarations in here as required type Gtk_Terminal_Record is new Gtk.Scrolled_Window.Gtk_Scrolled_Window_Record with record terminal : Gtk.Text_View.Gtk_Text_View; buffer : Gtk_Terminal_Buffer; -- <other record elements for it go in here> end record;

其初始化代码(在包体中):

procedure Initialize (the_terminal : access Gtk_Terminal_Record'Class) is begin Gtk.Scrolled_Window.Initialize(Gtk_Scrolled_Window(the_terminal)); Gtk.Text_View.Gtk_New(view => the_terminal.terminal); Gtk_New(the_terminal.buffer); Gtk.Text_View.Set_Buffer(view => the_terminal.terminal, buffer => the_terminal.buffer); the_terminal.buffer.parent := the_terminal.terminal; -- Other code in here Add(the_terminal, the_terminal.terminal); end Initialize;

就我而言,我发现这个特定的应用程序最好在有传入字符时调用“滚动到底部”操作,命令如下:

procedure Process(the_input : in UTF8_String; for_buffer : Gtk_Terminal_Buffer) is cursor_mark: Gtk.Text_Mark.Gtk_Text_Mark; begin -- <other commands in here> -- Scroll if required to make it visible cursor_mark := Get_Insert(for_buffer); Scroll_Mark_Onscreen(for_buffer.parent, cursor_mark); end Process;

© www.soinside.com 2019 - 2024. All rights reserved.