تسليط الضوء على الاختيار في NSCOLLECTIONVIEW
-
23-09-2019 - |
سؤال
لدي عمل NSCollectionView
مع استثناء صغير ، ولكن حرج ،. الحصول على العنصر المحدد وتسليط الضوء عليه داخل المجموعة.
لقد كان لدي كل هذا العمل قبل Snow Leopard ، لكن يبدو أن هناك شيئًا ما قد تغير ولا يمكنني وضع إصبعي عليه ، لذلك أخذت بلدي NSCollectionView
العودة مباشرة إلى اختبار أساسي واتبع وثائق Apple لإنشاء nscollectionView هنا:
يعمل عرض المجموعة بشكل جيد بعد دليل البدء السريع. ومع ذلك ، فإن هذا الدليل لا يناقش الاختيار بخلاف "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
وخلافا لمعظم طرق عرض واجهة المستخدم الكاكاو ، يبدو أنه لا يوجد تسليط الضوء الافتراضي المحدد.
لذا فإن مشكلتي تعود حقًا إلى قضية ذات صلة ، ولكن سؤالين متميزين.
- كيف يمكنني التقاط مجموعة مختارة من عنصر؟
- كيف أعرض تسليط الضوء على عنصر؟
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 وربط السمة المخفية لعنصر عرض المجموعة.
(في حالتي ، قمت بإنشاء NIB منفصل لـ CollectionViewItem ، لذلك يرتبط بمالك الملف. إذا لم يكن هذا هو الحال وعرض العنصر في نفس المنظم القومي مثل CollectionView ثم ربط عنصر عرض المجموعة)
تعيين مسار مفتاح النموذج كما selected
ومحول القيمة إلى NSNegateBoolean
. هذا الآن عندما يتم تحديد الخلايا الفردية/العناصر ، ستكون الصورة مرئية ، وبالتالي تشير إلى التحديد.
إضافة إلى إجابة Alter.
لتعيين NSBox كعنصر الجذر. ما عليك سوى إنشاء مستند IB جديد (say CollectionItem) واسحب nsbox إلى المنطقة الفارغة. أضف الآن جميع العناصر كما هو مطلوب داخل المربع. الآن انقر على مالك الملف وضبط فئة مخصصة على أنها NSCollectionViewItem
.
وفي المنقار حيث NSCollectionView
يضاف تغيير اسم NIB ل CollectionViewItem
في NSBOX ، ربط العناصر المتبقية Files Owner
. لتسمية سيكون مشابهًا لـ:
الآن للحصول على اللون البارز مثل تغيير المذكور في إجابته ، مجموعة ملونة المطلوبة في خيار لون التعبئة ، اضبط NSBox
للشفافية وربط سمة الشفافية على النحو التالي:
الآن عند تحديد عناصر عرض المجموعة ، يجب أن تكون قادرًا على رؤية لون ملء المربع.
في الخاص بك 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
}
}