DrawRect Square/Rectangle user values - objective-c

I've got the books, I've checked the apple docs and something is not clicking.
Here's what I want to do: get user values and draw a square/rectangle with them.
A window with one custom view on the right.
On the left two text fields, two labels (width and height) and a button "Draw".
On the right DrawView.
There's how one could do it:
You have to do the connection for the textFields and the button in your appDelegate and also have an IBOutlet for your customView.
In your customView you need to have the two variables which will hold the values from the textField. Don't use property/synthesize because once you set the values you need to call setNeedsDisplay in your customView-DrawView.
AppDelegate.h
#import <Cocoa/Cocoa.h>
#import "DrawView.h"
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (assign) IBOutlet NSWindow *window;
#property (weak) IBOutlet DrawView *myDrawView;
#property (weak) IBOutlet NSTextField *widthTextField;
#property (weak) IBOutlet NSTextField *heightTextField;
- (IBAction)draw:(id)sender;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "DrawView.h"
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
}
- (IBAction)draw:(id)sender {
[_myDrawView setWidth:[_widthTextField floatValue]];
[_myDrawView setHeight:[_heightTextField floatValue]];
}
DrawView.h
#import <Cocoa/Cocoa.h>
#interface DrawView : NSView {
float width;
float height;
}
-(void) setWidth: (float) aWidth;
-(void) setHeight: (float) aHeight;
#end
DrawView.m
#import "DrawView.h"
#implementation DrawView
#pragma mark - Setters
-(void) setWidht:(float)aWidth {
width = aWidth;
[self setNeedsDisplay:YES];
}
-(void) setHeight:(float)aHeight {
height = aHeight;
[self setNeedsDisplay:YES];
}
#pragma mark - Drawing
- (id)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setWidth:10];
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect {
//BackGround Color
[[NSColor whiteColor] setFill];
NSRectFill(dirtyRect);
[super drawRect:dirtyRect];
NSBezierPath* square = [NSBezierPath bezierPath];
[square setLineWidth:2];
NSRect squareRect = NSMakeRect(10,10,width,height);
[square appendBezierPathWithRoundedRect:squareRect xRadius:5 yRadius:5];
[square stroke];
}
#end
That's it. I don't know if there's a better way to do it. It seems a bit bizarre.

Yes it´s nill in drawRect but just before it reaches drawRect it's not because I can calculate the area with the same values...Could you please try it. It takes only 5' to do it.

Related

Objective-c floating button, same procedure different behaviour

