سؤال

لدي عمل NSCollectionView مع استثناء صغير ، ولكن حرج ،. الحصول على العنصر المحدد وتسليط الضوء عليه داخل المجموعة.

لقد كان لدي كل هذا العمل قبل Snow Leopard ، لكن يبدو أن هناك شيئًا ما قد تغير ولا يمكنني وضع إصبعي عليه ، لذلك أخذت بلدي NSCollectionView العودة مباشرة إلى اختبار أساسي واتبع وثائق Apple لإنشاء nscollectionView هنا:

http://developer.apple.com/mac/library/documentation/cocoa/conceptual/collectionViews/introduction/introduction.html

يعمل عرض المجموعة بشكل جيد بعد دليل البدء السريع. ومع ذلك ، فإن هذا الدليل لا يناقش الاختيار بخلاف "There are such features as incorporating image views, setting objects as selectable or not selectable and changing colors if they are selected".

باستخدام هذا كمثال ، ذهبت إلى الخطوة التالية في ربط وحدة تحكم الصفيف ب NSCollectionView مع مفتاح وحدة التحكم selectionIndexes, ، التفكير في أن هذا من شأنه أن يربط أي اختيار أقوم به بين NSCollectionView ووحدة تحكم المصفوفة وبالتالي إطلاق إشعار KVO. أنا أيضا تعيين NSCollectionView لتكون قابلة للاختيار في IB.

يبدو أنه لا يوجد مندوب اختيار ل NSCollectionView وخلافا لمعظم طرق عرض واجهة المستخدم الكاكاو ، يبدو أنه لا يوجد تسليط الضوء الافتراضي المحدد.

لذا فإن مشكلتي تعود حقًا إلى قضية ذات صلة ، ولكن سؤالين متميزين.

  1. كيف يمكنني التقاط مجموعة مختارة من عنصر؟
  2. كيف أعرض تسليط الضوء على عنصر؟

NSCollectionViewيبدو أن أدلة البرمجة قليلة ومتباعدة ، ويبدو أن معظم عمليات البحث عبر Google تسحب تطبيقات الفهد قبل Snow ، أو استخدام العرض في ملف XIB منفصل.

بالنسبة إلى الأخير (ملف XIB منفصل للعرض) ، لا أرى لماذا يجب أن يكون هذا شرطًا مسبقًا وإلا كنت سأشتبه في أن Apple لن تضمن العرض في نفس الحزمة كعنصر عرض المجموعة.

أعلم أن هذا سيكون "لا يمكن رؤية الحطب من أجل الأشجار" - لذلك أنا مستعد لـ "Doh!" الوقت الحاضر.

كالعادة ، أي وجميع تساعد في تقدير كبير.

تحديث 1

حسنًا ، لذلك اعتقدت العثور على العنصر (العناصر) المحددة ، لكن لم أكن لأتوقع تسليط الضوء بعد. لمعرفة المهتمين بمعرفة العناصر المحددة (على افتراض أنك تتبع دليل Apple):

