使用 NSButtonCell 实例获取自定义 NSCell 来处理鼠标单击/鼠标事件
好吧,我真的被这个问题难住了。我想制作一个复选框 NSTextFieldCell 组合在一起。复选框很重要 如果鼠标击中框而不是文本,则亮起。我已经完成了 或多或少是这样,但问题是接收鼠标事件,因为 我连续单击一个复选框,但它们全部变成 NSOnState。我 将展示我所做的事情以及我的各种失败的尝试,以便 让这个发挥作用。
所以这就是我到目前为止所做的:
header:
@interface MyCheckboxCellToo : NSTextFieldCell {
NSButtonCell *_checkboxCell;
}
implementation:
- (NSUInteger)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView {
NSPoint point = [controlView convertPoint:[event locationInWindow] fromView:nil];
NSLog(@"%@", NSStringFromPoint(point));
NSRect checkFrame;
NSDivideRect(cellFrame, &checkFrame, &cellFrame, cellFrame.size.height/*3 + [[_checkboxCell image] size].width*/, NSMinXEdge);
if (NSMouseInRect(point, checkFrame, [controlView isFlipped])) {
// the checkbox, or the small region around it, was hit. so let's flip the state
NSCellStateValue checkState = ([_checkboxCell state] == NSOnState) ? NSOffState:NSOnState;
[self setState:checkState];
[_checkboxCell setState:checkState];
[controlView setNeedsDisplay:YES];
return NSCellHitTrackableArea;
}
return [super hitTestForEvent:event inRect:cellFrame ofView:controlView];
}
我知道我可能不应该这样做:
[self setState:checkState];
[_checkboxCell setState:checkState];
[controlView setNeedsDisplay:YES];
在那里...因为结果是每个中的每个复选框都会转到 NSOnState。这是因为细胞被重复使用了吗?为什么 ImageAndTextCell 在同一个 tableview 中可以有不同的图像?如何处理鼠标事件?
我尝试过:
- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame
ofView:(NSView *)controlView untilMouseUp:(BOOL)untilMouseUp {
NSLog(@"%s %@", _cmd, theEvent);
return [_checkboxCell trackMouse:theEvent inRect:cellFrame
ofView:controlView untilMouseUp:untilMouseUp];
// return YES;
// return [super trackMouse:theEvent inRect:cellFrame
ofView:controlView untilMouseUp:untilMouseUp];
}
- (BOOL)startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView {
NSLog(@"%s %@", _cmd, NSStringFromPoint(startPoint));
return [super startTrackingAt:startPoint inView:controlView];
}
- (BOOL)continueTracking:(NSPoint)lastPoint at:(NSPoint)currentPoint
inView:(NSView *)controlView {
NSLog(@"%s %@", _cmd, NSStringFromPoint(currentPoint));
return [super continueTracking:lastPoint at:currentPoint
inView:controlView];
}
- (void)stopTracking:(NSPoint)lastPoint at:(NSPoint)stopPoint
inView:(NSView *)controlView mouseIsUp:(BOOL)flag {
NSLog(@"%s %d %@", _cmd, flag, NSStringFromPoint(stopPoint));
}
trackMouse: ... 确实被调用
,但
startTrackingAt:...、 continueTracking:... 和 stopTracking:... DO 当我单击
trackMouse 中的复选框“点击区域”时,不会被调用:...我已经尝试过
return [_checkboxCell trackMouse:theEvent inRect:cellFrame ofView:controlView untilMouseUp:untilMouseUp];
,并且
return [super trackMouse:theEvent inRect:cellFrame ofView:controlView untilMouseUp:untilMouseUp];
似乎都没有导致复选框处理鼠标事件。
如何让该复选框进入 NSOnState?我知道我很漂亮 关闭但经过大量文档阅读和谷歌搜索后我还没有 成功解决了这个问题。
欢迎提出建议和评论。
好吧,这里有更多内容来展示对象的创建和销毁。
- (id)init {
if ((self = [super init])) {
_checkboxCell = [[NSButtonCell alloc] init];
[_checkboxCell setButtonType:NSSwitchButton];
[_checkboxCell setTitle:@""];
[_checkboxCell setTarget:self];
[_checkboxCell setImagePosition:NSImageLeft];
[_checkboxCell setControlSize:NSRegularControlSize];
}
return self;
}
- copyWithZone:(NSZone *)zone {
MyCheckboxCellToo *cell = (MyCheckboxCellToo *)[super copyWithZone:zone];
cell->_checkboxCell = [_checkboxCell copyWithZone:zone];
return cell;
}
- (void)dealloc {
[_checkboxCell release];
[super dealloc];
}
OK I'm really stumped on this one. I want to make a checkbox with a
NSTextFieldCell combined together. It's important that the checkbox
goes ON if the mouse hits the box, NOT the text. I've accomplished
this, more or less, but the issue is receiving the mouse event because
I click one checkbox in a row, but ALL of them turn to NSOnState. I
will show what I've done and my various failed attempts in order to
get this to work.
So this is how I've done it so far:
header:
@interface MyCheckboxCellToo : NSTextFieldCell {
NSButtonCell *_checkboxCell;
}
implementation:
- (NSUInteger)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView {
NSPoint point = [controlView convertPoint:[event locationInWindow] fromView:nil];
NSLog(@"%@", NSStringFromPoint(point));
NSRect checkFrame;
NSDivideRect(cellFrame, &checkFrame, &cellFrame, cellFrame.size.height/*3 + [[_checkboxCell image] size].width*/, NSMinXEdge);
if (NSMouseInRect(point, checkFrame, [controlView isFlipped])) {
// the checkbox, or the small region around it, was hit. so let's flip the state
NSCellStateValue checkState = ([_checkboxCell state] == NSOnState) ? NSOffState:NSOnState;
[self setState:checkState];
[_checkboxCell setState:checkState];
[controlView setNeedsDisplay:YES];
return NSCellHitTrackableArea;
}
return [super hitTestForEvent:event inRect:cellFrame ofView:controlView];
}
I know I probably shouldn't be doing:
[self setState:checkState];
[_checkboxCell setState:checkState];
[controlView setNeedsDisplay:YES];
in there... because the result is that EVERY checkbox in every goes to
NSOnState. Is this because cells are re-used? How come the ImageAndTextCell can have different images in the same tableview? How do I handle the mouse event?
I have tried:
- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame
ofView:(NSView *)controlView untilMouseUp:(BOOL)untilMouseUp {
NSLog(@"%s %@", _cmd, theEvent);
return [_checkboxCell trackMouse:theEvent inRect:cellFrame
ofView:controlView untilMouseUp:untilMouseUp];
// return YES;
// return [super trackMouse:theEvent inRect:cellFrame
ofView:controlView untilMouseUp:untilMouseUp];
}
- (BOOL)startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView {
NSLog(@"%s %@", _cmd, NSStringFromPoint(startPoint));
return [super startTrackingAt:startPoint inView:controlView];
}
- (BOOL)continueTracking:(NSPoint)lastPoint at:(NSPoint)currentPoint
inView:(NSView *)controlView {
NSLog(@"%s %@", _cmd, NSStringFromPoint(currentPoint));
return [super continueTracking:lastPoint at:currentPoint
inView:controlView];
}
- (void)stopTracking:(NSPoint)lastPoint at:(NSPoint)stopPoint
inView:(NSView *)controlView mouseIsUp:(BOOL)flag {
NSLog(@"%s %d %@", _cmd, flag, NSStringFromPoint(stopPoint));
}
trackMouse: ... DOES gets called
but
startTrackingAt:..., continueTracking:..., and stopTracking:.... DO
NOT get called when I click on the checkbox "hit area"
in trackMouse:... I have tried
return [_checkboxCell trackMouse:theEvent inRect:cellFrame ofView:controlView untilMouseUp:untilMouseUp];
and
return [super trackMouse:theEvent inRect:cellFrame ofView:controlView untilMouseUp:untilMouseUp];
and neither seems to result in the mouse event being handled by the checkbox.
How do I get that single checkbox to go NSOnState? I know I'm pretty
close but after a lot of doc reading and google searching I haven't
been successful at solving this.
suggestions and comments welcome..
OK here is a bit more to show creation and destruction of the object..
- (id)init {
if ((self = [super init])) {
_checkboxCell = [[NSButtonCell alloc] init];
[_checkboxCell setButtonType:NSSwitchButton];
[_checkboxCell setTitle:@""];
[_checkboxCell setTarget:self];
[_checkboxCell setImagePosition:NSImageLeft];
[_checkboxCell setControlSize:NSRegularControlSize];
}
return self;
}
- copyWithZone:(NSZone *)zone {
MyCheckboxCellToo *cell = (MyCheckboxCellToo *)[super copyWithZone:zone];
cell->_checkboxCell = [_checkboxCell copyWithZone:zone];
return cell;
}
- (void)dealloc {
[_checkboxCell release];
[super dealloc];
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我无法直接回答问题的处理单元中事件部分,但我可以回答以下部分:
它们的重用方式与 UITableView 重用 UITableViewCell 的方式不同。
(我注意到您标记了问题“NSTableViewCell”。AppKit 中不存在这样的类。)
这两个问题的答案是相同的。
UITableView 为每一行使用一个单元格,并保留与屏幕上的行数一样多的单元格,而 NSTableView 为每一列使用一个单元格。
每一列都作为一个 NSTableColumn 对象存在,并且每个 NSTableColumn 恰好有一个单元格*。表视图将单元格的对象值设置为您为该列行交叉点提供的任何值,然后告诉单元格在其边界内的适当位置进行绘制。对于每一行的该列,它都会使用相同的单元格执行相同的操作。
(这里有例外,因为苹果添加了对特定行使用不同单元格的功能,并且因为他们添加了组行,这些行没有列并使用不同的单元格。不过,基本机制是相同的。
)抱歉,我无法帮助您一路找到解决方案(除了我的“将它们分开列”的建议之外),但我希望这至少可以帮助您部分。
*它也有一个标题单元格,但这里不算在内。我所说的“恰好一个单元格”是它的数据单元格。
I can't directly answer the handling-events-in-cells part of the question, but I can answer these parts:
They're reused in a different sense from how UITableView reuses UITableViewCells.
(I noticed that you tagged the question “NSTableViewCell”. No such class exists in AppKit.)
The answer to both questions is the same.
While UITableView uses one cell for each row, and keeps on hand as many cells as there are rows on the screen, NSTableView uses a single cell for every column.
Each column exists as an NSTableColumn object, and each NSTableColumn has exactly one cell*. The table view sets the cell's object value to whatever value you provided for that column-row intersection, and then tells the cell to draw at the appropriate place within its bounds. It'll do the same thing, with that same cell, for that column for every row.
(There are exceptions here, since Apple added the ability to use a different cell for specific rows, and since they added group rows, which have no columns and use a different cell. The fundamental mechanism is the same, though.)
I'm sorry that I can't help you all the way to a solution (aside from my just-make-them-separate-columns suggestion), but I hope this at least helps you part of the way.
*It has a header cell, too, but that doesn't count here. The “exactly one cell” I'm talking about is its data cell.
好吧,这或多或少似乎解决了我的问题。
在 hitForTestEvent: ...
而不是
应该是:
我仍然遇到一些问题,如果我单击某个位置的复选框命中区域,它不会注册,但或多或少可以工作。
Ok this is what appeared to fix my issue, more or less.
in hitForTestEvent: ...
instead of
it should be:
I still have some issues where if I click the checkbox hit zone in a certain spot it doesn't register but more or less this works.
我创建了一个自定义单元格类,它是 NSButtonCell 而不是 NSTextFieldCell 的子类。如果单击不在复选框上,则在 hitTestForEvent:inRect:ofView: 中返回 0。
当用户单击复选框时,在 NSBrowser 委托的 browser:setObjectValue:forItem: 中,我得到一个 NSBoolean 并将相应“节点”对象的“选中”ivar 设置为等于该 NSBoolean。
在 NSBrowser 委托的 browser:willDisplayCell:atRow:column: 方法中,我调用 [browser itemAtIndex:] 来获取我的“节点”,并使用节点的“已检查”ivar 调用单元格的 setState: 方法。
查看“ComplexBrowser”Xcode 示例项目,了解有关浏览器委托内容的示例代码。
无论你做什么,我都不建议子类化 NSBrowserCell。这对我来说是一个巨大的死胡同。
2011 年 8 月 30 日更新:这在 10.5 中不起作用。啊。我又回到了原点。
I created a custom cell class that's a subclass of NSButtonCell instead of NSTextFieldCell. It returns 0 in hitTestForEvent:inRect:ofView: if the click isn't on the checkbox.
When the user clicks on the checkbox, in the NSBrowser delegate's browser:setObjectValue:forItem: I get an NSBoolean and set the "checked" ivar of my corresponding "node" object equal to that NSBoolean.
In the NSBrowser delegate's browser:willDisplayCell:atRow:column: method I call [browser itemAtIndex:] to get my "node", and call the cell's setState: method with the node's "checked" ivar.
Check out the "ComplexBrowser" Xcode sample project for sample code on the browser delegate stuff.
Whatever you do, I don't recommend subclassing NSBrowserCell. That was a big crashy dead-end for me.
UPDATE Aug 30, 2011: This doesn't work in 10.5. Ugh. I'm back to square one.