make NSTextField in NSTableCellView firstResponder()
Don't subclass NSTextField
. You can make the text field in a view based table view first responder right out of the box.
It's pretty easy.
Assuming you know row
and column
(in your example row 0 and column 0) get the table cell view with view(atColumn: 0, row
and make the text field first responder.
let keyView = tableView.view(atColumn: 0, row: 0, makeIfNecessary: false) as! NSTableCellView
view.window!.makeFirstResponder(keyView.textField)
And what is the second outlet for? Just use the standard default textField
.
How to programmatically initiate NSTextFieldCell editing (make it firstResponder)
When the editing started ,fieldEditor
comes into picture thats why not able to set the firstResponder
.
Implemented the textDidEndEditing
delegate of the tableView. It solved the isssue.
NSTextField as FirstResponder has no stringValue unless manually clicking elsewhere
As Willeke asked in comments how I set and removed first responder I noticed that I had, incorrectly set it as:
[self.textfield becomeFirstResponder]
The docs state that this should not be used and the correct method is:
if ([self.textfield acceptsFirstResponder])
[self.textfield.window makeFirstResponder:self.textfield];
Thanks Willeke!
NSTextField in NSTableCellView
Probably the easiest way to accomplish this would be to subclass NSTextField and to override the drawRect: method in your subclass. There you can determine whether the NSTableCellView instance containing your NSTextField instances is currently selected by using this code (which I use with a NSOutlineView, but it should also work with NSTableView):
BOOL selected = NO;
id tableView = [[[self superview] superview] superview];
if ([tableView isKindOfClass:[NSTableView class]]) {
NSInteger row = [tableView selectedRow];
if (row != -1) {
id cellView = [tableView viewAtColumn:0 row:row makeIfNecessary:YES];
if ([cellView isEqualTo:[self superview]]) selected = YES;
}
}
Then draw the view like this:
if (selected) {
// set your color here
// draw [self stringValue] here in [self bounds]
} else {
// call [super drawRect]
}
NSTextfield renaming implementation on custom button in NSTableView
Well, the answer is actually very easy, it's the lack of related information that makes it kinda hard.
So, in case anybody's looking for the same thing, that's how I implemented this feature(it's actually one-liner):
in your action outlet just call
cell.textField?.selectText(self)
and the text's gonna get selected. After that just keep implementing it as usual.
Cocoa: Get Notified after Text Cell (NSTextField) is Edited & Start Editing Text Cell after Adding it in NSTableView in Swift 4?
Use Cocoa Bindings, it's very powerful and saves a lot of boilerplate code.
Short tutorial:
Edit: To take full advantage of KVC the data source must be an NSObject
subclass with dynamic
properties
Create a simple class
Dream
(thedescription
property is optional)class Dream : NSObject {
@objc dynamic var name : String
init(name : String) { self.name = name }
override var description : String { return "Dream " + name }
}In the view controller declare the data source array
var dreams = [Dream]()
and replace
var selectedRow:Int = 0
with@objc dynamic var selectedIndexes = IndexSet()
Go to Interface Builder
Select the table view, press ⌥⌘7 to go to the Bindings Inspector.
BindSelection Indexes
toView Controller
Model Key PathselectedIndexes
.
Press ⌥⌘6 and connect thedataSource
(by drag&drop) to the view controller () .Select the text field
File 1
inTable Cell View
in the table column. The easiest way is to ⌃⇧click in the text field area.
Press ⌥⌘7 and bindValue
toTable Cell View
Model Key PathobjectValue.name
(!)
In the view controller populate the data source array in
viewDidLoad
( I don't know that framework so I leave it out) and reload the table view.override func viewDidLoad() {
super.viewDidLoad()
let dreamNames = ["Hit the gym", "Run daily", "Become a millionaire", "Become a better programmer", "Achieve your dreams"]
dreams = dreamNames.map{Dream(name: $0)}
table.reloadData()
}Delete
acceptsFirstResponder
- Delete
tableViewSelectionDidChange
- Delete
tableView:viewFor:row:
Add
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
return dreams[row]
}Replace
addNewDream
withfunc addNewDream() {
let last = dreams.count
dreams.append(Dream(name: "Double Click or Press Enter to Add Item"))
table.insertRows(at: IndexSet(integer: last), withAnimation: .effectGap)
table.scrollRowToVisible(last)
table.selectRowIndexes([last], byExtendingSelection: false)
saveDreams()
}Replace
removeDream()
withfunc removeDream() {
guard let selectedRow = selectedIndexes.first else { return }
dreams.remove(at: selectedRow)
table.removeRows(at: IndexSet(integer: selectedRow), withAnimation: .effectFade)
saveDreams()
}
To save the array when the text was edited afterwards you have to implement the delegate method controlTextDidEndEditing(_:)
override func controlTextDidEndEditing(_ obj: Notification) {
saveDreams()
}
and in Interface Builder connect the delegate
of the text field in the table view to the view controller.
Related Topics
Argument of '#Selector' Does Not Refer to an '@Objc' Method, Property or Initializer
How to Get Frame Data in Apprtc iOS App for Video Modifications
Swift: Specialize Method of Generic Class for Function Types
Change the Font of a Datepicker
Generic and (Early) Binding in Swift 1.2
Why Use Class Only Protocols in Swift
Swift - How to Resize a Uiview Based on Its Uilabel Size (That Is Inside)
Reading Data from Excel Document in a Swift App
Swift Cannot Assign to Self in a Class Init Method
Implementing Swift Protocol Methods in a Base Class
Type Check Operator (Is) for Check VS Homogenous Protocol: Why Can This Be Done for Optionals
Why Is Deinit Not Called Until Uiview Is Added to Parent Again
Swiftui Button Interact with Map
How to Set an Initial Value for @Nsmanaged Property Pfobject Subclass