في وحدة التحكم (في حالة الاختبار الخاصة بي ، أضفت ما يلي:

في Awakefromnib

[personArrayController addObserver:self
       forKeyPath:@"selectionIndexes" 
       options:NSKeyValueObservingOptionNew
       context:nil];

أسلوب جديد

-(void)observeValueForKeyPath:(NSString *)keyPath 
                     ofObject:(id)object
                       change:(NSDictionary *)change
                      context:(void *)context
{
    if([keyPath isEqualTo:@"selectionIndexes"])
    {
        if([[personArrayController selectedObjects] count] > 0)
        {
            if ([[personArrayController selectedObjects] count] == 1)
            {
                personModel * pm = (PersonModel *) 
                       [[personArrayController selectedObjects] objectAtIndex:0];
                NSLog(@"Only 1 selected: %@", [pm name]);
            }
            else
            {
                // More than one selected - iterate if need be
            }
        }
    }

لا تنسى أن تعامل لغير GC

-(void)dealloc
{
    [personArrayController removeObserver:self 
                               forKeyPath:@"selectionIndexes"];
    [super dealloc];
}

لا تزال تبحث عن قرار تسليط الضوء ...

تحديث 2

أخذ نصيحة Macatomy ولكن لا يزال لديه مشكلة. نشر أساليب الفصل ذات الصلة لمعرفة أين أخطأت.

myview.h

#import <Cocoa/Cocoa.h>

@interface MyView : NSView {
    BOOL selected;
}

@property (readwrite) BOOL selected;

@end

myview.m

#import "MyView.h"

@implementation MyView

@synthesize selected;

-(id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code here.
    }
    return self;
}

-(void)drawRect:(NSRect)dirtyRect
{
    NSRect outerFrame = NSMakeRect(0, 0, 143, 104);
    NSRect selectedFrame = NSInsetRect(outerFrame, 2, 2);

    if (selected)
        [[NSColor yellowColor] set];
    else
        [[NSColor redColor] set];

    [NSBezierPath strokeRect:selectedFrame];
}

@end

MyCollectionViewitem.H

#import <Cocoa/Cocoa.h>
@class MyView;

@interface MyCollectionViewItem : NSCollectionViewItem {

}

@end

"myCollectionViewitem.M*

#import "MyCollectionViewItem.h"
#import "MyView.h"

@implementation MyCollectionViewItem

-(void)setSelected:(BOOL)flag
{

    [(MyView *)[self view] setSelected:flag];
    [(MyView *)[self view] setNeedsDisplay:YES];
}

@end
هل كانت مفيدة؟

المحلول

ليس من الصعب جدا القيام به. تأكد من تمكين "التحديد" لـ NSCOLLECTIONVIEW في Builder Interface. ثم في الفئة الفرعية NSVIEW التي تستخدمها في عرض النموذج الأولي الخاص بك ، أعلن خاصية تسمى "محدد":

@property (readwrite) BOOL selected;

رمز محدث هنا: (إضافة سوبر مكالمة)

الفئة الفرعية nscollectionViewitem و Override -selected:

- (void)setSelected:(BOOL)flag
{
    [super setSelected:flag];
    [(PrototypeView*)[self view] setSelected:flag];
    [(PrototypeView*)[self view] setNeedsDisplay:YES];
}

ثم تحتاج إلى إضافة رمز في سحب عرض النموذج الأولي الخاص بك: طريقة لرسم تسليط الضوء:

- (void)drawRect:(NSRect)dirtyRect 
{
    if (selected) {
       [[NSColor blueColor] set];
       NSRectFill([self bounds]);
    }
}

هذا ببساطة يملأ العرض باللون الأزرق عند اختياره ، ولكن يمكن تخصيصه لرسم البذيلة بأي طريقة تريدها. لقد استخدمت هذا في تطبيقاتي الخاصة ويعمل بشكل رائع.

نصائح أخرى

إذا كان لون الخلفية مختلفًا كافيًا كإصدار تسليط الضوء ، فيمكنك ببساطة استخدام NSBox كعنصر جذر لعنصر المجموعة. املأ NSBox بلون تسليط الضوء على اختيارك. قم بتعيين NSBox على Custom بحيث ستعمل التعبئة. اضبط NSBox على شفاف.

قم بربط سمة الشفافية لـ NSBox بالسمات المحددة لمالك الملف (عنصر المجموعة) قم بتعيين محول القيمة للربط الشفاف بـ NSNegateboolean.

حاولت إرفاق لقطات شاشة منشئ الواجهة ، لكنني رفضت BCOs أنا مبتدئ :-(

يمكنك أيضًا الذهاب إلى طريقة أخرى ، إذا لم تكن NSView فرعيًا لعرض Protoype الخاص بك.

في تجاوز nscollectionviewitem setSelected:

- (void)setSelected:(BOOL)selected
{
    [super setSelected:selected];
    if (selected)
        self.view.layer.backgroundColor = [NSColor redColor].CGColor;
    else
        self.view.layer.backgroundColor = [NSColor clearColor].CGColor;
}

وبالطبع ، كما قال جميع الأشخاص الحكيمين قبلي ، تأكد من تمكين "الاختيار" لـ NSCollectionView في Builder Interface.

نظرًا لأن أيًا من الإجابات الحالية عملت بشكل جيد بالنسبة لي ، فإليك رأيي عليه. قم بتغيير الفئة الفرعية لعنصر CollectionView إلى SelectableCollectionViewItem. هنا هو رمز. يأتي مع خاصية TextColor قابلة لترتيب لتثبيط ملصق النص الخاص بك ملزمة ملزمة ل.

@implementation SelectableCollectionViewItem

+ (NSSet *)keyPathsForValuesAffectingTextColor
{
    return [NSSet setWithObjects:@"selected", nil];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.wantsLayer = YES;
}

- (void) viewDidAppear
{
    // seems the inital selection state is not done by Apple in a KVO compliant manner, update background color manually
    [self updateBackgroundColorForSelectionState:self.isSelected];
}

- (void)updateBackgroundColorForSelectionState:(BOOL)flag
{
    if (flag)
    {
        self.view.layer.backgroundColor = [[NSColor alternateSelectedControlColor] CGColor];
    }
    else
    {
        self.view.layer.backgroundColor = [[NSColor clearColor] CGColor];
    }
}

- (void)setSelected:(BOOL)flag
{
    [super setSelected:flag];
    [self updateBackgroundColorForSelectionState:flag];
}

- (NSColor*) textColor
{
    return self.selected ? [NSColor whiteColor] : [NSColor textColor];
}

في حالتي ، أردت صورة (علامة الاختيار) للإشارة إلى اختيار الكائن. اسحب صورة ImageWell إلى NIB للتجميع. اضبط الصورة المطلوبة ووضع علامة عليها على أنها مخفية. انتقل إلى Bindings Inspector وربط السمة المخفية لعنصر عرض المجموعة.

enter image description here

(في حالتي ، قمت بإنشاء NIB منفصل لـ CollectionViewItem ، لذلك يرتبط بمالك الملف. إذا لم يكن هذا هو الحال وعرض العنصر في نفس المنظم القومي مثل CollectionView ثم ربط عنصر عرض المجموعة)

تعيين مسار مفتاح النموذج كما selected ومحول القيمة إلى NSNegateBoolean. هذا الآن عندما يتم تحديد الخلايا الفردية/العناصر ، ستكون الصورة مرئية ، وبالتالي تشير إلى التحديد.

إضافة إلى إجابة Alter.

لتعيين NSBox كعنصر الجذر. ما عليك سوى إنشاء مستند IB جديد (say CollectionItem) واسحب nsbox إلى المنطقة الفارغة. أضف الآن جميع العناصر كما هو مطلوب داخل المربع. الآن انقر على مالك الملف وضبط فئة مخصصة على أنها NSCollectionViewItem.

enter image description here

وفي المنقار حيث NSCollectionView يضاف تغيير اسم NIB ل CollectionViewItem

enter image description here

في NSBOX ، ربط العناصر المتبقية Files Owner. لتسمية سيكون مشابهًا لـ:

enter image description here

الآن للحصول على اللون البارز مثل تغيير المذكور في إجابته ، مجموعة ملونة المطلوبة في خيار لون التعبئة ، اضبط NSBox للشفافية وربط سمة الشفافية على النحو التالي:

enter image description here

الآن عند تحديد عناصر عرض المجموعة ، يجب أن تكون قادرًا على رؤية لون ملء المربع.

في الخاص بك NSCollectionViewItem الفئة الفرعية ، تجاوز isSelected وتغيير لون الخلفية للطبقة. اختبار في MacOS 10.14 و Swift 4.2

class Cell: NSCollectionViewItem {

  override func loadView() {    
    self.view = NSView()
    self.view.wantsLayer = true
  }

  override var isSelected: Bool {
    didSet {
      self.view.layer?.backgroundColor = isSelected ? NSColor.gray.cgColor : NSColor.clear.cgColor
    }
  }
}

كان هذا رائع ، شكرا جزيلا! كنت أعاني من هذا!

للتوضيح للآخرين:

 [(PrototypeView*)[self view] setSelected:flag];
 [(PrototypeView*)[self view] setNeedsDisplay:YES];

استبدل النموذج الأولي* باسم اسم فئة النموذج الأولي الخاص بك.

في حال كنت تحفر حول الحل السريع المحدث ، انظر هذا الرد.

class MyViewItem: NSCollectionViewItem {
  override var isSelected: Bool {
      didSet {
        self.view.layer?.backgroundColor = (isSelected ? NSColor.blue.cgColor : NSColor.clear.cgColor)
      }
  }
  etc...
}

هنا هو NSCollectionViewitem السريع الكامل مع الاختيار. لا تنسى ضبط NSCOLLECTIOVIEW على اختيار في IB أو برمجيًا. تم اختباره تحت Macos Mojave (10.14) و High Sierra (10.13.6).

import Cocoa

class CollectionViewItem: NSCollectionViewItem {

private var selectionColor : CGColor {
    let selectionColor : NSColor = (isSelected ? .alternateSelectedControlColor : .clear)
    return selectionColor.cgColor
}

override var isSelected: Bool {
    didSet {
        super.isSelected = isSelected
        updateSelection()
        // Do other stuff if needed
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    view.wantsLayer = true
    updateSelection()
}

override func prepareForReuse() {
    super.prepareForReuse()
    updateSelection()
}

private func updateSelection() {
    view.layer?.backgroundColor = self.selectionColor
}
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top