Stop NSView from printing - xcode

I have a very basic Mac application in Xcode with a Split View that contains a PDFThumbnailView and a PDFView. (Just like Preview.)
There's hardly any Swift code beyond what is required to load a PDF into the views.
However, when I select Print from the Print menu, the app wants to print the ThumbnailView, unless I click on the PDFView first.
Is there any way to always make it print the PDFView and never the ThumbnailView? I presume it's a setting or parameter somewhere in the Storyboard, rather than a bit of code as such.
Xcode 10.2.1 on Mojhave 10.14.5.

An easy solution would be to provide your own print method (like printContent:) on your controller, and in your XIB file change the target method for the print menu item to printContent: instead of print:
// eg.
#IBOutlet weak var pdfThumbnails: PDFThumbnailView!
#IBOutlet weak var pdfContent: PDFView!
...
#IBAction func printContent(_ sender: Any) {
self.pdfContent.printView(sender)
}

Related

NSCollectionView does not hide in osx

I used NSCollectionView in my application. In certain condition i want to hide and Unhide the NSCollectionView. But it will not hide the NSCollectionView.
I used the following code
#IBOutlet weak var thumbnailView: NSCollectionView!
func applicationDidFinishLaunching(aNotification: NSNotification) {
thumbnailView.hidden = true
NSThread.sleepForTimeInterval(5)
thumbnailView.hidden = false
}
Note: Sleep the thread just for demonstration purpose
Also Hiding the NSScrollView is not working.
EDIT: I perform same code on Button Touch up Inside event i get the same result. It does not hide my CollectionView.
#IBAction func ButtonnISClick(sender: AnyObject) {
thumbnailView.hidden = true
NSThread.sleepForTimeInterval(5)
thumbnailView.hidden = false
}
Here are things that are wrong with your code (mostly because you did not provide enough information in your question):
Use lowercase strings when naming variables (so change ThumbnailView to thumbnailView;
I don't know where are you writing this code. Is it NSWindowController, NSViewController or NSWindow subclass? Depending on the location, you should write 2nd to 4th lines in different methods (either windowDidLoad(), viewDidLoad() or awakeFromNib()
Update: Given your code is in application did finish launching and you are sleeping in that method, you won't see any changes, since the window of your app is presented only after the method has returned (i.e. all code has been executed). I suggest you to move this code into a subclass of either NSWindowController's windowDidLoad (I'm not sure about that one) or NSViewController's viewDidAppear: method.

Linking NSMenu to ViewController - Swift

I am working on a Yosemite app in swift and have hit a road block.
I have multiple views working properly, and now I want to implement custom menu actions. To keep the answer simple, how would I achieve this example. I want to click a menu button and have it change text on the viewcontroller. I have tried setting up IBActions, but I'm not sure how to make the link to the viewcontroller from the AppDelegate. How do you connect the two?
I'm still figuring this stuff out, so any insight would be awesome. Thanks in advance.
*UPDATE. I tried making a object and linking it that way. No luck.
When you press "Test" it prints test, however it's in it's own class. I need to do something in my main ViewController class. How to I make that reference?
Getting NSViewController from NSWindow is an easy solution.
If your app has multiple windows, select appropriate one through keyWindow or windows of NSApplication.
#IBAction func pressed(sender: AnyObject) {
if let window = NSApplication.sharedApplication().mainWindow {
if let viewController = window.contentViewController as? YourViewController {
// do stuff
...
}
}
}

How to use NSToolBar in Xcode 6 and Storyboard?

I've been trying to build on a Cocoa app that uses Swift and Storyboard in Xcode 6, but how can I use NSToolbar there?
In Xcode 5 and xib, you can add NSToolbar from within Object Library to any .xib files and then click on the added toolbar to expand it and drag and drop a connection from any items there to a AppDelegate.h file. In this way you can create a IBAction or IBOutlet connection. I confirmed that this can also be done if you use Swift and non-storyboard in Xcode 6. However, it looks like this is not the case in Xcode 6 and Storyboard environment.
I first created a project that uses Storyboard in Xcode 6, but then, I wasn't able to add a NSToolbar from within Object Library to a View Controller in Storyboard. So I added it to Window Controller's Window object in Storyboard. However, in this way I cannot create those connections from any items in the expanded toolbar to either AppDelegate.swift or ViewController.swift.
So my question is:
Is it feasible to create a storyboard app that uses NSToolbar?
If it is feasible, is the addition of NSToolbar to the Window Controller the proper way to use NSToolBar in Storyboard?
Finally, how can I create #IBOutlet and #IBAction connections there?
UPDATE
I found that the accepted answer by #GeorgeVillasboas only works for #IBAction. I am still looking for how to create an #IBOutlet connection...
I had this very same problem.
The solution works for both Objective-C and Swift projects.
Working with Storyboards on OSX, it creates an instance of NSWindow and segues to another NSViewController as its Window Content Segue, as you described.
On your ViewController, create a standard IBAction to receive the action when the toolbar is clicked. To wire it up with the NSToolbar, just control-drag (or leftClick-drag) from your NSToolbarItem to the FirstResponder object, as shown on the picture below.
This will open a HUGE list of available connections. Your IBAction will be on that list.
Just selected it and you're good to go.
Hope this helps!
Here's an answer that doesn't rely on run-time hook-ups - #cdalvaro's answer gets most of the way there for some applications, but isn't full, and it requires the ViewController to know about the artificial NSWindowController, which doesn't feel right.
Like #cdalvaro, the first step is to build your own subclass of NSWindowController, and to set the Storyboard WC to that class. You can then create all of your connections to and from the NSToolbar (both #IBOutlets & #IBActions) in the new WindowController. So far so good.
The last step, which I haven't seen anywhere else, is how to refer to the ViewController in the WindowController - you can't create an #IBOutlet to it - for the same reasons that we got here in the first place - you can't create references across scenes in the Storyboard. However, the WindowController must have a reference to the ViewController, and it does... self.window!.contentViewController! as! ViewController
Here's a complete WindowController with a checkbox that sets values in the ViewController, without the ViewController having to know anything...
class MyWindowController: NSWindowController {
var viewController: ViewController {
get {
return self.window!.contentViewController! as! ViewController
}
}
#IBOutlet weak var aSwitch: NSButton!
#IBAction func toolbarActionA(sender: AnyObject) {
println("toolbarActionA")
self.viewController.a = !self.viewController.a
self.aSwitch.state = self.viewController.a ? NSOnState : NSOffState
}
}
This helped me for the IBOutlet solution you are looking for:
https://stackoverflow.com/a/27555237/3398062
Update (explanation)
I discovered this thread because I was trying to create a Circular Progress Indicator inside the toolbar and I didn't know how to animate it from the ViewController since the IBOutlet was declared inside a custom WindowController.
Finally, I found the post that I have added above which describes how to access to IBOutlets from other classes.
In essence what I have done is the following:
Create a custom NSWindowController subclass (CustomWindowController) for the Window Controller so I can add the IBOutlet for the ProgressIndicator:
Code Example:
#interface CustomWindowController : NSWindowController
#property (weak) IBOutlet NSProgressIndicator *progressIndicator;
#end
Then in the ViewController class, in the method I want to use to update the state of the Progress Indicator, I create and object of the custom Window Controller.
Code Example:
CustomWindowController *customWindowController = self.view.window.windowController;`
Finally, to change the state of the Progress Indicator there is only to call the method from the created custom object.
Code Example:
[customWindowController.progressIndicator startAnimation:sender];
or
[customWindowController.progressIndicator stopAnimation:sender];
This video helped me how to create a toolbar without writing a single line of code: https://www.youtube.com/watch?v=XSQocHG3IjA
You can add the 'Window Controller' item from the Object Library (if you don't have one), connect to a View Controller (where you want your toolbar to display) and follow the video! For custom Toolbar buttons add 'Image Button' item to the Toolbar just by dragging from the Object Library. Then you can pick an image for a button, set the size and so on...
Here is a general solution for the outlets and actions. it allows you to preform all the the same functions as an iboutlet would for a tool bar item and also allows you to set the button to a function instead of creating an ibaction. hope it helps :P
override func viewDidLayout() {
var x = self.view.window?.toolbar?.items[1].label
println(x)
if(self.view.window?.toolbar?.items[0].label! != "Check")
{
toobarediting()
}
println("didlay")
}
func toobarediting() {
self.view.window?.toolbar?.insertItemWithItemIdentifier("Check", atIndex: 0)
}
func toolbarcheck(functiontoset: Selector) {
var y = self.view.window?.toolbar?.items[0] as NSToolbarItem
y.action = functiontoset
if(functiontoset != nil)
{
y.enabled = true
}
}
Here is a link to my question attempting to get a cleaner answer
http://www.stackoverflow.com/questions/27371439/use-nstoolbar-outlet-xcode-6-and-storyboard/27374449
but it looks like from the answers i have gotten so far this is the best option.
The same problem of IBOutlets also applies to KVO. One of the features of the NSSplitViewController is the canCollapse property for each split view item which supports KVO, but this is unusable in IB just like IBOutlets.
The only workaround I can see is to add a NSObjectController to each scene and when the scene loads, set the object controller's object to the object in the other scene (already loaded) that you want to reference.

Failed to connect (storyboard) outlet from (NSApplication) to (NSNibExternalObjectPlaceholder) error in Cocoa and storyboard

I've tried to build a sample Cocoa app on which I want to connect UI components put on storyboard to ViewController.swift as either an IBOutlet or IBAction. However, when I tried to control-drag the UI components on storyboard (such as NSButton) to ViewController.swift and create a #IBAction method, and then run the app, the resultant app logs the following message in console and of course the app doesn't respond to me tapping the button.
Failed to connect (storyboard) outlet from (NSApplication) to (NSNibExternalObjectPlaceholder): missing setter or instance variable
How can I use the IBAction method properly?
For your information here's my ViewController.swift:
import Cocoa
class ViewController: NSViewController {
#IBOutlet var txtTitle : NSTextField
#IBOutlet var boxColor : NSBox
override func viewDidLoad() {
super.viewDidLoad()
}
func colorChanged(cp: NSColorPanel) {
let c:NSColor = cp.color;
self.boxColor.fillColor = c
}
#IBAction func btnSetColor(sender : AnyObject) {
let cp:NSColorPanel = NSColorPanel.sharedColorPanel()
cp.setTarget(self)
cp.setAction("colorChanged:")
cp.orderFront(nil)
}
#IBAction func btnSetWindowTitle(sender : AnyObject) {
if self.txtTitle.stringValue != "" {
println(self.title)
println(self.txtTitle.stringValue)
self.title = self.txtTitle.stringValue
}
}
}
I use Xcode 6 beta on OS X 10.10 Yosemite. And started the template with storyboard being on.
While the answer above correctly states that this isn't the reason for compilation issues, I thought that I would clarify for those who are just looking to eliminate the warning messages altogether. This was what I was looking for when I found this page.
When you are building your actions and some of the actions change, or get deleted in the storyboard, the outlets remain. Select the controller/window where the older unused actions used to be and you will still see them in the outlets segment of the storyboard within the attributes tab. Remove those old actions/outlets there and then the warning disappear.
Look for duplicates between the ViewController and the File's Owner. One or both might be holding on to these objects when they shouldn't be. Removing those will remove these soft warnings.
Failed to connect (storyboard) outlet from (NSApplication) to (NSNibExternalObjectPlaceholder): missing setter or instance variable
The IBAction methods working like it should, see Apple Dev Forums:
"This is a known issue ... The messages are harmless and do not
indicate a problem with your code."
Apple Dev Forums: OS X Storyboard failure
Thats not why your code is not working, you need to fix the following:
A) Here is my working code to set the title - using self.view.window.title instead self.title:
#IBAction func btnSetWindowTitle(sender : AnyObject) {
if self.txtTitle.stringValue != "" {
println(self.view.window.title)
println(self.txtTitle.stringValue)
self.view.window.title = self.txtTitle.stringValue
}
}
B) In Interface Builder you need to set NSBox "Box Type" to "Custom":
And that's it:
I think I figured out the right solution.
1) Drag an Object into you xib interface.
2) Click the Object in the left list you just dragged in.
3) Bind the Object to your custom class.(Here my class is a login window controller as example)
4) Ctrl drag button to the source code. In the popup window, choose your class name(here in example is Login Window Controller) rather than File's Owner.
Hope this could help you.
I've found another easier solution these days while coding.
Check this out.
1) Select File's Owner in Document Outline in the .xib file.
2) Specify the class you want the .xib file to connect with.
3) Now when you connect outlet to the source file, just use default File's Owner. Much easier.
4) I guess it's not enough so far. I've met an exception when running called 'loaded the 'xxx' nib but the view outlet was not set'. We should do something more.
Select the view in Document Outline. Drag from the circle of New Referencing Outlet to the File's Owner in Document Outline.
Alright, that's the new easier solution. No additional objects should add into the xib. If it doesn't work, leave comments below.

windowDidLoad() never called using storyboards for mac

I've just played around with the new mac storyboard-feature included in Xcode 6. I've set up a new OS X-project using storyboards and swift, then I've created a new file MainWindowController.swift, created the initializer init(coder: NSCoder!) (because otherwise the compiler warns me) and hooked everything up in the Main.storyboard file (set the MainWindowController-class for the WindowController in the inspector).
Everything compiles fine, my Window with the specified window content-view opens. But the code I've written in the windowDidLoad-function is never be called. Let it just something like:
override func windowDidLoad() {
super.windowDidLoad()
println("Executed")
}
I've also tested if my initializer is called - it is.
Does anybody has a clue? I've never used storyboards intensively on iOS before, maybe I miss something substantial.
In Yosemite, NSViewController has been promoted with powerful new features to make it work with Storyboards. Meanwhile, NSWindowController got demoted. With Storyboards, windows are no longer loaded from a nib, so windowDidLoad() doesn't get called anymore.
It makes sense for the window itself to become less important, in favor of a more powerful view it actually contains. My other answer on this page shows how to set up an AppDelegate to customize the window appearance. There's more detail on another page here, about using an AppDelegate to implement some of the things you might previously have done in an NSWindowController.
However, if you only wanted to catch windowDidLoad() as a way to customize the appearance options of the window, it is very easy to do that in Interface Builder, by simply adding them as User Defined Runtime Attributes to the NSWindow object. You don't need to subclass NSWindowController or write any code at all. Just plug in these values to the NSWindow object via the Identity Inspector pane to achieve the same effect shown in the AppDelegate example code:
Keypath: titlebarAppearsTransparent, Type: Boolean, Value: Checked
Keypath: titleVisibility, Type: Number, Value: 1
Keypath: styleMask, Type: Number, Value: 32783
Look in the headers to determine the actual numeric values of the constants.
( for example: NSWindowTitleVisibility.Hidden = 1 )
Of course, you can't specify individual bits of the styleMask, but it's easy enough to add them all together and get a single number to specify the style.
Remove everything except the Application scene from the Main.storyboard file, and instead, create a new Application.storyboard for the application window. Implement an application delegate class and connect it to the Application object in Main.storyboard. Use this class to instantiate the window controller and set up custom options for the application window.
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidBecomeActive(notification: NSNotification) {
let storyboard = NSStoryboard(name: "Application", bundle: nil)
applicationController = storyboard.instantiateInitialController() as? NSWindowController
if let window = applicationController?.window {
window.titlebarAppearsTransparent = true
window.titleVisibility = NSWindowTitleVisibility.Hidden
window.styleMask |= NSFullSizeContentViewWindowMask
applicationController!.showWindow(self)
}
}
}
Rather than subclassing NSWindowController, use the ViewController.swift subclass of NSViewController that Xcode creates for you automatically with the project.
In the storyboard, notice how there's a Relationship that connects the "window content" to the ViewController. So, the ViewController can now do things that you might previously have done in a window controller.
The ViewController.swift file will already have a default override of viewDidLoad() that will be called when the window loads, just as you were expecting windowDidLoad() to be called if it were an NSWindowController subclass.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
println("Executed")
}

Resources