我有NSTableView
个单元格包含NSCheckBox
。我想改变它的行为,以便可以点击表格中的任何行,并且该行中的复选框会相应地打开/关闭。
我认为可以用
完成 func tableView(tableView: NSTableView, shouldSelectRow row: Int) -> Bool {
}
此方法提供单击行的索引,我可以使用它来以编程方式从那里切换复选框。但问题是NSCheckBox拦截其行上的鼠标点击。有没有办法禁用它,以便可以完全点击行?将NSCheckBox
的启用状态设置为false将允许此操作,但它也会使复选框及其标题变灰。
编辑:
澄清我需要的内容:(基于视图的)表格单元格视图包含一个复选框。如果用户单击该复选框,则会切换,但如果在没有复选框的位置单击该行,则不会执行任何操作。我希望单击该行,然后相应地切换复选框。所以基本上我希望复选框是不可点击的,并且表格行在单击行时通知其中的复选框。
答案 0 :(得分:2)
在基于单元格的表格视图中,您可以实施-selectionShouldChangeInTableView:
。我认为这也适用于基于视图的表视图。
- (BOOL)selectionShouldChangeInTableView:(NSTableView *)tableView
{
NSInteger clickedColumn = tableView.clickedColumn;
NSInteger attributeEnabledColumn = [tableView columnWithIdentifier:@"attributeEnabled"];
if (clickedColumn == attributeEnabledColumn) {
NSInteger clickedRow = tableView.clickedRow;
if (clickedRow >= 0) {
NSArrayController *attributesArrayController = self.attributesArrayController;
NSMutableDictionary *attributeRow = [attributesArrayController.arrangedObjects objectAtIndex:clickedRow];
BOOL attributeEnabled = [attributeRow[kAttributeSelectionAttributeEnabledKey] boolValue];
attributeRow[kAttributeSelectionAttributeEnabledKey] = @(!attributeEnabled);
}
return NO;
}
return YES;
}
答案 1 :(得分:1)
到目前为止,您的方法很好,您可以点击表格行,这会切换复选框状态。
正如您所说,可以单击该复选框,而不会触发表格行选择。您需要子类化NSTableCellView
并将此子类分配给单元格的类属性。在该自定义类文件中,您可以对复选框进行响应以切换并更改表的基础数据源。
import Cocoa
class MyTableCellView: NSTableCellView {
@IBOutlet weak var checkbox: NSButton! // the checkbox
@IBAction func checkboxToggle(sender: AnyObject) {
// modify the datasource here
}
}
编辑:
以下是一个代码段,当用户点击表格单元格的任意位置时,会切换复选框:
func tableView(tableView: NSTableView, shouldSelectRow row: Int) -> Bool {
if let cell = tableView.viewAtColumn(0, row: row, makeIfNecessary: false) as? MyTableCellView {
cell.checkbox.state = cell.checkbox.state == NSOnState ? NSOffState : NSOnState
}
return false
}
请注意,它仍然需要表格单元格的子类,您可以在其中放置@IBOutlet
复选框,以便在代码中访问它。
答案 2 :(得分:1)
Apple通过以下NSEvent
类方法为您提供拦截多种NSEvent
类型的机会:
每当type
属性与您传入上述方法的第一个参数的掩码匹配的事件执行时,block
(第二个参数)执行。这个区块让你有机会做很多事情:你可以进行额外的处理然后让事件像往常一样继续,你可以修改事件,或者你完全取消事件。至关重要的是,您在此块中放置的任何内容都会在任何其他事件处理之前发生 。
在下面的代码段中,只要点击一个复选框,传入的事件就会被修改,以使事件的行为与点击发生在复选框之外,但在复选框内部NSTableCellView
superview。
func applicationDidFinishLaunching(aNotification: NSNotification) {
NSEvent.addLocalMonitorForEventsMatchingMask(.LeftMouseDownMask,
handler: { (theEvent) -> NSEvent! in
var retval: NSEvent? = theEvent
let winPoint = theEvent.locationInWindow
// Did the mouse-down event take place on a row in the table?
if let row = self.tableView.rowContainingWindowPoint(winPoint) {
// Get the view on which the mouse down event took place
let view = self.tableView.viewAtColumn(0,
row: row,
makeIfNecessary: true) as! NSTableCellView
// In my demo-app the checkbox is the NSTableCellView's last subview
var cb = view.subviews.last! as! NSButton
let cbBoundsInWindowCoords = cb.convertRect(cb.bounds, toView: nil)
// Did the click occur on the checkbox part of the view?
if CGRectContainsPoint(cbBoundsInWindowCoords, theEvent.locationInWindow) {
// Create a modified event, where the <location> property has been
// altered so that it looks like the click took place in the
// NSTableCellView itself.
let newLocation = view.convertPoint(view.bounds.origin, toView: nil)
retval = theEvent.cloneEventButUseAdjustedWindowLocation(newLocation)
}
}
return retval
})
}
func tableView(tableView: NSTableView, shouldSelectRow row: Int) -> Bool {
if let view = self.tableView.viewAtColumn(0,
row: row,
makeIfNecessary: true) as? NSTableCellView {
var checkbox = view.subviews.last! as! NSButton
checkbox.state = (checkbox.state == NSOnState) ? NSOffState : NSOnState
}
return true
}
////////////////////////////////////////////////////////////////
extension NSTableView {
// Get the row number (if any) that coincides with a specific
// point - where the point is in window coordinates.
func rowContainingWindowPoint(windowPoint: CGPoint) -> Int? {
var rowNum: Int?
var tableRectInWindowCoords = convertRect(bounds, toView: nil)
if CGRectContainsPoint(tableRectInWindowCoords, windowPoint) {
let tabPt = convertPoint(windowPoint, fromView: nil)
let indexOfClickedRow = rowAtPoint(tabPt)
if indexOfClickedRow > -1 && indexOfClickedRow < numberOfRows {
rowNum = indexOfClickedRow
}
}
return rowNum
}
}
extension NSEvent {
// Create an event based on another event. The created event is identical to the
// original except for its <location> property.
func cloneEventButUseAdjustedWindowLocation(windowLocation: CGPoint) -> NSEvent {
return NSEvent.mouseEventWithType(type,
location: windowLocation,
modifierFlags: modifierFlags,
timestamp: timestamp,
windowNumber: windowNumber,
context: context,
eventNumber: eventNumber,
clickCount: clickCount,
pressure: pressure)!
}
}