Один метод является коррелированным подзапросом:
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)
Хорошо это не легко, но мне удалось сделать это, не имея необходимость использовать RRSpreadSheet или даже другое управление. Вот то, что необходимо сделать:
Создайте подкласс NSTextView
, это будет полевым редактором. Для этого примера имя MyFieldEditorClass
будет использоваться и myFieldEditor
будет относиться к экземпляру этого класса.
Добавьте метод к MyFieldEditorClass
названный"- (void) setLastKnownColumn:(unsigned)aCol andRow:(unsigned) aRow
"или что-то подобное, и имеет его, сохраняют обоих входные значения параметров где-нибудь.
Добавьте другой метод, названный "setTableView": и имейте его, сохраняют объект NSTableView где-нибудь, или если нет другой способ получить объект NSTableView от полевого редактора, используйте это.
Добавьте другой названный метод - (void) keyDown:(NSEvent *) event
. Это на самом деле переопределяет NSResponder
keyDown:
. Исходный код должен быть (знать, что MarkDown StackOverflow изменяется <
и >
кому: <
и >
):
- (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;
}
Дайте NSTableView в Вашем пере, делегат, и в делегате добавляет метод:
- (BOOL) tableView:(NSTableView *)aTableView shouldEditColumn:(NSTableColumn *) aCol row:aRow
{
if ([aTableView isEqual:TheTableViewYouWantToChangeBehaviour])
[myFieldEditor setLastKnownColumn:[[aTableView tableColumns] indexOfObject:aCol] andRow:aRow];
return YES;
}
Наконец, дайте главному окну Табличного представления делегата и добавьте метод:
- (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;
}
}
Запустите программу и дайте ей движение!
Вместо принуждения NSTableView
чтобы сделать что-то, для чего это не было разработано, можно хотеть посмотреть на использование чего-то разработанного с этой целью. У меня есть управление электронной таблицей с открытым исходным кодом, которое может сделать то, в чем Вы нуждаетесь, или можно, по крайней мере, смочь расширить его, чтобы сделать то, в чем Вы нуждаетесь: MBTableGrid
В 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;
}
Я хотел ответить на ответы здесь, но кажется, что кнопка ответа отсутствует, поэтому я вынужден доказывать ответ, когда я действительно просто хочу задать вопрос об ответах.
В любом случае, я видел несколько ответов на переопределение события -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