C “GtkTextBuffer”;标记“U集”;信号为箭头键或鼠标单击触发回调3-4次
我正试图使用C “GtkTextBuffer”;标记“U集”;信号为箭头键或鼠标单击触发回调3-4次,c,gtk2,C,Gtk2,我正试图使用'mark\u set'信号更新我的GtkTextBuffer中的行:列值。对于测试,我有一个简单的设置,在一个滚动窗口内的一个窗口内设置textview,例如: 我使用一个结构来保存应用程序的各种值,例如: typedef struct { GtkWidget *window; GtkWidget *view; GtkTextBuffer *buffer; GtkTextMark *cursor; gint line; gint co
'mark\u set'
信号更新我的GtkTextBuffer中的行:列
值。对于测试,我有一个简单的设置,在一个滚动窗口内的一个窗口内设置textview,例如:
我使用一个结构来保存应用程序的各种值,例如:
typedef struct {
GtkWidget *window;
GtkWidget *view;
GtkTextBuffer *buffer;
GtkTextMark *cursor;
gint line;
gint col;
gint winwidth;
gint winheight;
} context;
我正在尝试更新应用程序用于跟踪缓冲区中的行和列位置的struct实例中的当前line
和col
值。在create_window函数中,我初始化context*app的值
(在main()
中定义)并将'mark\u set'
信号连接到\u mark\u set()回调上的,将结构实例作为数据传递给回调。e、 g:
g_signal_connect (app->buffer, "mark_set",
G_CALLBACK (on_mark_set), app);
_mark_set()
回调上的是:
app->line
和app->col
的值在向缓冲区提供输入的每个按键后正确设置(仅一次)。e、 g.在文本视图中输入'abc'
,结果如下:
$ ./bin/text_mcve
line: 1 col: 2
line: 1 col: 3
line: 1 col: 4
但是,当我使用箭头键
移动输入光标或使用鼠标
重新定位输入光标时,会触发三重或四重回调。e、 g.按左箭头备份一个位置,结果如下:
line: 1 col: 3
line: 1 col: 3
line: 1 col: 3
通过单击鼠标重新定位到末端,将导致回调的四次触发:
line: 1 col: 4
line: 1 col: 4
line: 1 col: 4
line: 1 col: 4
无论是否输入数据或是否使用箭头键或鼠标移动光标,如何将\u mark\u set()
回调的执行限制为单个调用?考虑到“mark\u set”
是唯一可以覆盖输入的信号->光标位置处理,无论定位输入是来自按键还是鼠标单击。我们的目标是利用'mark_set'
信号来处理所有行:列
更新,但我必须找到一种方法来防止每次按键或鼠标单击事件触发回调不止一次
在textview小部件中使用'key\u press\u event'
时,您可以传递create a gboolean回调和GdkEventKey,并手动处理事件->keyval
以使用键盘(包括箭头键)处理光标重新定位,通过return
告诉默认的输入处理程序,不需要对任何给定的按键执行进一步的操作,但这不需要,也不能使用鼠标单击。因此,如果我能通过'mark\u set'
信号完成这一切,那将是我的选择
有什么方法可以对'mark\u set'
事件执行相同的操作,以确保on\u mark\u set()
回调只执行一次,而不考虑按键或鼠标单击?我已发布到gtk应用程序开发列表,但尚未收到回复。S.O.在gtk主题上可能比gtk列表本身更活跃。如果您能帮助解决这个难题,我们将不胜感激
用于测试的MCVE
下文提供了用于测试目的的MCVE。使用gcc-oprogname progname.c$(pkg config--cflags--libs gtk+-2.0)编译
知道当前的line:col
值后,就可以与新的line:col
值进行比较,新的line:col
值将基于GtkTextIter*iter
值作为参数传递给on_mark_set()
回调。这提供了当前值与新值的简单比较,允许您仅响应导致行:col
值发生变化的标记集
信号:
void on_mark_set (GtkTextBuffer *buffer, GtkTextIter *iter,
GtkTextMark *mark, context *app)
{
gint line, col;
line = gtk_text_iter_get_line (iter);
col = gtk_text_iter_get_line_offset (iter);
if (line == app->line && col == app->col) return;
app->line = line;
app->col = col;
g_print (" line: %3d col: %d\n", app->line + 1, app->col + 1);
if (mark) {}
}
(注意:调试g_print
语句留在上面,为下面的输出提供上下文)进一步注意,mark
和gtk_text_buffer_get_insert(buffer)
之间的比较无法进行,因为gtk_text_buffer_get_insert(buffer)
仅在进行箭头键或鼠标单击输入时返回匹配值。(对于正常文本输入,比较失败)
现在,当重复原始问题中记录的相同事件序列时(例如,输入'abc'
,然后用左箭头备份1,然后在末尾左键单击以重新定位光标),显示标记集上的现在只正确响应更新的行:col
值:
void on_mark_set (GtkTextBuffer *buffer, GtkTextIter *iter,
GtkTextMark *mark, context *app)
{
gint line, col;
line = gtk_text_iter_get_line (iter);
col = gtk_text_iter_get_line_offset (iter);
if (line == app->line && col == app->col) return;
app->line = line;
app->col = col;
g_print (" line: %3d col: %d\n", app->line + 1, app->col + 1);
if (mark) {}
}
输出
$ ./bin/text_mcve
line: 1 col: 2
line: 1 col: 3
line: 1 col: 4
line: 1 col: 3
line: 1 col: 4
Exiting... buffer contained:
abc
每个iter
位置都有多个标记,没有特定顺序
为了让这些问题成为一个好的参考,如果不是一个好的解决方案,我将在本主题中包含进一步调试的结果。在其他任何地方都找不到关于这个特定主题的信息
进一步的调试说明了为什么在这方面存在困难,以及为什么不能单独使用标记
和gtk_文本_缓冲区_获取_插入(缓冲区)
之间的简单比较来确定是否响应“标记_设置”
信号。为什么?
每次生成“标记设置”
信号时,在任何给定的iter
位置都可能有多个标记。在正常输入的情况下(例如,'a'
,'b'
等),传递到上的标记不一定是“insert”
标记,但显然是iter位置上存在的最后一个标记。(在匿名标记下方的每种情况下)任何给定iter
位置的标记列表可通过gtk\u text\u iter\u get\u marks(iter)
返回的GSList
标记找到。(注意:返回列表中的标记没有特定顺序——这可能是整个问题的基础。请参阅:)例如,您可以使用以下调试代码检查标记:<
GtkTextIter iterfirst;
...
app->cursor = gtk_text_buffer_get_insert (app->buffer);
gtk_text_buffer_get_iter_at_mark (app->buffer, &iterfirst, app->cursor);
app->line = gtk_text_iter_get_line (&iterfirst);
app->col = gtk_text_iter_get_line_offset (&iterfirst);
void on_mark_set (GtkTextBuffer *buffer, GtkTextIter *iter,
GtkTextMark *mark, context *app)
{
gint line, col;
line = gtk_text_iter_get_line (iter);
col = gtk_text_iter_get_line_offset (iter);
if (line == app->line && col == app->col) return;
app->line = line;
app->col = col;
g_print (" line: %3d col: %d\n", app->line + 1, app->col + 1);
if (mark) {}
}
$ ./bin/text_mcve
line: 1 col: 2
line: 1 col: 3
line: 1 col: 4
line: 1 col: 3
line: 1 col: 4
Exiting... buffer contained:
abc
void on_mark_set (GtkTextBuffer *buffer, GtkTextIter *iter,
GtkTextMark *mark, context *app)
{
gint line, col;
#ifdef DEBUG
g_print (" mark: %p - gtbgi (buffer): %p mark->name: %s\n", mark,
gtk_text_buffer_get_insert (buffer),
gtk_text_mark_get_name (mark));
GSList *marks = gtk_text_iter_get_marks (iter);
GSList *p = marks;
gint i = 0;
while (p) {
const gchar *name = gtk_text_mark_get_name (GTK_TEXT_MARK(p->data));
g_print (" mark[%d] : %p : %s\n", i++, GTK_TEXT_MARK(p->data), name);
p = p->next;
}
g_slist_free (marks);
#endif
line = gtk_text_iter_get_line (iter);
col = gtk_text_iter_get_line_offset (iter);
if (line == app->line && col == app->col) return;
app->line = line;
app->col = col;
#ifdef DEBUG
g_print (" line: %3d col: %d\n\n", app->line + 1, app->col + 1);
#endif
if (mark) {}
}
$ ./bin/text_mcve_dbg
mark: 0x2458880 - gtbgi (buffer): 0x237d600 mark->name: (null)
mark[0] : 0x237d600 : insert
mark[1] : 0x237d620 : selection_bound
mark[2] : 0x237d7a0 : gtk_drag_target
mark[3] : 0x2458880 : (null)
line: 1 col: 2
mark: 0x24792c0 - gtbgi (buffer): 0x237d600 mark->name: (null)
mark[0] : 0x237d600 : insert
mark[1] : 0x237d620 : selection_bound
mark[2] : 0x237d7a0 : gtk_drag_target
mark[3] : 0x24792c0 : (null)
line: 1 col: 3
mark: 0x24797a0 - gtbgi (buffer): 0x237d600 mark->name: (null)
mark[0] : 0x237d600 : insert
mark[1] : 0x237d620 : selection_bound
mark[2] : 0x237d7a0 : gtk_drag_target
mark[3] : 0x24797a0 : (null)
line: 1 col: 4
mark: 0x237d600 - gtbgi (buffer): 0x237d600 mark->name: insert
mark[0] : 0x237d600 : insert
mark[1] : 0x237d620 : selection_bound
line: 1 col: 3
mark: 0x237d620 - gtbgi (buffer): 0x237d600 mark->name: selection_bound
mark[0] : 0x237d600 : insert
mark[1] : 0x237d620 : selection_bound
mark: 0x2479700 - gtbgi (buffer): 0x237d600 mark->name: (null)
mark[0] : 0x237d600 : insert
mark[1] : 0x237d620 : selection_bound
mark[2] : 0x2479700 : (null)
mark: 0x237d600 - gtbgi (buffer): 0x237d600 mark->name: insert
mark[0] : 0x237d7a0 : gtk_drag_target
mark[1] : 0x237d600 : insert
mark[2] : 0x237d620 : selection_bound
line: 1 col: 4
mark: 0x237d620 - gtbgi (buffer): 0x237d600 mark->name: selection_bound
mark[0] : 0x237d7a0 : gtk_drag_target
mark[1] : 0x237d600 : insert
mark[2] : 0x237d620 : selection_bound
mark: 0x24792a0 - gtbgi (buffer): 0x237d600 mark->name: (null)
mark[0] : 0x237d7a0 : gtk_drag_target
mark[1] : 0x237d600 : insert
mark[2] : 0x237d620 : selection_bound
mark[3] : 0x24792a0 : (null)
mark: 0x2479200 - gtbgi (buffer): 0x237d600 mark->name: (null)
mark[0] : 0x237d7a0 : gtk_drag_target
mark[1] : 0x237d600 : insert
mark[2] : 0x237d620 : selection_bound
mark[3] : 0x2479200 : (null)
mark[4] : 0x24792a0 : (null)
void user_function (GtkTextBuffer *textbuffer, GtkTextIter *location,
GtkTextMark *mark, gpointer user_data)