Dear All,
I am fighting with NSOutline View to perform drag-n-drop within the table since last 2-3 day but couldn't get what i am doing wrong,
This is what i have done so far,
Requirement,
1 -- I want to have a transparent or with some background image NSoutlineview in my view, to do that, i need to overwrite drawRect method of NSOutlineView, this is what i have done
in header file
#interface MyCustomOutlineView:NSOutlineView{
NSImage *pBackgroundImage;
}
- setBackgroundImage:(NSImage *)pImage;
In source file, i just overwrite drawRect and some other stuffs to draw the background image or to make it transparent and this is working fine,
Now in my view, i have declared the NSOutlineView object like that,
/*
* My Custom view will have capability to draw the gradient and other effects
*/
#interface OutlineParentView:MyCustomView<NSOutlineDataSource>{
MyCustomOutlineView *pOutlineView;
}
#property(nonatomic,retain)MyCustomOutlineView *pOutlineView;
In source file, implemented following method ,
This method will be called from the initWIthFrame
#define OutlineViewPrivateDataType "MyOutlinePrivateData"
-(void)InitOutlineView{
NSRect scrollFrame = [self bounds];
NSScrollView* scrollView = [[[NSScrollView alloc] initWithFrame:scrollFrame] autorelease];
[scrollView setBorderType:NSNoBorder];
[scrollView setHasVerticalScroller:YES];
[scrollView setHasHorizontalScroller:NO];
[scrollView setAutohidesScrollers:YES];
[scrollView setDrawsBackground: NO];
NSRect clipViewBounds = [[scrollView contentView] bounds];
pOutlineView = [[[CommUICustomOutlineView alloc] initWithFrame:clipViewBounds] autorelease];
NSTableColumn* firstColumn = [[[NSTableColumn alloc] initWithIdentifier:#"firstColumn"] autorelease];
ImageTextCell *pCell = [[ImageTextCell alloc]init];
[firstColumn setDataCell:pCell];
[pCell setDataDelegate:self];
[firstColumn setWidth:25];
[pOutlineView addTableColumn:firstColumn];
[pOutlineView setRowHeight:30];
[pOutlineView setDataSource:self];
/* setData delegate implemented in the MyOutlineView to handle some of event in this
interface if i don't write this, then i can't handle the menu event on the
Outlineview
*/
[pOutlineView setDataDelegate:self];
**/* On this line i am getting one warning, saying OutlineParentView doesn't implement
NSOutlineView delegate protocol */**
[pOutlineView setDelegate:self];
[scrollView setDocumentView:pOutlineView];
/* I don't want group row to be highlighted */
[pOutlineView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleSourceList];
[pOutlineView registerForDraggedTypes:
[NSArray arrayWithObjects:OutlineViewPrivateDataType,nil]];
[pOutlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES];
[scrollView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
[self addSubview:scrollView];
[self setAutoresizesSubviews:YES];
[self log:#"Outline view created "];
}
Other Important method related to Drag-n-Drop implemented as below
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteb oard:(NSPasteboard *)pboard{
[self log:#"write Items"];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:items];
[pboard declareTypes:[NSArray arrayWithObject:OutlineViewPrivateDataType]
owner:self];
[pboard setData:data forType:OutlineViewPrivateDataType];
return YES;
}
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id < NSDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
{
NSLog(#"validate Drop");
return NSDragOperationEvery;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id < NSDraggingInfo >)info item:(id)item childIndex:(NSInteger)index{
[self log:#"inside accept drop for NSView "];
return YES;
}
I checked apple DragnDrop Sample code, but couldn't get what i am doing wrong,
i believe, some problem with the
[pOutlineView setDelegate:self]
Function, but how to solve that, that i don't know,
I upgraded recently from MyTableView to MyOutlineView, recently i was able to perform Drag-nDrop on the Custom Table view,
Remaining things are working fine, like DataSource etc...
Thanks in Advance
Kind Regards
Rohan
i was setting ColumnWidth so drag-n-drop working for the width which has been set, not on the full row my mistake :(
[firstColumn setWidth:25];
Removing this line working fine
But guys facing some other problem
Regarding NSoutlineView and WriteItem | Drag-and-Drop Problem
Related
I have a curious issue with an iOS 9/ObjC app I am writing using a 4 tab format. The "main" ViewController has several subviews with controls and an image. When the user taps the image a PickerView pops up and it is dismissed with another tap on the image. The other tabbed ViewControllers lead to simple views. It was all put together with IB, except for a single subview on the "main" view where I do some Quartz animation drawing superimposed on the image view there.
If I stay on and interact with just the "main" view, all works exactly as desired. The PickerView appears and disappears as designed. Tabbing to another ViewController, then back to the "main" View leads to the problem: A tap on the image view fails to pop up the Picker. The tap is recognized in the Quartz layer, fires a Notification event which is picked up in the picked up in the main view controller which in turn adds the picker subview, brings it to the front and enables interaction just as when it works properly, but the picker never appears, even though the Debugger shows it successfully added to the subview array.
Even stranger, if I tab off the main to any other tab view, then back to main, the picker now appears again as it should. This sequence is completely repeatable - tab once off the main, and the picker doesn't visualize, tab again and then back to main and the picker works.
Any thoughts on where to start looking? Thanks
Here's some code (but I'm not sure where the problem is)
#implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.picker = [[UIPickerView alloc] init];
self.picker.datasource = self;
self.picker.delegate = self;
float screenWidth = [UIScreen mainScreen].bounds.size.width;
float pickerWidth = screenWidth * 3 / 4;
// Calculate the starting x coordinate.
float xPoint = screenWidth / 2 - pickerWidth / 2;
[self.Picker setFrame: CGRectMake(xPoint, 50.0f, pickerWidth, 250.0f)];
[self.Picker setClipsToBounds:NO];
[self.Picker setBackgroundColor:[UIColor whiteColor]];
self.Picker.showsSelectionIndicator = YES;
self.Picker.userInteractionEnabled = YES;
.
.
.
UIImage *base = [UIImage imageNamed:#"Base"];
self.baseAView = [[UIImageView alloc] initWithFrame:imFrame];
[self.baseView setImage:base];
[self.view addSubview:_baseView];
self.GView = [[GView alloc] initWithFrame:imFrame];
self.GView.backgroundColor = [UIColor clearColor];
[self.view addSubview:_GView];
}
-(void) viewDidAppear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(doSin) name:#"touchP" object:nil];
}
- (void) doSin {
// user hits GView, draw Picker if not in View Hierarchy, if in Hierarch, grab value and resign
NSArray *subViews = [self.view subviews];
__block NSInteger foundIndex = NSNotFound;
[subViews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[UIPickerView class]]) {
foundIndex = idx;
// stop the enumeration
*stop = YES;
}
}];
if (foundIndex != NSNotFound) {
// Found the UIPickerView in subviews, so grab value & remove from screen
[self.view.subviews[foundIndex] removeFromSuperview];
} else {
// not in hierarchy, so put it up on screen
[self.view addSubview:self.Picker];
[self.view bringSubviewToFront:self.Picker];
self.view.userInteractionEnabled = YES;
}
}
When i try to add ATMHud to uitableviewcontroller subview it does work but it doesn't disable the scrolling and if the tableview is not on top i can't see the hud view. What i did was added to teh tabBarController.view that works but i want find out if this is a good idea or later on i might have issues with it.
Another question is tabBarController.view frame is that the whole screen or just the bottom part. How come atmhud shows in the middle of the screen?
Thanks in advance!
Yan
============
Found a blog post that shows how to reset self.view and add tableview separately in uitableviewcontroller
UITableViewController and fixed sub views
- (void)viewDidLoad {
[super viewDidLoad];
if (!tableView &&
[self.view isKindOfClass:[UITableView class]]) {
tableView = (UITableView *)self.view;
}
self.view = [[[UIView alloc] initWithFrame:
[UIScreen mainScreen].applicationFrame] autorelease];
self.tableView.frame = self.view.bounds;
self.tableView.contentInset = UIEdgeInsetsMake(44.0, 0.0, 0.0, 0.0);
[self.view addSubview:self.tableView];
UIView *fixedBar = [[UIView alloc] initWithFrame:
CGRectMake(0.0, 0.0, self.view.bounds.size.width, 44.0)];
fixedBar.backgroundColor = [UIColor colorWithRed:
0.0 green:1.0 blue:0.0 alpha:0.7];
[self.view addSubview:fixedBar];
[fixedBar release];
}
After this when add hud to self.view you will be able to disable the tableview on the bottom.
Let me know if this a good way to setup the tableview
The problem with using the tab bar is that the hud is now modal, and the user cannot change the tab.
It sounds like the tableview is not your primary viewm, as it can get "covered up". If its not the primary view, then add the ATMHud to self.view. If the tableView is the same as self.view, then add a new transparent view to it, then add the HUD to that view.
The tabBarController.view is the view that hosts the tabbed views - if you want to see its size (or frame) log it using NSStringFromCGRect(self.tabBarController.frame);
EDIT: I just did a test, the ATMHud DOES block the UI. All I can think of is that you have not inserted it where you need to (at the top of current view's subviews.) I have a demo project where I do this:
hud = [[ATMHud alloc] initWithDelegate:self];
[self.view addSubview:hud.view];
[hud setCaption:#"Howdie"];
[hud setActivity:YES];
[hud show];
[hud hideAfter:5];
A button under the hud is not active - in fact nothing in the view is active (probably the Nav Bar would be live though)
If you want an ARCified and field tested version, you can grab it here
EDIT2: The solution to your problem is below. Note that ATMHud blocks clicks from getting to the table, and the code below stops the scrolling:
- (void)hudWillAppear:(ATMHud *)_hud
{
self.tableView.scrollEnabled = NO;
}
- (void)hudDidDisappear:(ATMHud *)_hud
{
self.tableView.scrollEnabled = YES;
}
Dump the views:
#import <QuartzCore/QuartzCore.h>
#import "UIView+Utilities.h"
#interface UIView (Utilities_Private)
+ (void)appendView:(UIView *)v toStr:(NSMutableString *)str;
#end
#implementation UIView (Utilities_Private)
+ (void)appendView:(UIView *)a toStr:(NSMutableString *)str
{
[str appendFormat:#" %#: frame=%# bounds=%# layerFrame=%# tag=%d userInteraction=%d alpha=%f hidden=%d\n",
NSStringFromClass([a class]),
NSStringFromCGRect(a.frame),
NSStringFromCGRect(a.bounds),
NSStringFromCGRect(a.layer.frame),
a.tag,
a.userInteractionEnabled,
a.alpha,
a.isHidden
];
}
#end
#implementation UIView (Utilities)
+ (void)dumpSuperviews:(UIView *)v msg:(NSString *)msg
{
NSMutableString *str = [NSMutableString stringWithCapacity:256];
while(v) {
[self appendView:v toStr:str];
v = v.superview;
}
[str appendString:#"\n"];
NSLog(#"%#:\n%#", msg, str);
}
+ (void)dumpSubviews:(UIView *)v msg:(NSString *)msg
{
NSMutableString *str = [NSMutableString stringWithCapacity:256];
if(v) [self appendView:v toStr:str];
for(UIView *a in v.subviews) {
[self appendView:a toStr:str];
}
[str appendString:#"\n"];
NSLog(#"%#:\n%#", msg, str);
}
#end
Is it possible to draw multiple NSImages in a single NSView?
So far drawing in an NSView subclass is done like so:
- (void)drawRect:(NSRect)dirtyRect
{
[image drawInRect:NSMakeRect(0.0f, 0.0f, 100.0f, 100.0f) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0f];
}
//to change the current image
- (void)newImage:(NSImage *)image_
{
[image release];
image = [image_ retain];
[self setNeedsDisplay:YES];
}
But this is for drawing just one image. Can anyone please help out?
Thanks.
You have to keep references to the images you need to draw.
#interface MyView : NSView
{
NSMutableArray* images;
}
Then, add the images with a suitable API, for example:
#implementation MyView
- (void) addImage: (NSImage *) anImage
{
[images addObject: anImage];
[self setNeedsDisplay: YES];
}
In drawRect: you can iterate through the images and draw all/some of them.
I've been able to find tutorials on modifying the table headers on iOS using UITableView - but havent been able to find any info for mac development. Does anyone know of any good resources / steps to modify the appearance of tables?
Zach
To change how the table headers appear you need to subclass NSTableHeaderCell, perform your own custom drawing in one of its drawing methods, then replace the header cells of each column with an instance of your subclass.
You may also find that you need to subclass NSTableHeaderView to draw the any space where no header cells are visible, and to replace the cornerView of the table view.
This should get you started:
for (NSTableColumn *column in [tableView tableColumns]) {
[column setHeaderCell:
[[[MyHeaderCell alloc]
initTextCell:[[column headerCell] stringValue]]
autorelease]];
}
And here’s a starting point for a subclass of NSTableHeaderCell:
#interface MyHeaderCell : NSTableHeaderCell
{
}
- (void)drawWithFrame:(CGRect)cellFrame
highlighted:(BOOL)isHighlighted
inView:(NSView *)view;
#end
#implementation MyHeaderCell
- (void)drawWithFrame:(CGRect)cellFrame
highlighted:(BOOL)isHighlighted
inView:(NSView *)view
{
CGRect fillRect, borderRect;
CGRectDivide(cellFrame, &borderRect, &fillRect, 1.0, CGRectMaxYEdge);
NSGradient *gradient = [[NSGradient alloc]
initWithStartingColor:[NSColor whiteColor]
endingColor:[NSColor colorWithDeviceWhite:0.9 alpha:1.0]];
[gradient drawInRect:fillRect angle:90.0];
[gradient release];
if (isHighlighted) {
[[NSColor colorWithDeviceWhite:0.0 alpha:0.1] set];
NSRectFillUsingOperation(fillRect, NSCompositeSourceOver);
}
[[NSColor colorWithDeviceWhite:0.8 alpha:1.0] set];
NSRectFill(borderRect);
[self drawInteriorWithFrame:CGRectInset(fillRect, 0.0, 1.0) inView:view];
}
- (void)drawWithFrame:(CGRect)cellFrame inView:(NSView *)view
{
[self drawWithFrame:cellFrame highlighted:NO inView:view];
}
- (void)highlight:(BOOL)isHighlighted
withFrame:(NSRect)cellFrame
inView:(NSView *)view
{
[self drawWithFrame:cellFrame highlighted:isHighlighted inView:view];
}
#end
Code to change column header in tableView:
NSString *title = #"Your Title";
NSTableColumn *yourColumn = self.tableView.tableColumns.lastObject;
[yourColumn.headerCell setStringValue:title];
I'm trying to add a tableview to a view in code instead of using Interface Builder and unfortunately it's causing some problems =(
Here's an example of how I'm doing it now.
NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame:someRect];
NSTableView *tableView = [[NSTableView alloc] initWithFrame: scrollView.bounds];
resultsTableView.dataSource = self;
resultsScrollView.documentView = tableView;
[someView addSubview: scrollView];
So basically I'm just putting the tableView inside the scrollView (because that's what IB is doing) and then adding the latter as a subview of the someView. The result is that a tableView appears - but the no data is shown within the tableView. Debugging shows that the dataSource is being asked for how many rows are in the tableView but the method:
tableView:objectValueForTableColumn:row:
is never being called. I suspect that this is because of my way of creating the tableView.
I've tried google but no luck and the "Introduction to Table Views Programming Guide" on macdevcenter wasn't helpful either. What am I missing?
Thanks in advance...
I created the default sample project and then did the following:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSRect scrollFrame = NSMakeRect( 10, 10, 300, 300 );
NSScrollView* scrollView = [[[NSScrollView alloc] initWithFrame:scrollFrame] autorelease];
[scrollView setBorderType:NSBezelBorder];
[scrollView setHasVerticalScroller:YES];
[scrollView setHasHorizontalScroller:YES];
[scrollView setAutohidesScrollers:NO];
NSRect clipViewBounds = [[scrollView contentView] bounds];
NSTableView* tableView = [[[NSTableView alloc] initWithFrame:clipViewBounds] autorelease];
NSTableColumn* firstColumn = [[[NSTableColumn alloc] initWithIdentifier:#"firstColumn"] autorelease];
[[firstColumn headerCell] setStringValue:#"First Column"];
[tableView addTableColumn:firstColumn];
NSTableColumn* secondColumn = [[[NSTableColumn alloc] initWithIdentifier:#"secondColumn"] autorelease];
[[secondColumn headerCell] setStringValue:#"Second Column"];
[tableView addTableColumn:secondColumn];
[tableView setDataSource:self];
[scrollView setDocumentView:tableView];
[[[self window] contentView] addSubview:scrollView];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
{
return 100;
}
- (id) tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
{
NSString* cellValue = [NSString stringWithFormat:#"%# %ld", [aTableColumn identifier], (long)rowIndex];
return cellValue;
}
You can grab the sample app TableViewInCode
(Oh, to the objective-c dot syntax, just say no. :-)
The result is that a tableView appears - but the no data is shown within the tableView. Debugging shows that the dataSource is being asked for how many rows are in the tableView but the method:
tableView:objectValueForTableColumn:row:
is never being called.
It's not asking you for the object values for any columns because it doesn't have any columns. Create some NSTableColumn instances and add them to the table view.
It doesn't appear (from your sample) that you're putting the tableView inside the scrollView. Is it getting added as a subview somewhere you're not showing us?
Also, are you sure you need a separate scrollview? Doesn't tableView implement scrolling already?