Редактирование NSTableView и NSOutlineView с помощью клавиши табуляции - PullRequest
6 голосов
/ 09 апреля 2011

У моего приложения NSOutlineView и NSTableView, и у меня одна и та же проблема с обоими. Когда строка выбрана, нажатие клавиши табуляции переводит первый столбец в режим редактирования вместо того, чтобы следующий респондент просматривал следующий ключ. Чтобы перейти к следующему ключевому представлению, вам нужно просмотреть все столбцы.

Кроме того, вкладка Shift в любом из представлений приводит к переходу столбца last в режим редактирования, что требует большего количества клавиш Shift для перехода в его предыдущее представление ключа.

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

Обновление

Благодаря полезным ответам ниже, я решил это. По сути, я переопределяю -keyDown в своем пользовательском классе табличного представления, который обрабатывает табулирование и сдвиг табуляции из табличного представления. Однако было сложнее решить табуляцию в представлении таблицы. Я установил логическое свойство YES в пользовательском табличном представлении -acceptsFirstResponder, если оно принимает управление из другого представления.

Делегат -tableView:shouldEditTableColumn:row проверяет это, когда текущее событие является событием Shift-Tab keyDown. Вызывается -tableView:shouldEditTableColumn:row, и это не событие shift-tab, оно устанавливает свойство табличного представления обратно в NO, поэтому его можно редактировать как обычно.

Я вставил полное решение ниже.

/* CustomTableView.h */

@interface CustomTableView : NSTableView {}

@property (assign) BOOL justFocused;

@end

/* CustomTableView.m */

@implementation CustomTableView

@synthesize justFocused;

- (BOOL)acceptsFirstResponder {
    if ([[self window] firstResponder] != self) {
        justFocused = YES;
    }

    return YES;
}

- (void)keyDown:(NSEvent *)theEvent
{
    // Handle the Tab key
    if ([[theEvent characters] characterAtIndex:0] == NSTabCharacter) {
        if (([theEvent modifierFlags] & NSShiftKeyMask) != NSShiftKeyMask) {
            [[self window] selectKeyViewFollowingView:self];
        } else {
            [[self window] selectKeyViewPrecedingView:self];
        }
    }
    else {
        [super keyDown:theEvent];
    }
}

@end

/* TableViewDelegate.m */

. . .

- (BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)tableColumn
              row:(NSInteger)row
{
    NSEvent *event = [NSApp currentEvent];
    BOOL shiftTabbedIn = ([event type] == NSKeyDown
                          && [[event characters] characterAtIndex:0] == NSBackTabCharacter);

    if (shiftTabbedIn && ((CustomTableView *)tableView).justFocused == YES) {
        return NO;
    } else {
        ((CustomTableView *)tableView).justFocused = NO;
    }

    return YES;
}

. . .

Ответы [ 5 ]

7 голосов
/ 09 апреля 2011

Это поведение по умолчанию. Если строка не выбрана, то табличное представление в целом имеет фокус, и клавиша Tab переключается на следующий ключевой вид. Если выбрана строка, табличное представление начинает редактирование или перемещается в следующую ячейку, если оно уже редактируется.

Из Замечания к выпуску AppKit :

Таблицы теперь поддерживают межячейки навигация следующим образом:

  • Вкладка вперед к столу фокусирует всю таблицу.
  • Нажатие на пробел попытается выполнить «executeClick:» на NSButtonCell в выбранная строка, если есть только одна экземпляр в этом ряду.
  • Вкладка снова фокусирует первую «фокусируемую» (1) ячейку, если она есть.
  • Если вновь выделенную ячейку можно редактировать, редактирование начнется.
  • Нажатие пробела вызывает 'executeClick:' в ячейке и устанавливает источник данных. значение после, если изменилось. (2)
  • Если текстовая ячейка редактируется, нажатие Enter приведет к редактированию и фокусировке будет возвращен в таблицу, и Tab / Shift-tab совершит редактирование а затем выполнить новую вкладку цикла поведение.
  • Вкладка будет перемещаться только через одну строку
  • Как только будет достигнута последняя ячейка в строке, вкладка переместится на следующий фокусируемый элемент управления.
  • При заднем вкладке в таблицу будет выбрана последняя фокусируемая ячейка.

Если вы хотите изменить это поведение, может быть полезен метод делегата tableView:shouldEditTableColumn:row:. Вам также может понадобиться создать подкласс NSTableView, если вы действительно хотите повлиять только на поведение клавиши Tab.

2 голосов
/ 09 апреля 2011

Мне тоже приходилось иметь дело с этим раньше. Мое решение состояло в том, чтобы создать подкласс NSTableView или NSOutlineView и переопределить keyDown:, чтобы отлавливать нажатия клавиш табуляции и затем действовать на них.

0 голосов
/ 13 ноября 2018

Решение, использующее keyDown, не сработало для меня.Возможно, потому что это для табличного представления на основе ячеек.

Мое решение для табличного представления на основе представления в Swift выглядит так:

extension MyTableView: NSTextFieldDelegate {
    func controlTextDidEndEditing(_ obj: Notification) {
        guard
            let view = obj.object as? NSView,
            let textMovementInt = obj.userInfo?["NSTextMovement"] as? Int,
            let textMovement = NSTextMovement(rawValue: textMovementInt) else { return }

        let columnIndex = column(for: view)
        let rowIndex = row(for: view)

        let newRowIndex: Int
        switch textMovement {
        case .tab:
            newRowIndex = rowIndex + 1
            if newRowIndex >= numberOfRows { return }
        case .backtab:
            newRowIndex = rowIndex - 1
            if newRowIndex < 0 { return }
        default: return
        }

        DispatchQueue.main.async {
            self.editColumn(columnIndex, row: newRowIndex, with: nil, select: true)
        }
    }
}

Вам также необходимо установить cell.textField.delegate так что реализация работает.

Мой пост в блоге об этом сложном обходном пути: https://samwize.com/2018/11/13/how-to-tab-to-next-row-in-nstableview-view-based-solution/

0 голосов
/ 06 января 2013

Это сработало для меня:

- (BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
  NSEvent *e = [NSApp currentEvent];
  if (e.type == NSKeyDown && e.keyCode == 48) return NO;
  return YES;
}
0 голосов
/ 10 апреля 2011

Как удобно!Я сам только вчера смотрел на это, и приятно видеть какое-то подтверждение подхода, который я выбрал - keyDown: обработка.

Однако у меня есть одно небольшое возможное уточнение вашего подхода: я решил, чтометодом, вызывающим редактирование при возврате к таблице обратно, был вызов becomeFirstResponder.Итак, что я сделал для подкласса NSTableView:

  1. Добавить синтезированное свойство, чтобы контролировать, было ли отключено редактирование табуляции
  2. В случае нажатия клавиш проверьте первый символ (также проверьте [[theEvent characters] length], чтобы избежать исключений для мертвых ключей!) Для вкладки;если редактирование вкладок отключено, перейдите к следующему / предыдущему представлению в соответствии с примером кода.
  3. Переопределить becomeFirstResponder:
    - (BOOL)becomeFirstResponder {
        if (tabEditingDisabled) {
            [self display];
            return YES;
        }
        return [super becomeFirstResponder];
    }

При этом весь код остается вподкласс tableview, обеспечивающий чистоту делегата:)

Единственная опасность в том, что я не знаю, что еще делает NSTableView в intoFirstResponder;Я ничего не заметил, но ...

...