2016-08-07 5 views
4

У меня возникли проблемы с управлением вставляемым текстовым сигналом, выпущенным виджлетом Gtk.Entry. Рассмотрим следующий пример:Gtk 3-позиционный атрибут на вставке-текстовый сигнал от Gtk.Entry всегда 0

from gi.repository import Gtk 

def on_insert_text(entry, new_text, new_text_length, position): 
    print(position) 

entry = Gtk.Entry() 
entry.connect('insert-text', on_insert_text) 

window = Gtk.Window() 
window.connect("destroy", lambda q: Gtk.main_quit()) 
window.add(entry) 
window.show_all() 
Gtk.main() 

Положение атрибута Я получаю от обработчика сигналов всегда равен 0. Если меня не недоразумение это должно не быть положение, в котором следующий текст должен быть вставлен?

В конце концов, я хочу, чтобы подтвердить ввод текста в виджет, чтобы ограничить символы, которые будут приняты. Способ, которым я планирую это сделать, аналогичен примеру, представленному в документации, в которой все символы преобразуются в верхний регистр.

+0

Просто запустил ваш код. Я также получил эту проблему, но если вам действительно нужна позиция, просто используйте 'entry.get_position()'. К какому примеру в документации вы ссылаетесь на этот путь? – B8vrede

+0

В описании класса Gtk.Editable имеется ссылка на сигнал «insert-text» и пример возможного обработчика для этого сигнала. В документах текст преобразуется в нижний регистр, в моем случае я бы проверял его на регулярное выражение и решал, нужно ли вставлять или нет, но структура обработчика будет точно такой, как показано на рисунке. Кстати, 'entry.get_posisition()' делает работу, я думаю, поэтому я, вероятно, буду ее использовать. –

+0

Я думаю, что поведение, которое мы видим, связано с тем, что привязки python не обрабатывают все правильно. Когда вы запустили мой примерный код выше, вы также получили следующее предупреждение? 'Предупреждение: g_value_get_int: assertion 'G_VALUE_HOLDS_INT (значение)' failed Gtk.main()' –

ответ

6

Ожидается, что обработчик «insert-text» обновит значение, полученное в параметре позиции (которое мы видели неверно), чтобы отразить позицию, из которой должен быть вставлен будущий текст, и вернуть его. Это важно, чтобы курсор был изменен в нужное место после возврата обработчика сигнала (это делается gtk). Если вы не обновляете и не возвращаете, курсор остается в позиции 0.

После того, как вы предложили использовать entry.get_position(), чтобы получить правильное значение позиции, я узнал, что обновление и возврат позиции в моем обработчике игнорируется pygobject. Он вел себя так, как будто я ничего не возвращал (курсор остался в позиции 0). Установка позиции внутри обработчика не помогла, потому что gtk изменит ее обратно на 0 после возврата обработчика.

После некоторого дальнейшего исследования я узнал, что проблема заключается с обработкой в ​​/ из параметров в pygobject, который хорошо работает в большинстве случаев, но не с сигналами (см bug 644927)

Если вы используете подключение к прикрепить обработчик сигнала, а сигнал имеет параметр ввода/вывода, который может не получить то, что вы ожидаете от обработчика, и даже если вы вернете значение, это значение, вероятно, не будет корректно обрабатываться pygobject. Все, что зависит от этого значения, вероятно, не работает должным образом (например, переместить курсор в новое положение)

Существует решение, хотя, который должен отменить связанный с ним vfunc (обработчик по умолчанию) вместо того, чтобы соединяться с connect(). Это решение подразумевает получение базового класса, но оно действительно работает.

Вы можете использовать этот метод для проверки/преобразования входных данных на Gtk.Entry. Пример обработки мой случай использования будет:

import re 
import gi 
gi.require_version('Gtk', '3.0') 
from gi.repository import Gtk 


class MyEntry(Gtk.Entry, Gtk.Editable): 

    def __init__(self): 
     super(MyEntry, self).__init__() 

    def do_insert_text(self, new_text, length, position): 
     regexp = re.compile('^(\d*\.?\d*)$') 

     if new_text == '.' and '.' in self.get_text(): 
      return position 
     elif regexp.match(new_text) is not None: 
      self.get_buffer().insert_text(position, new_text, length) 
      return position + length 

     return position 

entry = MyEntry() 
window = Gtk.Window() 
window.connect("destroy", lambda q: Gtk.main_quit()) 
window.add(entry) 
window.show_all() 

Gtk.main() 

В этом случае параметр позиции принят правильно и возвращаемое значение рассматривается и используется pygobject поэтому курсор правильно.

Важное примечание Вы должны наследовать от Gtk.Editable в дополнение к Gtk.Entry. Если вы этого не сделаете, вы начнете видеть валидацию или все, что вы делаете внутри do_insert_text, применяя к любой другой Gtk.Entry в своем приложении. Если вы не наследуете, вы переопределяете базовую реализацию, предоставляемую Gtk.Editable, которая вызывается всеми другими Gtk.Entry виджетами в вашем приложении. Наследуя от Gtk.Editable, вы переопределяете только «local» копию базовой реализации, которая применяется только к вашему пользовательскому классу.