Клавиши со стрелками с NSTableView

Один метод является коррелированным подзапросом:

select t.*
from t
order by (select max(t2.publish_date)
          from t t2
          where t2.author = t.author
         );

MySQL 8+ (и стандартный SQL) имеет гораздо более простой метод с использованием оконных функций:

select t.*
from t
order by max(publish_date) over (partition by author)
11
задан dreamlax 4 March 2009 в 22:43
поделиться

4 ответа

Хорошо это не легко, но мне удалось сделать это, не имея необходимость использовать RRSpreadSheet или даже другое управление. Вот то, что необходимо сделать:

  1. Создайте подкласс NSTextView, это будет полевым редактором. Для этого примера имя MyFieldEditorClass будет использоваться и myFieldEditor будет относиться к экземпляру этого класса.

  2. Добавьте метод к MyFieldEditorClass названный"- (void) setLastKnownColumn:(unsigned)aCol andRow:(unsigned) aRow"или что-то подобное, и имеет его, сохраняют обоих входные значения параметров где-нибудь.

  3. Добавьте другой метод, названный "setTableView": и имейте его, сохраняют объект NSTableView где-нибудь, или если нет другой способ получить объект NSTableView от полевого редактора, используйте это.

  4. Добавьте другой названный метод - (void) keyDown:(NSEvent *) event. Это на самом деле переопределяет NSResponder keyDown:. Исходный код должен быть (знать, что MarkDown StackOverflow изменяется < и > кому: &lt; и &gt;):

    - (void) keyDown:(NSEvent *) event
    {
        unsigned newRow = row, newCol = column;
        switch ([event keyCode])
        {
            case 126: // Up
                if (row)
                newRow = row - 1;
                break;
    
            case 125: // Down
                if (row < [theTable numberOfRows] - 1)
                    newRow = row + 1;
                break;
    
            case 123: // Left
                if (column > 1)
                    newCol = column - 1;
                break;
    
            case 124: // Right
                if (column < [theTable numberOfColumns] - 1)
                    newCol = column + 1;
                break;
    
            default:
                [super keyDown:event];
                return;
        }
    
        [theTable selectRow:newRow byExtendingSelection:NO];
        [theTable editColumn:newCol row:newRow withEvent:nil select:YES];
        row = newRow;
        column = newCol;
    }
    
  5. Дайте NSTableView в Вашем пере, делегат, и в делегате добавляет метод:

    - (BOOL) tableView:(NSTableView *)aTableView shouldEditColumn:(NSTableColumn *) aCol row:aRow
    {
        if ([aTableView isEqual:TheTableViewYouWantToChangeBehaviour])
            [myFieldEditor setLastKnownColumn:[[aTableView tableColumns] indexOfObject:aCol] andRow:aRow];
        return YES;
    }
    
  6. Наконец, дайте главному окну Табличного представления делегата и добавьте метод:

    - (id) windowWillReturnFieldEditor:(NSWindow *) aWindow toObject:(id) anObject
    {
        if ([anObject isEqual:TheTableViewYouWantToChangeBehaviour])
        {
            if (!myFieldEditor)
            {
                myFieldEditor = [[MyFieldEditorClass alloc] init];
                [myFieldEditor setTableView:anObject];
            }
            return myFieldEditor;
        }
        else
        {
            return nil;
        }
    }
    

Запустите программу и дайте ей движение!

4
ответ дан 3 December 2019 в 08:05
поделиться

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

1
ответ дан 3 December 2019 в 08:05
поделиться

В Sequel Pro мы использовали другой (и, на мой взгляд, более простой) метод: мы реализовали control: textView: doCommandBySelector: в делегат TableView. Этот метод трудно найти - его можно найти в Справочнике по протоколу NSControlTextEditingDelegate . (Помните, что NSTableView является подклассом NSControl)

Короче говоря, вот что мы придумали (мы не переопределяли клавиши со стрелками влево / вправо, поскольку они используются для навигации внутри ячейки. Мы используем Tab для перехода left / right)