I have a created a floating button on a UITableViewController. It works like expected.
Now I wanted to use the button as well on a UIViewController where I added a UITableView.
The code for creating the floating button is identically, but the behaviour is different.
At the UITableViewController the button stay where it shall.
At the UIViewController the button moves up (when I scroll down) and down (when I scroll up)
How do I get the button stay where it shall on the UIViewController. Like on the UITableViewController?
TableViewController.h
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "SingletonClass.h"
#interface MagTableViewController : UITableViewController <UIGestureRecognizerDelegate>
#property (strong, nonatomic) IBOutlet UITableView *magTableView;
#property (strong, nonatomic) UIButton *oButton;
#property (nonatomic) float originalOrigin;
#end
TableViewController.m - floating button, works like expected
- (void)viewDidLoad
{
[super viewDidLoad];
SingletonClass *sharedSingleton = [SingletonClass sharedInstance];
self.originalOrigin = sharedSingleton.photoButtonY; // 430.0
[self addOverlayButton];
}
#pragma mark Camera Button
- (void)addOverlayButton {
self.oButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.oButton.frame = CGRectMake(132.0, self.originalOrigin, 56.0, 56.0);
[self.oButton setImage:[UIImage imageNamed:#"CameraButton56x56.png"] forState:UIControlStateNormal];
[self.oButton addTarget:self action:#selector(toCameraView:) forControlEvents:UIControlEventTouchUpInside];
[self.view insertSubview:self.oButton aboveSubview:self.view];
}
// to make the button float over the tableView including tableHeader
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGRect tableBounds = self.tableView.bounds; // should be _magTableView, but works with _tableView as well. But I do not know where this _tableView comes from...
//CGRect tableBounds = self.magTableView.bounds;
// floating Button;
CGRect floatingButtonFrame = self.oButton.frame;
floatingButtonFrame.origin.y = self.originalOrigin + tableBounds.origin.y;
self.oButton.frame = floatingButtonFrame;
[self.view bringSubviewToFront:self.oButton]; // float over the tableHeader
}
ViewController.h
#import <UIKit/UIKit.h>
#import "SingletonClass.h"
#interface DetailViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) UIButton *oButton;
#property (nonatomic) float originalOrigin;
#end
ViewController.m - Jumping Button, not wanted behaviour (Update: works no, no jumping anymore)
- (void)viewDidLoad
{
[super viewDidLoad];
self.originalOrigin = [[SingletonClass sharedInstance] photoButtonY]; // 430.0
[self addOverlayButton];
[self initTableView]; // initiate the tableview and works properly
}
#pragma mark Camera Button
- (void)addOverlayButton {
self.oButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.oButton.frame = CGRectMake(132.0, self.originalOrigin, 56.0, 56.0);
[self.oButton setImage:[UIImage imageNamed:#"CameraButton56x56.png"] forState:UIControlStateNormal];
[self.oButton addTarget:self action:#selector(toCameraView:) forControlEvents:UIControlEventTouchUpInside];
[self.view insertSubview:self.oButton aboveSubview:self.view];
}
/** Remove this function and the button stayed where I expected it
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGRect tableBounds = self.tableView.bounds;
// floating Button;
CGRect floatingButtonFrame = self.oButton.frame;
floatingButtonFrame.origin.y = self.originalOrigin + tableBounds.origin.y;
self.oButton.frame = floatingButtonFrame;
[self.view bringSubviewToFront:self.oButton]; // float over the tableHeader
}
*/

pass slider value to subview

I have a UISlider placed in my main view and I have added a subview UIView (via interface builder) that I have associated with its own class SecondView. I need to pass the value of the slider to my sub view to move a point in the sub view when the slider changes.
I have made changes to the original code and the the below paragraph no longer is accurate. I used used the suggested changes offered by #MatthiasBauch.
I thought it would be simple a matter of sharing an iVar between the two. I created an iVar myPoint using #property (if this is still considered an iVar) in my ViewController interface, set myPoint = sliderValue.value in my ViewController implementation in the IBAction for when the slider value changes. Then in my SecondView implementation I #import "ViewController.h" then call my call my iVar in my SecondView implementation but the way I have done it it only returns nil or 0 instead of the slider value.
I don't want to use global variables.
I have looked at other post that seem to be asking a similar question but I'm still missing the concept, I guess. My code is below.
ViewController.h
#import <UIKit/UIKit.h>
#import "SecondView.h"
#interface ViewController : UIViewController
{
SecondView *secondView; // Do I need this with secondView declared as a #property below?
}
#property (nonatomic, retain) SecondView *secondView;
- (IBAction)sliderChanged:(id)sender;
#property (weak, nonatomic) IBOutlet UISlider *sliderValue;
#property (weak, nonatomic) IBOutlet UILabel *myLabel;
#property (weak, nonatomic) IBOutlet UIView *myView;
#end
ViewController.m
#import "ViewController.h"
#import "SecondView.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize sliderValue, myLabel, myView, secondView;
- (void)viewDidLoad
{
[super viewDidLoad];
secondView.thePoint = 50;
NSLog(#"%f", secondView.thePoint); // This is retuning a zero
}
- (IBAction)sliderChanged:(id)sender
{
secondView.thePoint = sliderValue.value;
myLabel.text = [NSString stringWithFormat:#"%.2f", sliderValue.value];
[secondView setNeedsDisplay];
}
#end
SecondView.h
#import <UIKit/UIKit.h>
#interface SecondView : UIView
#property (assign, nonatomic) CGFloat thePoint;
#end
SecondView.m
#import "SecondView.h"
#implementation SecondView
#synthesize thePoint;
- (void)drawRect:(CGRect)rect
{
float aPoint = thePoint;
NSLog(#"%f", aPoint); // this is retuning 0.000000
UIBezierPath *point = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(aPoint, 100, 4, 4)];
[point fill];
}
#end
Tell the view where to draw and don't ask the (newly allocated) viewController where to draw.
You are allocating a new viewController, this viewController of course does not know the value you set in the viewController where you actually changed the slider.
This won't work. Those two viewControllers are not the same instance. They share the same class, but that's it. Values from one viewController instance don't magically appear in a second instance.
Instead you should set a point property of the secondary view in your slider action.
Something like this:
Add a float #property to your view
#interface SecondView : UIView
#property (assign, nonatomic) CGFloat point;
#end
to draw use that point and not the initial value from a new ViewController instance.
- (void)drawRect:(CGRect)rect
{
float aPoint = self.point;
UIBezierPath *point = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(aPoint, 100, 4, 4)];
[point fill];
}
and set the point property of the secondary view in the slider action
- (IBAction)sliderChanged:(id)sender
{
secondView.point = sliderValue.value;
[secondView setNeedsDisplay]; // you might be able to omit that
myLabel.text = [NSString stringWithFormat:#"%.2f", myPoint];
}
Your ViewController has a property called #myView which points to the instance of SecondView created by the runtime.
So, your ViewController's implementation could call the drawRect: method on myView and pass in the relevant coordinates.
Here's some pseudo code for your ViewController.
- (IBAction)sliderChanged:(id)sender
{
myPoint = sliderValue.value;
myLabel.text = [NSString stringWithFormat:#"%.2f", myPoint];
[myView drawRect:CGRectMake(myPoint, 100, 4, 4)];
}
Note however that in your ViewController, myView is just a UIView, not a SecondView. You have a few choices on how to resolve this. The cleanest way is probably to remove the #import ViewController.h from SecondView and instead do the opposite. That is, have ViewController do an #import SecondView.h, then promote myView to a SecondView.
If that doesn't work for some reason (for example, if XCode demands that it remain strictly a UIView), you can still upcast the myView property at runtime like this:
[(*SecondView)myView drawRect:CGRectMake(myPoint, 100, 4, 4)];
Alternatively, you could point your slider's action at myView like the answer to this question does for a button: subclass UIView actions in viewcontroller
As usual in programming, there are several possible solutions. It's up to you to pick the best one for you. Good luck!

mouseDown not firing properly on NSTextField

I tried implementing the second answer posted in this post here. I have the desire as the person asking the question however my mouseDown is not working/registering. Here is what I have.
AppDelegate.h
AppDelegate.m
MouseDownTextField.h
MouseDownTextField.m
and there relavent content:
AppDelegate.h
#import <Cocoa/Cocoa.h>
#import "MouseDownTextField.h"
#interface AppDelegate : NSObject <MouseDownTextFieldDelegate> {
NSWindow *window;
IBOutlet NSMenu *statusMenu;
NSStatusItem *statusItem;
NSMutableArray *selector;
NSMutableArray *display;
NSTimer *timer;
MouseDownTextField *quoteHolder; }
#property IBOutlet MouseDownTextField *quoteHolder;
#end
AppDelegate.m
- (void)displayString:(NSString *)title {
NSRect frame = NSMakeRect(50, 0, 200, 17);
quoteHolder = [[MouseDownTextField alloc] initWithFrame:frame];
[[self quoteHolder] setDelegate:self];
[quoteHolder setStringValue:title];
[quoteHolder setTextColor:[NSColor blueColor]];
[test addSubview:quoteHolder];
[statusItem setView:test]; }
-(void)mouseDownTextFieldClicked:(MouseDownTextField *)textField {
NSLog(#"Clicked");}
MouseDownTextField.h
#import <Appkit/Appkit.h>
#class MouseDownTextField;
#protocol MouseDownTextFieldDelegate <NSTextFieldDelegate>
-(void) mouseDownTextFieldClicked:(MouseDownTextField *)textField;
#end
#interface MouseDownTextField: NSTextField {
}
#property(assign) id<MouseDownTextFieldDelegate> delegate;
#end
MouseDownTextField.m
#import "MouseDownTextField.h"
#implementation MouseDownTextField
-(void)mouseDown:(NSEvent *)event {
[self.delegate mouseDownTextFieldClicked:self]; }
-(void)setDelegate:(id<MouseDownTextFieldDelegate>)delegate {
[super setDelegate:delegate]; }
-(id)delegate {
return [super delegate]; }
#end
Thoughts on what could be wrong or what i have done wrong?
You are creating quoteHolder in IB, you should remove the following line of code and you should be fine.
quoteHolder = [[MouseDownTextField alloc] initWithFrame:frame];
The result of reassigning the NSTextField is that the one you are clicking is no longer the one registered with the delegate. No need to add it as a subview either, it's already been added to the view hierarchy in IB.
Also, make sure in IB, under Accessibility, "User Interaction Enabled" is checked for the NSTextField.
As for the follow up quesion, how could you have multiple of these?
If you were adding multiple NSTextField instances in IB, each would be referenced as a #property just as you did with quoteHolder. The linkage is done in IB like this linked answer.
These could all have the same delegate. When mouseDownTextFieldClicked: is pressed you could interrogate the NSTextField for a unique id which could be assigned in IB as well. Hope this helps.

How do I switch between 2 image using UISegmentcontrol?

I've tried writing this code but I don't think it's correct cause there is an error with the viewDidLoad.
I'm trying to switch between 2 images in the same UIImageView using UISegmentcontol using Storyboard. All the examples online are for switching labels and not using Xcode storyboard.
h.file
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
{
IBOutlet UIImageView *myImage;
IBOutlet UISegmentedControl *segControl;
}
#property(nonatomic, retain)IBOutlet UIImageView *myImage;
#property (nonatomic, retain)IBOutlet UISegmentedControl *segControl;
- (IBAction)switchButton:(id)sender;
#end
m.file
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize myImage;
#synthesize segControl;
- (IBAction)switchButton:(id)sender
{
if (segControl.selectedSegmentIndex == 0)
{
[myImage setImage:[UIImage imageNamed:#"image1.jpg"]];
}
else
if (segControl.selectedSegmentIndex == 1)
{
[myImage setImage:[UIImage imageNamed:#"image2.jpg"]];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIImage *myImage = [myImage setImage:[UIImage imageNamed:#"image1.jpg"]];
}
If you want to fill the segments of the segmented control with images, you don't need code. Just use the storyboard.

SubClassing UILabel

I read in this same site how to inset and UILabel (subclass UILabel and override the required methods). Before adding it to my app I decided to test it out in a standalone test app. Code is shown below.
Here's MyUILabel.h
#import <UIKit/UIKit.h>
#interface MyUILabel : UILabel
#end
Here's MyUILabel.m
#import "MyUILabel.h"
#import <QuartzCore/QuartzCore.h>
#implementation MyUILabel
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
// for border and rounding
-(void) drawRect:(CGRect)rect
{
self.layer.cornerRadius = 4.0;
self.layer.borderWidth = 2;
[super drawRect:rect];
}
// for inset
-(void) drawTextInRect:(CGRect)rect
{
UIEdgeInsets insets = {0, 5, 0, 5};
[super drawTextInRect: UIEdgeInsetsInsetRect(rect, insets)];
}
Here's my ViewController.h
#import <UIKit/UIKit.h>
#import "MyUILabel.h"
#interface ViewController : UIViewController
{
MyUILabel *myDisplay;
}
#property (strong, nonatomic) IBOutlet MyUILabel *myDisplay;
#end
Here's ViewController.m:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize myDisplay;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
myDisplay.text = #"Hello World!";
}
- (void)viewDidUnload
{
[self setMyDisplay:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
None of the methods in MyUILabel.m (that Im overriding) get called.
Insights into why are greatly appreciated.
Regards,
Ramon.
Ok. I did some further digging and in Xcode there is a field visible when looking at the nib file. Its the 'Identity Inspector' (3rd icon from left). This needed to be changed from UILabel to MyUILabel.
Now it works!