NSTextField not visible - swift

I recently started coding Swift. So I am working on a macOS app to get more used to Swift.
I want that an NSTextField is created when the user presses a button. I got the code below but the NSTextField doesn't display. While research I found that it somehow must be added to view but not how this is done.
#IBAction func buttonPressed(_ sender: Any) {
let label = NSTextField()
label.stringValue = ("Hello World")
}
How do I make the NSTextField display? Any help would be highly appreciated.

Just turn the label into a layer-backed view. Then add it into a visible view:
let rect = NSMakeRect(20, 20, 80, 44)
let label = NSTextField(frame: rect)
label.wantsLayer = true
label.layer?.backgroundColor = NSColor.greenColor().CGColor
window?.contentView?.addSubview(label)

let rect = NSMakeRect(20, 20, 80, 44)
let label = NSTextField(frame: rect)
view.addSubview(label)
Worked for me. In Xcode 10 with swift 4.

Related

NSToolbar Flexible space not working in Swift 5.x

I developed this app using Xcode 10.1 (Swift 4.2 I believe) and toolbar looks good:
But I ported in over to my Xcode 11.6 (Swift 5.2 I believe), now the right-most item on the toolbar is no longer on the far right:
Before the port, I added that plus button - the checkbox (Show Hidden) was one of the first items and was never changed since.
Also the buttons function as expected - their actions fire OK.
Note: This app uses no Storyboards or IB things.
Since my code in split over several files (with lots of unrelated code), I will give an overview.
class ToolbarController: NSObject, NSToolbarDelegate {
let toolbar = NSToolbar(identifier: NSToolbar.Identifier("toolbar"))
lazy var toolbarItem1: NSToolbarItem = {
let toolbarItem = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier(rawValue: "Btn1"))
let button = NSButton(frame: NSRect(x: 0, y: 0, width: 40, height: 1))
button.target = self
...
toolbarItem.view = button
return toolbarItem
}() // defined as "lazy" to allow "self"
var toolbarItemSpace: NSToolbarItem = {
let toolbarItem = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier.space)
return toolbarItem
}()
...
var toolbarItemFlexSpace: NSToolbarItem = {
let toolbarItem = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier.flexibleSpace)
return toolbarItem
}()
lazy var toolbarItemShowHidden: NSToolbarItem = {
let toolbarItem = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier(rawValue: "Checkbox"))
let box = NSBox(frame: NSRect(x: 0, y: 0, width: 120, height: 40))
let button = NSButton() // put in NSBox to use isolated action
...
button.target = self
box.contentView = button
box.sizeToFit() // tightly fit the contents (button)
toolbarItem.view = box
return toolbarItem
}()
lazy var tbItems: [NSToolbarItem] = [toolbarItem1, ...]
That class defines the toolbar, add the items, implements all those toolbar (delegate) methods and makes it the delegate. My NSWindowController then set it to the application toolbar.
Can anyone see an issue with my code that causes the above?
Otherwise, is this a bug?
Had the same problem with Swift 5.0 ... even though the documentation says minSize and maxSize are deprecated, I solved this like:
let toolbarItem = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier.flexibleSpace)
toolbarItem.minSize = NSSize(width: 1, height: 1)
toolbarItem.maxSize = NSSize(width: 1000, height: 1) //just some large value
return toolbarItem
Maybe this works as well for Swift 5.2
Found a way without living w/ the warning & not using the deprecated properties.
We create a transparent subview for the NASToolbarItem with the min / max constraints in advance, so the system has a way to calc the min and max size itself.
let toolbarItem = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier.flexibleSpace)
// view to be hosted in the flexible space toolbar item
let view = NSView(frame: CGRect(origin: .zero, size: CGSize(width: MIN_TOOLBAR_ITEM_W, height: MIN_TOOLBAR_H)))
view.widthAnchor.constraint(lessThanOrEqualToConstant: MAX_TOOLBAR_ITEM_W).isActive = true
view.widthAnchor.constraint(greaterThanOrEqualToConstant: MIN_TOOLBAR_ITEM_W).isActive = true
// set the view and return
toolbarItem?.view = view
return toolbarItem

SystemStatusBar statusItem title being cut short on OS X

I am trying to display an OS X application statusItem in the System Status Bar and am having success with everything except the fact that the title is being cut off. I am initializing everything like so:
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(-1)
func applicationDidFinishLaunching(aNotification: NSNotification) {
let icon = NSImage(named: "statusIcon")
icon?.template = true
statusItem.image = icon
statusItem.menu = statusMenu
statusItem.title = "This is a test title"
}
The problem is the statusItem.title is appearing like so:
As you can see the application next to mine (iStatMenuBar) is cutting off the title to my application (or something similar is happening)
If I comment out the icon for the statusItem, it works and shows the entire title but when I re-add the icon it cuts off again. Is there a way for the two (icon and title) to co exist? I have reviewed some Apple docs and may have missed a critical piece which explains this.
Thanks guys.
One option would be to assign a custom view to your statusBarItem and within that view's class override drawRect(dirtyRect: NSRect) e.g.
private var icon:StatusMenuView?
let bar = NSStatusBar.systemStatusBar()
item = bar.statusItemWithLength(-1)
self.icon = StatusMenuView()
item!.view = icon
and StatusMenuView might look like:
// This is an edited copy & paste from one of my personal projects so it might be missing some code
class StatusMenuView:NSView {
private(set) var image: NSImage
private let titleString:NSString = "really long title..."
init() {
icon = NSImage(named: "someImage")!
let myWideStatusBarItemFrame = CGRectMake(0, 0, 180.0, NSStatusBar.systemStatusBar().thickness)
super.init(frame.rect)
}
override func drawRect(dirtyRect: NSRect)
{
self.item.drawStatusBarBackgroundInRect(dirtyRect, withHighlight: self.isSelected)
let size = self.image.size
let rect = CGRectMake(2, 2, size.width, size.height)
self.image.drawInRect(rect)
let titleRect = CGRectMake( 2 + size.width, dirtyRect.origin.y, 180.0 - size.width, size.height)
self.titleString.drawInRect(titleRect, withAttributes: nil)
}
}
Now, the above might change your event handling, you'll need to handle mouseDown in the StatusMenuView class.