Обратите внимание, что это всего лишь фрагмент исходного кода Sequel Pro, и он не работает как

- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command
{
    NSUInteger row, column;

    row = [tableView editedRow];
    column = [tableView editedColumn];

    // Trap down arrow key
    if (  [textView methodForSelector:command] == [textView methodForSelector:@selector(moveDown:)] )
    {
        NSUInteger newRow = row+1;
        if (newRow>=numRows) return TRUE; //check if we're already at the end of the list
        if (column>= numColumns) return TRUE; //the column count could change

        [tableContentView selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
        [tableContentView editColumn:column row:newRow withEvent:nil select:YES];
        return TRUE;
    }

    // Trap up arrow key
    else if (  [textView methodForSelector:command] == [textView methodForSelector:@selector(moveUp:)] )
    {
        if (row==0) return TRUE; //already at the beginning of the list
        NSUInteger newRow = row-1;

        if (newRow>=numRows) return TRUE;
        if (column>= numColumns) return TRUE;

        [tableContentView selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
        [tableContentView editColumn:column row:newRow withEvent:nil select:YES];
        return TRUE;
    }
9
ответ дан 3 December 2019 в 08:05
поделиться

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

В любом случае, я видел несколько ответов на переопределение события -keyDown в табличном представлении, в которых говорится о создании подкласса TableView, но, согласно каждой книге по Objective-C, которую я читал до сих пор, и нескольким обучающим видео Apple, вы должен очень редко, если вообще когда-либо, создавать подкласс одного из основных классов. Фактически, каждый из них подчеркивает, что программисты на C увлекаются созданием подклассов, а Objective-C работает не так; что Objective-C - это помощники и делегаты, а не подклассы.

Итак, должен ли я просто игнорировать любые ответы, которые говорят о подклассе, поскольку это, кажется, прямо противоречит предписаниям Objective-C?

--- Изменить ---

Я нашел кое-что, что работал без подкласса NSTableView. Хотя я перемещаю наследование на одну ступеньку выше в цепочке от NSObject к NSResponder, я не делаю полностью подкласс NSTableView. Я просто добавляю возможность переопределить событие keyDown.

Я сделал класс, который использовал в качестве делегата, наследованием от NSResponder вместо NSObject, и установил nextResponder для этого класса в awakeFromNib. Затем я смог улавливать нажатия клавиш с помощью события keydown. Я, конечно, подключил IBOutlet и установил делегата в Interface Builder.

Вот мой код с минимумом, необходимым для отображения захвата ключа:

Заголовочный файл

//  AppController.h

#import <Cocoa/Cocoa.h>

@interface AppController : NSResponder {

    IBOutlet NSTableView *toDoListView;
    NSMutableArray *toDoArray;
}

-(int)numberOfRowsInTableView:(NSTableView *)aTableView;

-(id)tableView:(NSTableView *)tableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
           row:(int)rowIndex;

@end

Вот m-файл.

//  AppController.m
#import "AppController.h"

@implementation AppController

-(id)init
{
    [super init];
    toDoArray = [[NSMutableArray alloc] init];
    return self;
}

-(void)dealloc
{
    [toDoArray release];
    toDoArray = nil;
    [super dealloc];
}

-(void)awakeFromNib
{
    [toDoListView setNextResponder:self];
}

-(int)numberOfRowsInTableView:(NSTableView *)aTableView
{
    return [toDoArray count];
}

-(id)tableView:(NSTableView *)tableView
    objectValueForTableColumn:(NSTableColumn *)aTableColumn
                          row:(int)rowIndex
{
    NSString *value = [toDoArray objectAtIndex:rowIndex];
    return value;
}

- (void)keyDown:(NSEvent *)theEvent
{
    //NSLog(@"key pressed: %@", theEvent);
    if (theEvent.keyCode == 51 || theEvent.keyCode == 117)
    {
        [toDoArray removeObjectAtIndex:[toDoListView selectedRow]];
        [toDoListView reloadData];
    }
}
@end
1
ответ дан 3 December 2019 в 08:05
поделиться