我一直致力于编写故事的文本编辑器。我正在使用 Python、GTK+ 3 和 GtkSourceView 3。编辑器的要点是折叠某些区域。虽然没有 - 还没有?- 在 GTK TextView / SourceView 中内置对折叠的支持,我一直在使用带有 invisible=True 的标签和 SourceView 的源标记来实现该功能。
此处提供源代码:https ://github.com/mkoskim/mawe
核心编辑器(SourceBuffer 和 SourceView)位于:https ://github.com/mkoskim/mawe/blob/master/gui/gtk/SceneView.py https://github.com/mkoskim/mawe/blob/master /gui/gtk/SceneBuffer.py
出于测试目的,您可以克隆存储库,并使用以下命令运行应用程序:
mawe$ ./mawe.py test/test.txt
现在,应用程序不断频繁地随机崩溃,出现如下错误:
(mawe.py:10556): Gtk-WARNING **: /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gtk/gtktextbtree.c:4034: byte index off the end of the line
(mawe.py:10556): Gtk-ERROR **: Byte index 1362 is off the end of the line
Trace/breakpoint trap
没有其他错误或警告日志。我一直在谷歌搜索错误没有任何成功。
其他症状似乎是:
即使编辑器处于空闲状态,也会发生崩溃
今天我发现奇怪的是,我可以通过将鼠标移到隐藏部分上来非常快地崩溃:o
我不能 100% 确定,但我认为这与不可见区域有关。
问题:有没有人碰巧知道这是否是一些已知的错误?
问题:有没有人有任何想法可以让我寻找可能的解决方案?有什么想法会导致崩溃,以及我可以更深入地探索什么?
更新:我用标签做了一些更广泛的测试。似乎没有其他属性对鼠标移动做出反应,但是当打开不可见性时,鼠标在区域上移动会使应用程序崩溃。我一直在搜索报告鼠标事件崩溃 gtktextbtree,但到目前为止没有成功。看起来这适用于几个 v3.x GTK 版本。
更新:我想我几乎找到了解决方法:从 GtkSource.View 过滤掉运动通知事件似乎有效,如下所示:
def filter_event(widget, event, *args):
# Allow these
if event.type == Gdk.EventType.KEY_PRESS: return False
if event.type == Gdk.EventType.KEY_RELEASE: return False
# Block these
if event.type == Gdk.EventType.LEAVE_NOTIFY: return True
if event.type == Gdk.EventType.MOTION_NOTIFY: return True
# Print & allow the rest
print(event)
return False
self.text.connect("event", filter_event)
如果您在隐藏线附近按下鼠标按钮,应用程序仍然会崩溃,但似乎它不再因鼠标移动而崩溃。
更新:更多调查。虽然阻止鼠标事件可以防止崩溃,但它也会导致怪癖,例如无法使用鼠标放置光标、选择区域、DnD、... 此外,鼠标光标可能会消失,因为它不是每次都正确更新。我很确定将鼠标/窗口坐标转换为缓冲区位置的算法存在错误(当文本中有较大的隐藏块时),因此任何鼠标事件都可能使应用程序崩溃。
更新:我一直在尝试为该主题创建简单的测试用例。好事:隐藏似乎奏效了。坏事:还不能重现问题。测试脚本可以在这里找到:
https://github.com/mkoskim/mawe/blob/master/gui/gtk/test/hidecrash/hidecrash.py
更新:试图弄清楚 - 测试用例有效,编辑器不起作用。测试用例的区别至少在于编辑器将隐藏标签放入事件循环(*)中。试图为此做一个测试用例......
(*) 使用当前的 Gtk SourceView/TextView 实现折叠肯定有很多不同的解决方案。我选择了使用“标记”语言并在编辑时应用折叠的方法,因为它适用于撤消/重做。我还尝试了其他解决方案,例如:
剪切折叠场景并将小部件插入到文本缓冲区,包含文本本身。想法:“文本[选择用于折叠的部分]文本”->“文本[锚+带有剪切文本的小部件]文本”-遗憾的是,它不适用于撤消/重做。
剪切文本,给它一个 ID,然后在缓冲区中放置一个包含 ID 的特殊标记部分。想法“文本[选择用于折叠的部分]文本”->“文本[ID w/隐藏+受保护标签]文本”-不起作用,因为剪切'n'粘贴或撤消/重做不应用标签,所以用户可以销毁标记。
普通标记:尝试使用折叠指示器保持标记非常困难。您需要带有受保护标签的“[char][mark][char]”之类的东西,以确保您不会在某处丢失标记。
无论如何,我会继续调查。
更新:仍然无法在我的测试脚本中重现该问题,但发现了一些可能有趣的东西:折叠最后一个场景不会导致崩溃 - 仅在折叠跟随另一个场景(折叠或未折叠)的场景时。