How to display a string/int within a UIView in Swift?

this is a very simple question, but I can't find an answer anywhere. I am trying to display a high score within a CGRect, but cannot figure out exactly how to do it. I am currently trying to do this on a playground so that might have something to do with it. Thanks for the help.
You can make a UILabel in a Swift playground. Here's how it might look:
Here's the code from the playground:
import UIKit
let score = 200
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 20))
label.backgroundColor = UIColor.purpleColor()
label.textColor = UIColor.orangeColor()
label.text = "High Score: \(score)"
A CGRect is the frame or dimensions assigned to a UIView, not the UIView itself. I would suggest creating a UILabel and add that to your view. You can set the text on the UILabel to, in your case, the high score variable as a string. Im not sure if it is possible to do this in a playground, but I may be mistaken. A XCode project would work perfect for this, but again, im not sure about the playground.
To do this in a playground, it would look like this:
import UIKit
import XCPlayground
let view = UIView(frame: CGRectMake(0,0,500,500)) //create a view and give it a proper size
let label = UILabel(frame: CGRectMake(0,0,100,23)) //create a label with a size
label.text = "My Label" //give the label some text
view.backgroundColor = UIColor.lightGrayColor() //default view in Playground as black background
view.addSubview(label) //add the label to the view
XCPlaygroundPage.currentPage.liveView = view //tell playgound to display your view as the root view in the assistant editor
You need to open the assistant editor in the playground to see the result (the two circles icon in the upper right corner)

NSAttributedString: image not showing up in UILabel

For some reason, the image does not display. I have dropped test.png and test#2x.png both under Image.xcassets/ I also dropped it within the project. None of that helped. Any assistance would be greatly appreciated.
var testView: UILabel = UILabel(frame: CGRectMake(20, 20, self.view.frame.width-40, self.view.frame.height-40))
var a = "Testing..."
var attachment = NSTextAttachment()
//This is the image that I would like to add
// I have dropped test.png and test#2x.png under Image.xcassets
attachment.image = UIImage(named: "test")
var attachmentString = NSAttributedString(attachment: attachment)
let attrsB = NSAttributedString(
string: "2nd line..Testing testing",
attributes: NSDictionary(
object: UIFont(name: "HelveticaNeue", size: 18.0)!,
forKey: NSFontAttributeName) as [NSObject : AnyObject])
a.appendAttributedString(attrsB)
let attributedTextToDisplay = NSMutableAttributedString(attributedString: a)
attributedTextToDisplay.appendAttributedString(attachmentString)
testView.attributedText = attributedTextToDisplay
self.view.addSubview(testView)
You need to allow your label to have multiple lines if you want to display more than 1 line.
var testView: UILabel = UILabel(frame: CGRectMake(20, 20, self.view.frame.width-40, self.view.frame.height-40))
testView.numberOfLines = 0;
Tips:
Use Storyboard & Interface Builder. WYSIWYG.
Use AutoLayout, it solves a lot of resizing for you
Use asserts if you are unsure of the content of a variable
Step into debugger and push on the eye icon to reveal quicklook
Eliminating all these variables will help you find out the root cause, and not worry, say, about whether or not your image is loaded. See sample below.
For good measures, I also explicitly typed a into a a:NSMutableAttributedString.
var a:NSMutableAttributedString
I had the issue when I used didSet {} on the IBOutlet, moving the code to ViewDidLoad() method solved it.

Swift coordinates of a pressed button

I'm working on a tic tac toe game (3x3), so I have 9 buttons and what I want to do is to get coordinates of a button which user had pressed and insert an image on the place of the button.
Example:
#IBOutlet weak var button1Outlet: UIButton!
#IBAction func button1Action(sender: AnyObject) {
let imageName = "IMG.png"
let image = UIImage(named: imageName)
let imageView = UIImageView(image: image!)
imageView.frame = CGRect(x: 0, y: 0, width: 90, height: 90)
view.addSubview(imageView)
}
I know I can get coordinates of the button using button1Outlet.center , but I need something like this.center to avoid hardcoding it for every button.
You can cast the sender to a UIButton which you then can access any frame related methods on.
(sender as UIButton).center
When a button is clicked it is passed as a parameter to the function. Just use the sender.
// Change sender to a UIButton type
#IBAction func button1Action(sender: UIButton) {
// ... Setup your views
// Set same frames
imageView.frame = sender.frame
view.addSubview(imageView)
// If you want to remove the button
sender.removeFromSuperview()
}