Как управлять нажатиями клавиш для специальных целей в Gtk # TreeView? - программирование

Как управлять нажатиями клавиш для специальных целей в Gtk # TreeView?

У меня есть сигнал KeyPressed в Gtk #/mono С# для двух разных целей, которые отсутствуют в стандартном TreeView: a) перейдите к следующей ячейке, нажав TAB и b) начать редактирование, нажав любую клавишу.

TreeView прост, он имеет ListStore, показывающий только строки и столбцы, т.е. содержит табличные данные.

Код, который у меня есть, ниже.

[GLib.ConnectBefore]
protected void OnTableKeyPressed(object o, Gtk.KeyPressEventArgs args)
{
    int rowIndex;
    int colIndex;

    // Do not "eat" the key, by default
    args.RetVal = false;

    // Get the current position, needed in both cases.
    this.GetCurrentCell( out rowIndex, out colIndex );

    // Adapt the column
    colIndex += NumFixedColumns;

    if ( args.Event.Key != Gdk.Key.ISO_Enter ) {
        if ( args.Event.Key == Gdk.Key.Tab
          || args.Event.Key == Gdk.Key.ISO_Left_Tab )
        {
            if( args.Event.State == Gdk.ModifierType.ShiftMask ) {
                // Back
                colIndex -= 1;
                if ( colIndex < 1 ) {
                    colIndex = document.Columns;
                    --rowIndex;
                }

                rowIndex = Math.Max( 0, rowIndex );
            } else {
                // Advance
                colIndex += 1;
                if ( colIndex > document.Columns ) {
                    colIndex = 1;
                    ++rowIndex;
                }

                rowIndex = Math.Min( rowIndex, document.Rows );
            }

            this.SetCurrentCell( rowIndex, colIndex );
            args.RetVal = true;                              // Eat the TAB
        } else {
            this.SetCurrentCell( rowIndex, colIndex, true );
        }
    }

    return;
}

У меня есть два вопроса:

  • Как я могу сигнализировать TreeView, что ячейка закончена? Проблема в том, что если вы нажимаете TAB, когда никакая ячейка не редактируется, все работает нормально. Однако, если пользователь редактирует ячейку, содержимое, введенное до сих пор, теряется. Таким образом, в случае, если пользователь редактирует ячейку, я хочу сообщить в TreeView, чтобы закончить выпуск, и продолжить с текущим поведением.

  • Как я могу избежать потери первого ключа при редактировании ячейки? Скажите, что вы находитесь за ячейкой. Вы нажимаете клавиши 1, 2, 3 и 4. Мой обработчик правильно вмешивается и помещает текущую ячейку в режим редактирования. Тем не менее, ячейка получает только 2, 3 и 4, хотя я устанавливаю arg.RetVal в false.

Информация о моих функциях

  • GetCurrentCell(row, col) переводит текущую ячейку из TreePath в пару целых чисел.
  • SetCurrentCell(row, col, [edit]) использует TreeView.SetCursor(), чтобы сделать ток ячейки. edit может быть истинным или ложным. Если true, то ячейка помещается в редакцию. Если оно ложно, ничего не редактируется.
4b9b3361

Ответ 1

Я не эксперт в GTK, на самом деле я никогда с ним не работал. Но я играл со стандартными элементами управления, чтобы обмануть их в нестандартное поведение. Я особенно модифицировал панель меню, которая захватила все входные данные при нажатии клавиши Alt, но мне нужен был ключ Alt в качестве модификатора для различных взаимодействий. Поэтому я могу предложить вам общий совет об обмане вашего TreeView в то, что вам нужно.

Вопрос 1:

Из того, что вы описали, я полагаю, что поведение по умолчанию было бы нажатием Enter для успешного редактирования и оставить ячейку для отмены редактирования. Это может быть приемлемым во многих приложениях. Другие (например, Microsoft Excel) склонны воспринимать редактирование даже при выходе из ячейки. Поэтому я могу понять, что вы хотите этого поведения.

Если такого встроенного поведения нет, вы можете имитировать действие, которое пользователь должен сделать, чтобы сигнализировать TreeView, чтобы закончить редактирование, например. нажмите Enter. Вы можете отправить фальшивое событие Key, используя описанный ниже подход или если GTK построит на WPF, например здесь. Второй подход еще более низкий, поскольку он действительно внедряет фальшивое ключевое событие в очередь событий Windows. Я думаю, это должно работать в любом случае, если ваша платформа - Windows. Но я уверен, что в других операционных системах существуют аналогичные механизмы.

Затем только ПОСЛЕ того, чтобы перевести на следующую ячейку, TreeView получает событие потерянного фокуса, но оно больше не находится в режиме редактирования, и ничего не должно произойти.

Вопрос 2:

Я думаю, что происходит следующее: нажата клавиша, TreeView не находится в режиме редактирования, поэтому игнорирует событие. Вы получаете событие и устанавливаете его в режиме редактирования. Но тогда событие не вернется к TreeView, поэтому никакого ввода больше не будет.

Вы можете попробовать выполнить описанный выше подход и вручную повторно отправить событие ключа. Другой способ - захватить событие раньше, затем, когда TreeView обрабатывает его. В WPF часто бывает событие PreviewOn* (например, см. здесь). так может быть, есть такое событие для вашего контроля?

Вы также можете зацепить себя еще глубже. В WPF есть событие InputManager.Current.PreProcessInput, которое находится чуть выше цикла сообщений Windows и позволяет фильтровать и обрабатывать все виды входов.

Вот мой код, который может вам помочь:

InputManager.Current.PreProcessInput += (sender, e) =>
{
    if (e.StagingItem.Input is MouseButtonEventArgs)
    {
        var earg = (MouseButtonEventArgs)e.StagingItem.Input;
        if (earg.RoutedEvent == Mouse.PreviewMouseDownOutsideCapturedElementEvent)
            OnPreviewMouseDownOutsideCapturedElement(sender, earg);
    }
};

Для более низкоуровневых крючков см. например, question.

Удачи и прокомментируйте, если у вас есть более конкретные вопросы.