【问题标题】:NSTableView to allow user to choose which columns to displayNSTableView 允许用户选择要显示的列
【发布时间】:2012-11-13 06:51:16
【问题描述】:

任何人都知道如何允许用户通过右键单击然后选择来选择要显示的 NSTableView 的哪些列?就像 iTunes 一样。

【问题讨论】:

    标签: objective-c macos cocoa nstableview nsmenu


    【解决方案1】:

    我已经实现了这个,以下应该可以在没有任何子类的情况下使用。

    首先在 IB 中实现一个空菜单,并连接到 Table Header View 的菜单输出。

    此方法(从 awakeFromNib 调用)从标题构造菜单的内容(并包括一个防止用户隐藏主列的测试)

    - (void)initViewHeaderMenu:(id)view {
        //create our contextual menu
        NSMenu *menu = [[view headerView] menu];
        //loop through columns, creating a menu item for each
        for (NSTableColumn *col in [view tableColumns]) {
            if ([[col identifier] isEqualToString:COLUMNID_NAME])
                continue;   // Cannot hide name column
            NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle:[col.headerCell stringValue]
                                                        action:@selector(toggleColumn:)  keyEquivalent:@""];
            mi.target = self;
            mi.representedObject = col;
            [menu addItem:mi];
        }
        return;
    }
    

    这会调用以下内容来执行实际的隐藏/取消隐藏

    - (void)toggleColumn:(id)sender {
        NSTableColumn *col = [sender representedObject];
        [col setHidden:![col isHidden]];
    }
    

    您还需要设置 Menu 的委托并实现以下设置状态:-

    #pragma mark NSMenu Delegate Methods
    -(void)menuWillOpen:(NSMenu *)menu {
        for (NSMenuItem *mi in menu.itemArray) {
            NSTableColumn *col = [mi representedObject];
            [mi setState:col.isHidden ? NSOffState : NSOnState];
        }
    }
    

    【讨论】:

    • menuWillOpen 在此方法期间不要修改...菜单项。 也许menuNeedsUpdate 是更好的候选者?
    • 如果方法名不是初始值设定项,则不应以“init”开头。
    • 这太棒了。您可能希望添加mi.state = (col.isHidden ? NSOffState: NSOnState); 以在可见列旁边显示一个复选框。这需要在隐藏toggleColumn: 中的列后更新,就像 `[sender setState: (col.isHidden ? NSOffState: NSOnState)];
    【解决方案2】:

    我基于 this blog post 扩展了 Milliways 的出色答案,并添加了以下功能:

    • 显示可见列的复选标记
    • 使用NSUserDefaults 保持设置

    初始设置

    // Your intial Startup code
    [self setupHeaderMenu:self.yourTableView];
    

    创建菜单

    重要提示:由于 col.identifier,您必须为 IB 中的每个表视图列设置一个“标识标识符”才能使其工作。

    #pragma mark - Show Hide Columns
    - (void)setupHeaderMenu:(NSTableView *)tableView {
    
        NSDictionary *savedCols = [[NSUserDefaults standardUserDefaults] dictionaryForKey:kUserDefaultsKeyVisisbleColumns];
    
        NSMenu *menu = [NSMenu new];
        for (NSTableColumn *col in tableView.tableColumns) {
    
            NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle:[col.headerCell stringValue]
                                                        action:@selector(toggleColumn:)
                                                 keyEquivalent:@""];
            mi.target = self;
    
            if(savedCols){
                BOOL isVisible = [savedCols[col.identifier] boolValue];
                [col setHidden:!isVisible];
            }
    
            mi.state = (col.isHidden ? NSOffState: NSOnState);
            mi.representedObject = col;
            [menu addItem:mi];
        }
    
        tableView.headerView.menu = menu;
        return;
    }
    

    切换方法

    toggle方法将新配置保存在NSUserDefaults

    - (void)toggleColumn:(NSMenuItem *)menu {
        NSTableColumn *col = menu.representedObject;
    
        BOOL shouldHide = !col.isHidden;
        [col setHidden:shouldHide];
    
        menu.state = (col.isHidden ? NSOffState: NSOnState);
    
        NSMutableDictionary *cols = @{}.mutableCopy;
        for( NSTableColumn *column in self.yourTableView.tableColumns){
            cols[column.identifier] = @(!column.isHidden);
        }
    
        [[NSUserDefaults standardUserDefaults] setObject:cols forKey:kUserDefaultsKeyVisibleColumns];
        if(shouldHide){
            [self.yourTableView sizeLastColumnToFit];
        } else {
            [self.yourTableView sizeToFit];
        }
    }
    

    菜单委托

    -(void)menuWillOpen:(NSMenu *)menu {
        for (NSMenuItem *mi in menu.itemArray) {
            NSTableColumn *col = [mi representedObject];
            [mi setState:col.isHidden ? NSOffState : NSOnState];
        }
    }
    

    结果

    所以现在您可以选中/取消选中每一列,即使重新启动您的应用程序,配置也会保存。

    【讨论】:

    • 隐藏列有效,但如果您希望所有列的宽度均匀,它会失败。我在我的 tableview 上使用“uniform”,在我的列上使用“resize with tableview”。取消选中/检查一些后,宽度变得不均匀。知道如何解决这个问题吗?
    • 太棒了!这很好用!我唯一需要添加的是隐藏/显示列的默认值,它可以使用了。谢谢!
    【解决方案3】:

    您需要将NSMenu 附加到具有NSMenuItems 列的表的标题并在右键单击时将其弹出。我通过继承NSViewController 并在其中附加我的表格视图来完成此操作。该类也应该是NSMenuDelegate。下面的例子。

    .h 文件:

    @interface UserManagedColumnsTableViewController : NSViewController <NSMenuDelegate>
    @property (weak) IBOutlet NSTableView *tableView;
    @end
    

    .m 文件:

    @interface UserManagedColumnsTableViewController ()
    - (void)toggleColumn:(id)sender;
    @end
    
    @implementation UserManagedColumnsTableViewController
    
    - (void)awakeFromNib {
      [super awakeFromNib];
      NSMenu *columnsMenu = [[NSMenu alloc] initWithTitle:@""];
      for (NSTableColumn *column in self.tableView.tableColumns) {
        NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:[column.headerCell stringValue]
                                                          action:@selector(toggleColumn:)
                                                   keyEquivalent:@""];
        menuItem.target = self;
        menuItem.representedObject = column;
        [columnsMenu addItem:menuItem];
      }
      columnsMenu.delegate = self;
      [self.tableView.headerView setMenu:columnsMenu];
    }
    
    #pragma mark - NSMenuDelegate conformance
    - (void)menuWillOpen:(NSMenu *)menu {
      for (NSMenuItem *menuItem in menu.itemArray) {
        NSTableColumn *column = [menuItem representedObject];
        [menuItem setState:column.isHidden ? NSOffState : NSOnState];
      }
    }
    
    #pragma mark - Private Methods
    - (void)toggleColumn:(id)sender {
      NSTableColumn *column = [sender representedObject];
      [column setHidden:![column isHidden]];
    }
    
    @end
    

    【讨论】:

      猜你喜欢
      • 2016-08-15
      • 2018-06-27
      • 2015-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-05
      • 1970-01-01
      • 2019-07-07
      相关资源
      最近更新 更多