将子视图添加到 NSView 以获得类似国际象棋的网格
Posted
技术标签:
【中文标题】将子视图添加到 NSView 以获得类似国际象棋的网格【英文标题】:adding subviews to an NSView to have a chess-like grid 【发布时间】:2012-05-01 18:33:19 【问题描述】:我正在尝试创建一个 Cocoa UI,它由两组正方形(类似国际象棋的网格)组成,当底层算法运行时它们会呈现不同的颜色。当算法的执行结束时,UI 应该能够处理点击、平移和其他手势。
我目前的层次结构如下(具体请查看附件代码):
1) 作为窗口控制器的窗口的主窗口
2) 具有两个自定义视图 mainView 和 sideView 的拆分视图(每个视图都包含一组正方形)
3)两个视图控制器(mainViewController和sideViewController)
我希望能够将方块加载为 mainView 和 sideView 的子视图。
我想有另一个自定义视图,比如 SquareView 和另一个 nib 文件。我的问题是:
a) 我如何创建这个 SquareView 以便它可以用于创建将作为子视图添加到 mainView 和 sideView 以形成类似象棋的网格的正方形?
b) 如何将子视图添加到 mainView 和 sideView 以构建两个网格?为简单起见,我们假设前面提到的每个视图都有四个不重叠的正方形。
谢谢!
MainView.m
#import "MainView.h"
@implementation MainView
- (void)drawRect:(NSRect)TheRect
[[NSColor grayColor] set];
[NSBezierPath fillRect:[self bounds]];
SideView.m
#import "SideView.h"
@implementation MainView
- (void)drawRect:(NSRect)TheRect
[[NSColor whiteColor] set];
[NSBezierPath fillRect:[self bounds]];
MainWindowController.h
#import <Cocoa/Cocoa.h>
@class SideViewController;
@class MainViewController;
@interface MainWindowController : NSWindowController
IBOutlet NSSplitView* oMainSplitView;
SideViewController* sideViewController;
MainViewController* mainViewController;
@end
MainWindowController.m
#import "MainWindowController.h"
#import "SideViewController.h"
#import "MainViewController.h"
@implementation MainWindowController
- (void)windowDidLoad
sideViewController = [[SideViewController alloc] initWithNibName:@"SideView" bundle:nil];
NSView* splitViewLeftView = [[oMainSplitView subviews] objectAtIndex:0];
NSView* sideView = [sideViewController view];
[sideView setFrame:[splitViewLeftView bounds]];
[sideView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
[splitViewLeftView addSubview:sideView];
mainViewController = [[MainViewController alloc] initWithNibName:@"MainView" bundle:nil];
NSView* splitViewRightView = [[oMainSplitView subviews] objectAtIndex:1];
NSView* mainView = [mainViewController view];
[mainView setFrame:[splitViewRightView bounds]];
[mainView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
[splitViewRightView addSubview:mainView];
【问题讨论】:
【参考方案1】:您可以根据自己的意愿将其变得简单或复杂:简单吗?在 MainView 的 drawRect 方法中做你想做的一切;复杂:嵌套 NSViews(或 NSCell's,或 NSBox's 等)并让每个人自己绘制。
就个人而言,我会投票保持简单......
【讨论】:
【参考方案2】:a) 我认为最简单的方法是创建一个 NSBoxes 矩阵,您可以在代码或 IB 中执行此操作。将正方形放在矩阵中可以很容易地遍历它们或访问特定的。
b) 我不确定您的问题是什么——您可以像在发布的代码中那样使用 [mainView addSubview:squareMatrix];
编辑后:实际上,IB 似乎不允许您将 NSBoxes 嵌入矩阵中。过去,我制作了一个子类 NSButtonCells 矩阵(以允许背景颜色没有边框),它有一个 64x64 单元格的网格,这些单元格是可点击的,并且会随着这些点击而改变颜色。我不知道您是否希望视图中的单元格数量固定,还是需要动态更改数量?我认为这样的东西可能对你有用——我实际上是在代码中创建的,因为 IB 在更新这么多单元时真的很慢。
这就是我所做的。就我而言,我需要没有边框但有背景颜色的单元格,所以我必须继承 NSButtonCell,如下所示:
-(id)initWithRGBAlpha:(NSArray *)rgbAlpha
if (self == [super init])
NSColor *color = [NSColor colorWithCalibratedRed:[[rgbAlpha objectAtIndex:0]doubleValue]
green:[[rgbAlpha objectAtIndex:1]doubleValue]
blue:[[rgbAlpha objectAtIndex:2]doubleValue]
alpha:[[rgbAlpha objectAtIndex:3]doubleValue]];
[self setBackgroundColor:color];
[self setTitle:@""];
[self setBordered:NO];
[self setTag:0];
[self setImageScaling:3];
return self;
else
return nil;
-(void) setState:(NSInteger)value
if (value == 1)
self.backgroundColor = self.selectedColor;
[super setState:value];
else
self.backgroundColor = self.backgroundColor;
[super setState:value];
-(void) setBackgroundColor:(NSColor *)color
backgroundColor = color;
selectedColor = [color colorWithAlphaComponent:.75];
- (void)encodeWithCoder:(NSCoder *)encoder
[super encodeWithCoder:encoder];
[encoder encodeObject:self.backgroundColor forKey:@"bColor"];
- (id)initWithCoder:(NSCoder *)decoder
[super initWithCoder:decoder];
self.backgroundColor = [decoder decodeObjectForKey:@"bColor"];
return self;
我在代码中创建了矩阵,如下所示:
@implementation RDMatrix
-(void) initWithParentView:(NSView *) cv
NSNumber *one = [NSNumber numberWithInt:1];
NSArray *colors = [NSArray arrayWithObjects:one,one,one,one,nil];
RDButtonCell *theCell = [[RDButtonCell alloc ]initWithRGBAlpha:colors];
[self initWithFrame:NSMakeRect(200,100,1,1) mode:2 prototype:theCell numberOfRows:64 numberOfColumns:64];
[self setSelectionByRect:TRUE];
[self setCellSize:NSMakeSize(8,8)];
[self sizeToCells];
self.target = self;
self.action = @selector(matrixClick:);
self.backgroundColor = [NSColor lightGrayColor];
self.drawsBackground = TRUE;
self.autoresizingMask = 8;
self.allowsEmptySelection = TRUE;
[cv addSubview:self];
-(void) matrixClick: (id) sender
for (RDButtonCell *aCell in self.selectedCells)
if ([self.selectedCells count] < 64)
aCell.backgroundColor = [NSColor colorWithCalibratedRed:1 green:0 blue:0 alpha:1];
else
aCell.backgroundColor = [NSColor colorWithCalibratedRed:0 green:.5 blue:1 alpha:1];
[self deselectAllCells];
@end
【讨论】:
为什么使用NSBox
比在自定义视图中绘制正方形更容易/更好?
@***foe,我不知道“更好”,但我认为在 IB 中这样做更容易,因为你可以按照你想要的方式布置它,并且 NSBoxes(自定义类型)为您提供边框和填充颜色。最终(对我来说),它归结为方便(在 IB 中进行)与在代码中进行的灵活性。
我可能不够清楚,对此我深表歉意。这个想法是为每个视图(mainView 和 sideView)添加一个正方形网格。随着算法的运行,每个方块将呈现不同的颜色。以后的触控板手势必须由应用程序处理。我真的不知道该走哪条路。我是否应该有一个带有正方形的 nib 文件,该文件将被加载以创建一组子视图?在这种情况下,我需要另一个视图控制器用于子视图吗?还是使用 NSCollectionView、CALayers、NSBoxes 或 NSButtons 会更好?如果我有 100 多个方格怎么办?谢谢!
好吧,我支持我原来帖子中的想法(但请参阅我编辑的答案,以获得更正)。你的进一步解释并没有让我认为它不起作用,所以我不知道你认为我对你的问题不理解。
网格中的方格数不会随时间变化。算法完成后,方块只会改变颜色并适应触控板手势。 1) 你认为你可以向我提供一些关于创建 64x64 单元格网格的代码行吗? 2) 网格会从属于 mainView 控制器还是需要类似的东西?谢谢。以上是关于将子视图添加到 NSView 以获得类似国际象棋的网格的主要内容,如果未能解决你的问题,请参考以下文章
如何以编程方式将视图添加到 NSWindow(或 NSView)?