Thomas  Granger

Thomas Granger

1560920600

Getting Started with macOS Programming

Dear readers, let me welcome you and start by saying that this tutorial is the beginning of a new journey and new explorations, as it’s the first of a series of tutorials on a new topic: macOS programming!

Developing for macOS and creating desktop applications is a wonderful process if you want to go down that road. If you are coming from an iOS background like me, then you will find exciting and challenging at the same time to be able to make apps for both systems. What makes it even better is one simple fact: There are lots of common things between iOS and macOS programming. Several frameworks and SDKs, the language itself (Swift), even the coding style that one has used to remain almost the same. But macOS programming is not meant for people being iOS developers already. New programmers who have started learning Swift and they want to make their own desktop applications can follow along as well!

Starting from this tutorial we are going to meet and learn key concepts on macOS programming. I am planning to present various topics for which I will highlight their most important concepts and I will show techniques, how-to and best practices. It is obvious that it would take a series of books to cover everything about macOS programming, not just a series of tutorials. However, what I’m going to show you starting from this tutorial and onwards not only will get you started, but it will enable you to build full applications and it will put you on the right track so you know how to look further on topics you are interested in. Whenever possible, we will be going through the making process of a new macOS app that will have some usefulness at the end. Something that you can take with you when finish reading each post.

So, once again welcome to a new exciting journey! Let’s go together to build our first macOS application!

Our Roadmap

In this post we are going to see the basics of a macOS app through the creation of a simple, but at the same time useful for many developers app: A font viewer that will let us choose font families and it will be displaying the PostScript names of the available fonts. Clarifying why this is useful: The PostScript name is the font name we write in code when creating a NSFont object. Usually it’s not the same to the font’s file name, and without knowing the PostScript it’s impossible to create font objects in code or to add custom fonts into projects. There’s a manual process to reveal PostScript names as described here, but why not to have a macOS app that will let us get it instantly?

Our menu today contains a lot of key stuff:

  • How to create a new macOS project.
  • What the most important parts of the generated project are.
  • What is a window controller and how to configure its contained window, including size, position, title, and a lot more.
  • How to add graphical controls into a view controller.
  • How to interact with those graphical controls, update their values and react on actions triggered by them.
  • How to create additional window controllers.
  • How to change a window’s appearance so it looks like a utility or auxiliary panel.
  • How to load and present and close a window programmatically.

There are even more things to discuss in this post in addition to those listed above. We will talk about new classes that will be proved extremely valuable for our cause, we will talk about the custom logic that we will implement in the various parts of the app, and we will see small or big details that will produce at the end a complete project.

Here is what you are going to have in your hands by the time you will leave here:

Creating Your First Mac App

Launch Xcode, and then choose to create a new project:

In the first step of the guide that appears next do the following:

  • How to create a new macOS project.
  • What the most important parts of the generated project are.
  • What is a window controller and how to configure its contained window, including size, position, title, and a lot more.
  • How to add graphical controls into a view controller.
  • How to interact with those graphical controls, update their values and react on actions triggered by them.
  • How to create additional window controllers.
  • How to change a window’s appearance so it looks like a utility or auxiliary panel.
  • How to load and present and close a window programmatically.

Once you do so, it’s time to “baptise” the project and set all the rest initial information. Since we’re going to create our custom font viewer, why not to call it just like that, Font Viewer? Set that as the value to the Product Name field, and configure the other properties such as Team, Organization Name, Organization Identifier. Generally, make sure that your window looks like the next one:

Finally, choose a place to save the project on your disk, and finish with the creation process.

Running The App

While having Font Viewer project open in Xcode, press Cmd + R on your keyboard to run the app. Here’s what you’ll see appearing on your screen:

Congratulations! You just ran your first macOS app!

It’s an empty window for now, but it doesn’t matter as we will change that. Look and play around with it. You will notice that standard behaviour and attributes are assigned by default to the window, such as resizing, moving or going full screen. Also, there’s the main menu at the top bar, where some common functionalities are provided already, while some others are just disabled as they don’t trigger any action.

Exploring The Project

If you have prior experience to iOS development, you will find out that a macOS project looks pretty much the same to an iOS project. Project Navigator lists all files and groups, tabs like General, Capabilities, Build Settings, etc are here too, and generally everything looks familiar. Displayed settings and options are specific to macOS though.

In the Project Navigator you will find all files and groups that Xcode creates by default for a Cocoa App. What is new here (comparing again to iOS projects), is an .entitlements file. This is a property list file that contains rights an app is granted with. Most of the times there is no need to edit it manually. Changes made through the Capabilities tab update this file automatically.

Other than that, two code files are created automatically. AppDelegate.swift and ViewController.swift. We will add more code to ViewController.swift in a while. There is also:

  • How to create a new macOS project.
  • What the most important parts of the generated project are.
  • What is a window controller and how to configure its contained window, including size, position, title, and a lot more.
  • How to add graphical controls into a view controller.
  • How to interact with those graphical controls, update their values and react on actions triggered by them.
  • How to create additional window controllers.
  • How to change a window’s appearance so it looks like a utility or auxiliary panel.
  • How to load and present and close a window programmatically.

Looking at the General tab of the Font Viewer target, in the Identity section you can find the Bundle Identifier, as well as the Version and Build Number. But what is more interesting here, is the Application Category popup, where you can find all available app categories also found on App Store. This is the place where we set the category of our app. Which category would be suitable for us here? We could assign it under Developer Tools since it’s going to display font information, but we could also have it in the Utilities category. Right now it doesn’t really matter as we are not going to publish it, but remember to choose a category for your app before you send it to the App Store (it’s still okay if you don’t, you can choose app category on the App Store as well, but why not to do it here?).

Looking a bit lower you will see the Deployment Info section. Here you specify the minimum macOS version required by your app to run. You can have it run on macOS Mojave only (10.14), or enable it running on High Sierra (10.13) or older versions too. Keep that option in mind if you ever want to support older operating systems.

Take your time to go through every aspect of the project. Switch to the Capabilities tab, and see what kind of options are available, or go to Build Settings and see if you find something interesting there too. Once you finish your exploration, let’s take a few moments to see what Main.storybard file contains.

Exploring The Main.storyboard

Clicking on the Main storyboard file in the Project Navigator, the automatically created, default user interface will be revealed in Interface Builder. Any Cocoa based app contains three default scenes:

  • How to create a new macOS project.
  • What the most important parts of the generated project are.
  • What is a window controller and how to configure its contained window, including size, position, title, and a lot more.
  • How to add graphical controls into a view controller.
  • How to interact with those graphical controls, update their values and react on actions triggered by them.
  • How to create additional window controllers.
  • How to change a window’s appearance so it looks like a utility or auxiliary panel.
  • How to load and present and close a window programmatically.

Let’s focus on some interesting details now. Click on the window in the window controller scene, and open Attributes Inspector in the inspectors panel of Xcode. This is what you should be seeing:

For some of them, just enabling or disabling options has immediate visual effect on the window. For some others it has not. Let me highlight the most important ones, but if you find yourself needing information for options not mentioned below, feel free to search for them on the web.

  • How to create a new macOS project.
  • What the most important parts of the generated project are.
  • What is a window controller and how to configure its contained window, including size, position, title, and a lot more.
  • How to add graphical controls into a view controller.
  • How to interact with those graphical controls, update their values and react on actions triggered by them.
  • How to create additional window controllers.
  • How to change a window’s appearance so it looks like a utility or auxiliary panel.
  • How to load and present and close a window programmatically.

Leaving the rest options to their default settings makes sure that a window fits to the general macOS environment and it follows workflows that users are already familiar with. Of course, you can find additional information about them and their purpose if you wish so, I just highlighted the most important ones here.

With the window still being selected, show the Size Inspector. Here, you can set the content size of the window, the allowed maximum and minimum size, as well as the initial place of the window on screen.

Setting the content size (width and height) makes the obvious, it changes the window’s default content size. By leaving the Minimum Content Size and Maximum Content Size unchecked, users can resize the window and make it as small or as big they want. To limit the minimum content size so users cannot decrease it further than that, just enable the Minimum Content Size checkbox and specify values for the min width and height. Similarly, enable the Maximum Content Size checkbox to prevent your window grow more than the values you specify.

To keep a constant content size and disallow resizing, then set the exact same values to both minimum and maximum content size.

By default a window is displayed to the bottom left side of the screen. You can change that by either dragging the window sample in the small screen preview window, or just change the initial position X and Y values. Just remember: coordinates in macOS are not like iOS. The Y=0 point is the bottom side of the screen, not the top.

Windows can also be shown centered on the screen. To do that, click on the Proportional Horizontal and Proportional Vertical popup buttons, and select Center Horizontally and Center Vertically respectively. The screen sample in the Size inspector will be updated, and you can verify that by running the app; the window will be shown on the center of the screen.

Setting Up The UI

After that quick walkthrough to the macOS project, let’s do some real work on our app. For starters, select the default Window and open the Size Inspector in the inspectors panel. Change the Content Size to 370×250. Then, select the view controller’s view and do the same.

Now let’s add the graphical controls to the default view of the view controller.

Begin by clicking on the Library Button on Xcode to open the Objects Library:

In the Objects Library, type popup in the top search field:

Choose the Pop Up Button item, and drag and drop it to the view controller’s view. Select the popup control you just dragged to the view controller, and press Cmd + D on your keyboard to duplicate it.

Select both popup buttons, and add the following constraints: Top: 20, Leading: 20, Trailing: 20, Height: 21.

Following the above steps, let’s add also a push button and a label:

  1. Open the Objects Library again, and type button.
  2. Drag and drop a push button to view controller’s view below the popups.
  3. Set its constraints: Trailing: 20, Bottom: 20, Width: 120, Height: 21.
  4. Double click on the button to change its title to: Display All
  5. Open the Objects Library one last time, and type label in the search field.
  6. Drag and drop a label object into the view controller, under the popups but above the push button.
  7. Set the following constraints for the label: Top: 20, Leading: 20, Trailing: 20, Height: 80.

At the end, your view should be similar to this one:

The first popup button will be displaying all available font families on the system, while the second will contain all available font types (such as bold, italic, etc) for any selected font family in the first popup.

Label will show the PostScript name of the selected font family and type, formatted accordingly.

Lastly, the “Display All” button will be used to show all available font types of a font family at once. More about that later.

IBOutlet Properties And IBAction Methods

We will come to the need to interact with the controls we just added soon, so it’s necessary to create and connect IBOutlet properties and IBAction methods to them. Open the ViewController.swift file, and to the top of the class add the next IBOutlet property declarations:

@IBOutlet weak var fontFamiliesPopup: NSPopUpButton!
 
@IBOutlet weak var fontTypesPopup: NSPopUpButton!
 
@IBOutlet weak var sampleLabel: NSTextField!

Also, define the following IBAction methods:

@IBAction func handleFontFamilySelection(_ sender: Any) {
 
}
 
 
@IBAction func handleFontTypeSelection(_ sender: Any) {
 
}
 
 
@IBAction func displayAllFonts(_ sender: Any) {
 
}

Back to the Main.storyboard file, select the view controller object in the document outline:

In the inspectors panel, select to open the Connections inspector, where you will find all the IBOutlet properties and IBAction methods previously declared. Make the connections as follows:

  • How to create a new macOS project.
  • What the most important parts of the generated project are.
  • What is a window controller and how to configure its contained window, including size, position, title, and a lot more.
  • How to add graphical controls into a view controller.
  • How to interact with those graphical controls, update their values and react on actions triggered by them.
  • How to create additional window controllers.
  • How to change a window’s appearance so it looks like a utility or auxiliary panel.
  • How to load and present and close a window programmatically.

Before we make the simple user interface we just created usable, let’s take a look at the controls we just added. By default, each popup button contains three items, where each one is a menu item (more about menus and menu items in a future post). These can be changed either by double clicking on the popup button and then by double clicking on each item, or by selecting the popup button and spotting each item to the Document Outline.

In this demo application, we will change the menu items programmatically, but Interface Builder is a good option to do that if you have a constant set of items that are not meant to be changed on the fly.

Note: Popup button items can be always updated programmatically regardless of whether an initial set of real items has been set through Interface Builder.

In the Attributes inspector you can find all configurable properties of the popup button (after selecting one). For example, you can define the default selected item, or to set font properties and text alignment.

Similarly, label’s and button’s properties can be changed in the Attributes inspector too if you select the label or button object in the view controller. Feel free to look around and experiment a bit by changing any properties you want. It doesn’t matter if you “damage” any control by accident; just delete it and create a new one by following the steps described above.

Another interesting point is the object hierarchy and the actual contained objects in the Document Outline pane. One would expect to find there only the popup buttons, the label and the push button along with their constraints. However, if you start expanding the objects tree you will notice that there are more objects than those we specifically added. Apart from the menu items of the popups (which is fine to be found there since a menu item is actually another Cocoa control created automatically), you will also find a cell object going in pair with each control. For example, the fontFamiliesPopup is a NSPopUpButton object, but it contains a NSPopUpButtonCell item which in turn contains the menu items. Likewise, the label which is a NSTextField object contains a NSTextFieldCell item.

So, what is the purpose of those “Cell” objects?

Generally speaking, a cell object (any “…Cell” subclass) is responsible for implementing the actual Cocoa control and its functionalities. All those subclasses inherit from the same ancestor, NSCell, which implements several common properties and methods regarding the appearance and behaviour of controls. Even though we will be interacting with the popup buttons, the label and the push button objects directly in this app, behind the scenes any visual changes and updates will be handled by the matching cell subclasses.

Practically speaking now, we don’t have to worry about them as we won’t have to deal with any cell subclass. Just one general warning: make sure to connect IBOutlet properties to the actual controls and not their cell counterparts. It’s a common mistake that can happen if you perform the outlet connection by pressing Control and drag-and-dropping from Interface Builder to the Assistant Editor (code) and you don’t pay attention to what the origin (source) object of the dragging is.

Bringing App To Life

Building the UI, even a simple one, is an achievement. But without code, not much can happen.

Initial Configuration

Open the ViewController.swift file, where we’ll get started by implementing a function in the ViewController class that will perform some initial setup to the UI.

Go after the default view controller methods and add the following:

func setupUI() {
    fontFamiliesPopup.removeAllItems()
    fontTypesPopup.removeAllItems()
    sampleLabel.stringValue = ""
    sampleLabel.alignment = .center
}

In the first two lines we remove all default items from the two popup buttons. In the other two lines we empty the default text of the label, and we center it. Notice that the property to set the label’s text is stringValue; don’t look for a property called text or something like that.

Next step is to populate the first popup button with actual values: All font families existing in the Mac. We will achieve that by getting to know a new class called NSFontManager. It is responsible for several things including the Font panel and Font menu found in many apps, keeping record of the currently selected font, triggering font changes, and more. Among its “duties”, important information about available font families and font attributes is also included!

NSFontManager is used through a shared instance programmatically. A property named availableFontFamilies can give us what we need: A collection (array) with all the available font families!

Right next we define a new method that uses the NSFontManager class and adds the found family names as items to the fontFamiliesPopup:

func populateFontFamilies() {
    fontFamiliesPopup.removeAllItems()
    fontFamiliesPopup.addItems(withTitles: NSFontManager.shared.availableFontFamilies)
}
 

Now, both of methods we implemented above have to be called once the app is started, and before the view gets appeared. Go right after the viewDidLoad() method and add the following:

override func viewWillAppear() {
    super.viewWillAppear()
 
    setupUI()
    populateFontFamilies()
}

6

7

override func viewWillAppear() {

    super.viewWillAppear()

 

    setupUI()

    populateFontFamilies()

}

 

Let’s see what we’ve done so far. Run the app and open the first popup, you will find all available font families in it!

Handling Actions

NSFontManager class seems to be quite useful, as there are more interesting properties and methods to explore and use. One such method that is particularly interesting is called availableMembers(ofFontFamily:). It returns an array where each item is another array ([[Any]]) with four distinct values:

  1. Open the Objects Library again, and type button.
  2. Drag and drop a push button to view controller’s view below the popups.
  3. Set its constraints: Trailing: 20, Bottom: 20, Width: 120, Height: 21.
  4. Double click on the button to change its title to: Display All
  5. Open the Objects Library one last time, and type label in the search field.
  6. Drag and drop a label object into the view controller, under the popups but above the push button.
  7. Set the following constraints for the label: Top: 20, Leading: 20, Trailing: 20, Height: 80.

An item-array is called a member of the font family. The following example taken from Apple Documentation illustrates what availableMembers(ofFontFamily:) returns:

(("Times-Roman", "Roman", 5, 4),
("Times-Italic", "Italic", 6, 5),
("Times-Bold", "Bold", 9, 2),
("Times-BoldItalic", "Bold Italic", 9, 3)
)

Putting the above in different words, with *availableMembers(ofFontFamily:)* we can get all font variations that a font family supports, and display them on the *fontTypesPopup* popup button.

Before we make the actual use of the above method, let’s declare the following two properties to the ViewController class, they’ll become handy a bit later:

var selectedFontFamily: String?
 
var fontFamilyMembers = [[Any]]()

What we need to do now is to make it possible to keep the selected font family and get its contained members every time the fontFamiliesPopup selection gets changed. This must be done in the handleFontFamilySelection(_:) IBAction method:

@IBAction func handleFontFamilySelection(_ sender: Any) {
    if let fontFamily = fontFamiliesPopup.titleOfSelectedItem {
 
        selectedFontFamily = fontFamily
 
        if let members = NSFontManager.shared.availableMembers(ofFontFamily: fontFamily) {
            fontFamilyMembers.removeAll()
            fontFamilyMembers = members
        }
    }
}
 

At first, we get the title of the item that gets selected in the fontFamiliesPopup; it matches to the font family name. We keep it in the selectedFontFamily property.

Next, we get all available members of the selected font family using the availableMembers(ofFontFamily:) method of the NSFontManager class. Those members are kept in the fontFamilyMembers class property. It’s important to remove any previous items existing in that array! We don’t want data from a previously selected font family to remain while we are selecting another one! That’s why removeAll() is called prior to assigning members to fontFamilyMembers.

However, just keeping the selected font family name and its members makes no real difference. We need to populate them to the fontTypesPopup so we see and use the font variations of each family. Why don’t we create a new method to do that? Add the next one to the ViewController class:

func updateFontTypesPopup() {
    fontTypesPopup.removeAllItems()
 
    for member in fontFamilyMembers {
        if let fontType = member[1] as? String {
            fontTypesPopup.addItem(withTitle: fontType)
        }
    }
}

Here is what is going on in the above method:

  1. Open the Objects Library again, and type button.
  2. Drag and drop a push button to view controller’s view below the popups.
  3. Set its constraints: Trailing: 20, Bottom: 20, Width: 120, Height: 21.
  4. Double click on the button to change its title to: Display All
  5. Open the Objects Library one last time, and type label in the search field.
  6. Drag and drop a label object into the view controller, under the popups but above the push button.
  7. Set the following constraints for the label: Top: 20, Leading: 20, Trailing: 20, Height: 80.

You might want to run the app now and see the available font variations after having selected a font family first. Do it, and soon enough you will end up to an unpleasant result: The fontTypesPopup does not get any value at all! But why?

Well, the previous method does, indeed, populate the available members of a font family to the fontFamiliesPopup, but where exactly is it called? Nowhere yet!

Back to the handleFontFamilySelection(_:) IBAction method, which should be updated so it calls the updateFontTypesPopup() when the available members have been retrieved using the availableMembers(ofFontFamily:) method:

@IBAction func handleFontFamilySelection(_ sender: Any) {
    if let fontFamily = fontFamiliesPopup.titleOfSelectedItem {
        selectedFontFamily = fontFamily
 
        if let members = NSFontManager.shared.availableMembers(ofFontFamily: fontFamily) {
            // ...
 
            updateFontTypesPopup()
        }
    }
}

Great, now you can run the app, select a font family, and then see the available members in the second popup!

So far so good, but we still have some more distance to run and get to finish line. When selecting a font member from the second popup, an actual sample should be shown in the sampleLabel label. We can make that happen if we update the font of the sample label every time a font variation is selected. And here is a new thing: How can we create a font (a NSFont object) using the data we have so far?

NSFontManager will be our tool again, as it provides a method named font(withFamily:traits:weight:size:) that returns a NSFont object. If you think about it, we have values for all parameters, as traits and weight are parts of the font member data that we keep in the fontFamilyMembers collection. Also, the selected font family is also kept to the selectedFontFamily property. Regarding size, we’ll set a random value, it doesn’t really matter.

In the handleFontTypeSelection(_:) IBAction method we are going to implement all the logic that will allow the creation of a new font object, which in turn we will set to the sample label along with the PostScript name of the font.

@IBAction func handleFontTypeSelection(_ sender: Any) {
    let selectedMember = fontFamilyMembers[fontTypesPopup.indexOfSelectedItem]
 
    if let postscriptName = selectedMember[0] as? String, let weight = selectedMember[2] as? Int, let traits = selectedMember[3] as? UInt, let fontfamily = selectedFontFamily {
 
        let font = NSFontManager.shared.font(withFamily: fontfamily,
                                             traits: NSFontTraitMask(rawValue: traits),
                                             weight: weight,
                                             size: 19.0)
        sampleLabel.font = font
        sampleLabel.stringValue = postscriptName
    }
}

  1. Open the Objects Library again, and type button.
  2. Drag and drop a push button to view controller’s view below the popups.
  3. Set its constraints: Trailing: 20, Bottom: 20, Width: 120, Height: 21.
  4. Double click on the button to change its title to: Display All
  5. Open the Objects Library one last time, and type label in the search field.
  6. Drag and drop a label object into the view controller, under the popups but above the push button.
  7. Set the following constraints for the label: Top: 20, Leading: 20, Trailing: 20, Height: 80.

Run the app again, and this time you will have both a sample of the selected font, and its PostScript name too!

An Eye To The Details

Our small app is working, but there are a few details left untouched. Let’s go through them.

Regarding the first one, it’s obvious that there is no font sample when the app starts. Moreover, no font members are contained in the fontTypesPopup popup button until we update the selected font family. To get around that, we will go back to one of the first methods created here, the populateFontFamilies(). In it we must make a call to the handleFontFamilySelection(_:) IBAction method and trigger that way the gathering of the font family’s available members:

func populateFontFamilies() {
    // ...
 
    handleFontFamilySelection(self)
}

 This fixes the missing values on the second popup when the app starts, but it doesn’t fix the missing font sample. To make the sample label show the font sample of the first member found in the fontTypesPopup popup button automatically, we need to update the updateFontTypesPopup() method as shown in the next snippet:

func updateFontTypesPopup() {
    // ...
 
    fontTypesPopup.selectItem(at: 0)    
    handleFontTypeSelection(self)
}

First, we auto-select the first item in the popup. Then, we call the handleFontTypeSelection(_:) IBAction method to create the font based on the selected member and update the sample label.

Lastly, one more detail that will show us a general technique beyond the demo app specifics…

Updating The Window title

Our app’s window title is saying “Window” (unless you changed that in Interface Builder), but wouldn’t be nice to make it show the selected font family’s name?

Accessing the window programmatically is easy and it’s done through the view property (main view) of the view controller as you will see right next. Go to the handleFontFamilySelection(_:) IBAction method and add the following line:

@IBAction func handleFontFamilySelection(_ sender: Any) {
    if let fontFamily = fontFamiliesPopup.titleOfSelectedItem {
        // ...
 
        view.window?.title = fontFamily
    }
}

The window now displays the selected font family!

Completing The App With A New Window Controller

Our small application is working perfectly at this point and all steps presented so far have already shown some important how-to stuff regarding macOS programming. However, the “Display All” push button is not functioning yet, and this is the part that we will focus on here. This will give us the chance to explore and talk about more things that will make this post more complete and valuable.

The purpose of the “Display All” push button is to present a new window where font variations of a selected font family will be displayed all together, formatted based on each font’s PostScript name. That might not sound such a big deal given that we can already see them one by one through the popup buttons we have. By doing that though, we will learn:

  • How to create a new macOS project.
  • What the most important parts of the generated project are.
  • What is a window controller and how to configure its contained window, including size, position, title, and a lot more.
  • How to add graphical controls into a view controller.
  • How to interact with those graphical controls, update their values and react on actions triggered by them.
  • How to create additional window controllers.
  • How to change a window’s appearance so it looks like a utility or auxiliary panel.
  • How to load and present and close a window programmatically.

So, if all that sound interesting to you, just keep reading.

Adding A New Window Controller

Back to Main.storyboard file, let’s add a new window controller along with a view controller to our canvas.

Note: Additional window controllers are not required to exist in the Main.storyboard file. You can create new storyboard files to host them. Here we will have them all into the Main storyboard so we keep things simple.

  • How to create a new macOS project.
  • What the most important parts of the generated project are.
  • What is a window controller and how to configure its contained window, including size, position, title, and a lot more.
  • How to add graphical controls into a view controller.
  • How to interact with those graphical controls, update their values and react on actions triggered by them.
  • How to create additional window controllers.
  • How to change a window’s appearance so it looks like a utility or auxiliary panel.
  • How to load and present and close a window programmatically.

You will notice that along with the window controller, an attached view controller is added as well!

What Kind Of Panel Do You Prefer?

Now, let’s see how we can change the default appearance so we can make our new window look like an auxiliary panel.

At first, click on the new window and then show the Identity Inspector. Look at the Custom Class section, where the window’s class is automatically set to NSWindow.

Click on that field, type: NSPanel and hit the Return key on your keyboard.

And now, switch to the Attributes Inspector. A new section has been added to the top, named Panel! The default value in the Style popup is Regular Panel, which means the normal window appearance. Two more panel types are supported:

  • How to create a new macOS project.
  • What the most important parts of the generated project are.
  • What is a window controller and how to configure its contained window, including size, position, title, and a lot more.
  • How to add graphical controls into a view controller.
  • How to interact with those graphical controls, update their values and react on actions triggered by them.
  • How to create additional window controllers.
  • How to change a window’s appearance so it looks like a utility or auxiliary panel.
  • How to load and present and close a window programmatically.

Both of them are meant to exist as auxiliary windows that contain supplementary options or information to the content shown on the main window.

Change the panel style and go through all options; see how the window’s appearance is being changed accordingly. A HUD panel is similar to a Utility panel, with the obvious graphical difference. It’s darker and translucent. Also, only the close button is available on the window’s bar.

Once you finish examining panel style settings, choose HUD as the style for our new window.

You are encouraged to read the Human Interface Guidelines about panels here.

While still being in the Attributes Inspector, set the “Fonts Display” text (without the quotes) as the window’s title.

One last thing before we move to the next step. Show the Identity inspector and in the Identifier text field under the Identity section type the value: fontsDisplayStoryboardID. You will see in a while why we need that.

The Fonts Display View Controller

Along with the window controller, a new view controller was added too to the project. That brings us to the need to create a new NSViewController subclass that we will connect to that new view controller. Press Cmd + N in your keyboard, and select Cocoa Class under the Source section.

Click Next, and change the Subclass of: field to NSViewController. In the Class field, type FontsDisplayViewController. Get finished with the creation of the new file.

Again to the Main.storyboard file, click on the View Controller object, and set the FontsDisplayViewController value to the Class field in the Identity Inspector.

Next, click on the main view of the view controller, and show the Size Inspector. Set its size to 480×400.

Let’s add two new Cocoa controls now to the view.

  1. Open the Objects Library again, and type button.
  2. Drag and drop a push button to view controller’s view below the popups.
  3. Set its constraints: Trailing: 20, Bottom: 20, Width: 120, Height: 21.
  4. Double click on the button to change its title to: Display All
  5. Open the Objects Library one last time, and type label in the search field.
  6. Drag and drop a label object into the view controller, under the popups but above the push button.
  7. Set the following constraints for the label: Top: 20, Leading: 20, Trailing: 20, Height: 80.

We will use the textview to display all available font members of a font family formatted. The button will be used to close the window.

Note: Adding a button to close the window is not really necessary, as the panel itself provides a close button. However, we are doing that here clearly for learning reasons; to see how we can close a window programmatically.

In the FontsDisplayViewController.swift file now, let’s declare an IBOutlet property for the textview, and an IBAction method for the button:

@IBOutlet var fontsTextView: NSTextView!
 
@IBAction func closeWindow(_ sender: Any) {
 
}

Finally, in the Main.storyboard file again, click to select the Fonts Display View Controller object and from the Connections Inspector connect the fontsTextView outlet to the textview, and the closeWindow(_:) action to the button.

There is one disturbing thing in the UI we are being creating, and that is the white textview on the dark and translucent HUD window. That’s okay and tolerable in the storyboard, however who would want it when using the app?

So, open the FontsDisplayViewController.swift file and add the following function:

func setupTextView() {
    fontsTextView.backgroundColor = NSColor(white: 1.0, alpha: 0.0)
    fontsTextView.enclosingScrollView?.backgroundColor = NSColor(white: 1.0, alpha: 0.0)
    fontsTextView.isEditable = false
    fontsTextView.enclosingScrollView?.autohidesScrollers = true
}
 

The above:

  • How to create a new macOS project.
  • What the most important parts of the generated project are.
  • What is a window controller and how to configure its contained window, including size, position, title, and a lot more.
  • How to add graphical controls into a view controller.
  • How to interact with those graphical controls, update their values and react on actions triggered by them.
  • How to create additional window controllers.
  • How to change a window’s appearance so it looks like a utility or auxiliary panel.
  • How to load and present and close a window programmatically.

We will call setupTextView() right before the view gets appeared:

override func viewWillAppear() {
    super.viewWillAppear()
 
    setupTextView()
}

Loading And Presenting The Window Controller

The UI of the auxiliary panel is ready, so let’s see how it looks like when the application is running. Before we load and present the new window controller, we must declare the following two properties in the FontsDisplayViewController.swift file:

var fontFamily: String?
var fontFamilyMembers = [[Any]]()

We need both of them, as we are going to pass the selected font family name and its members from the ViewController class to FontsDisplayViewController. We’ll see how we’ll make use of them in a while. Just declaring them for now is good enough.

So, let’s proceed to the presentation of the new window controller. Open the ViewController.swift file, and go to the displayAllFonts(_:) IBAction method. Remember that this action method is connected to the “Display All” button in the default window of our app, so any code added here will be executed when that button is clicked.

The idea behind presenting a window controller that has been created graphically in a storyboard file, is to initialize a **NSStoryboard** object and ask it to instantiate that window controller. A NSStoryboard object is being initialized by providing the storyboard name, but in a not-so-much straightforward way. Here it is:

let storyboardName = NSStoryboard.Name(stringLiteral: "Main")
let storyboard = NSStoryboard(name: storyboardName, bundle: nil)

As you can see, the NSStoryboard initializer does not accept a string value as an argument (aka the storyboard name). It expects for a NSStoryboard.Name value instead, where Name is String type alias. Value of bundle can be left nil.

With the storyboard object being initialized now, we can instantiate our window controller. For that purpose we will use the storyboard Identifier we had previously set in Interface Builder:

let storyboardID = NSStoryboard.SceneIdentifier(stringLiteral: "fontsDisplayStoryboardID")
 
if let fontsDisplayWindowController = storyboard.instantiateController(withIdentifier: storyboardID) as? NSWindowController {
 
}

instantiateController(withIdentifier:) is the method of the NSStoryboard class that instantiates the window controller in the above code. It returns an Any? value, so it is necessary to:

  • How to create a new macOS project.
  • What the most important parts of the generated project are.
  • What is a window controller and how to configure its contained window, including size, position, title, and a lot more.
  • How to add graphical controls into a view controller.
  • How to interact with those graphical controls, update their values and react on actions triggered by them.
  • How to create additional window controllers.
  • How to change a window’s appearance so it looks like a utility or auxiliary panel.
  • How to load and present and close a window programmatically.

Note: Apart from window controllers, it is also possible to instantiate view controllers using the *instantiateController(withIdentifier:)* method, as long as a storyboard Identifier has been set for them in Interface Builder. That’s why that method returns an *Any* value instead of a *NSWindowController* object. It’s our duty to cast to the proper type.

Also, in the above snippet you see that the window controller’s identifier is not given as a plain String value. Instead, a NSStoryboard.SceneIdentifier value must be provided, where SceneIdentifier is a String type alias.

Supposedly at this point the new window controller has been instantiated. That’s not enough though, we must access its content view controller, and pass the selected font family and its members collection to it. NSWindowController has a property named contentViewController which represents the view controller attached to the window controller. We will use it, and after having accessed it we will pass the values we want:

if let fontsDisplayVC = fontsDisplayWindowController.contentViewController as? FontsDisplayViewController {
    fontsDisplayVC.fontFamily = selectedFontFamily
    fontsDisplayVC.fontFamilyMembers = fontFamilyMembers
}

Finally, we can present the window as follows:

fontsDisplayWindowController.showWindow(nil)

The above are the steps required to instantiate a window controller programmatically, to get its content view controller, and eventually present them all. Right next is the displayAllFonts(_:) method in one piece:

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@IBAction func displayAllFonts(_ sender: Any) {
    let storyboardName = NSStoryboard.Name(stringLiteral: "Main")
    let storyboard = NSStoryboard(name: storyboardName, bundle: nil)
 
    let storyboardID = NSStoryboard.SceneIdentifier(stringLiteral: "fontsDisplayStoryboardID")
 
    if let fontsDisplayWindowController = storyboard.instantiateController(withIdentifier: storyboardID) as? NSWindowController {
 
        if let fontsDisplayVC = fontsDisplayWindowController.contentViewController as? FontsDisplayViewController {
            fontsDisplayVC.fontFamily = selectedFontFamily
            fontsDisplayVC.fontFamilyMembers = fontFamilyMembers
        }
 
        fontsDisplayWindowController.showWindow(nil)
    }
}

Now you can run the app and click on the “Display All” button. There will be no content yet, however you will have your first HUD panel!

Displaying Fonts

What we are going to achieve in this part is to display all font variations contained in a selected font family one after another in the textview. More precisely, the font PostScript names. Furthermore, each displayed font variation is going to be formatted according to the font it represents.

We will achieve that by creating an attributed string that will contain all PostScript names separated by the newline character “\n”, and by adding new font attributes for each displayed line. At the end, that attributed string will be assigned to the textview.

Let’s get started by creating a new method in the FontsDisplayViewController class. We’ll name it showFonts(), and the first thing we’ll do is to make sure that the font family name exists.

func showFonts() {
    guard let fontFamily = fontFamily else { return }    
}
 

Remember that fontFamily is supposed to get its value when the “Display All” push button is clicked on the main window of the app.

Next, let’s declare the following two variables:

var fontPostscriptNames = ""
var lengths = [Int]()

fontPostscriptNames is the string that will hold all PostScript names that will be displayed on the textview. lengths is an array that will keep the length of each PostScript name. I’ll explain why we need it later.

Now, let’s gather all PostScript names from the font family members and let’s build the display string. At the same time, we’ll be storing each name’s length:

for member in fontFamilyMembers {
    if let postscript = member[0] as? String {
        fontPostscriptNames += "\(postscript)\n"
        lengths.append(postscript.count)
    }
}

Once again, the fontPostscriptNames string is composed by appending each font PostScript name and the newline symbol “\n” to it.

Having the string value we want to display, we are able to create the attributed string that will format later:

let attributedString = NSMutableAttributedString(string: fontPostscriptNames)

Here’s what’s coming next: We will go once again through all font family members, and for each one we will be creating a new font (NSFont) object based on each member’s data.

for (index, member) in fontFamilyMembers.enumerated() {
    if let weight = member[2] as? Int, let traits = member[3] as? UInt {            
        if let font = NSFontManager.shared.font(withFamily: fontFamily, traits: NSFontTraitMask(rawValue: traits), weight: weight, size: 19.0) {
 
        }
    }
}

We will use the font object above to create a new attribute which we will add it to the attributedString we initialized previously.

Now, there is a tricky part coming. Any attribute added to an attributed string must specify the range of text that it will be applied to. That range is a NSRange value, which is composed by two distinct values: location and length. Location indicates the index of the starting character a range starts from, and length shows how many characters the range will spread to.

Given the fact that we want each line of our text to have a different attribute because of the different font, we must calculate the range of the text that each font will be applied to. And here is where the lengths array is becoming handy. Each new range will start where the previous range stopped, and its length will be equal to the respective value in the lengths array. First range will start at zero.

The following code shows how we calculate the starting location for each range and how we create a new range:

var location = 0
if index > 0 {
&nbsp;&nbsp;&nbsp;&nbsp;for i in 0..<index {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;location += lengths[i] + 1
&nbsp;&nbsp;&nbsp;&nbsp;}
}
&nbsp;
let range = NSMakeRange(location, lengths[index])

In case index is zero, meaning this is the first member in the fontFamilyMembers array, the location is set to zero too (start of text). In every other case, location is the sum of all previous range lengths, including the “\n” symbol which counts as additional character in each line (that’s why “+ 1” is added to each length).

Last line shows how a range is created. NSMakeRange() function accepts two arguments, the location and the length of the range.

Finally, we can create a new attribute for each font now:

attributedString.addAttribute(NSAttributedString.Key.font, value: font, range: range)

All the above will happen for each single item found in the fontFamilyMembers array, or in other words, in the for (index, member) in fontFamilyMembers.enumerated() { ... } loop. There’s one more attribute we have to add to the entire text, and after the end of the loop. That is the text color. By default, black color is the text color of the textview. But since we are using a HUD panel which is already dark, we have to give a light color to the text.

Here is how we do that for the entire text. As you will see, specifying the range in that case is a lot easier than what we previously did:

attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: NSColor.white, range: NSMakeRange(0, attributedString.string.count))

Finally, the attributed string is ready with all the attributes set. It’s time to assign it to the textview, or more precisely, to the textStorage property of the textview:

fontsTextView.textStorage?.setAttributedString(attributedString)

Here’s the showFonts() method with its code all together:

func showFonts() {
&nbsp;&nbsp;&nbsp;&nbsp;guard let fontFamily = fontFamily else { return }
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;var fontPostscriptNames = ""
&nbsp;&nbsp;&nbsp;&nbsp;var lengths = [Int]()
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;for member in fontFamilyMembers {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if let postscript = member[0] as? String {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fontPostscriptNames += "\(postscript)\n"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lengths.append(postscript.count)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;let attributedString = NSMutableAttributedString(string: fontPostscriptNames)
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;for (index, member) in fontFamilyMembers.enumerated() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if let weight = member[2] as? Int, let traits = member[3] as? UInt {
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if let font = NSFontManager.shared.font(withFamily: fontFamily, traits: NSFontTraitMask(rawValue: traits), weight: weight, size: 19.0) {
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var location = 0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if index > 0 {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for i in 0..<index {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;location += lengths[i] + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let range = NSMakeRange(location, lengths[index])
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;attributedString.addAttribute(NSAttributedString.Key.font, value: font, range: range)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: NSColor.white, range: NSMakeRange(0, attributedString.string.count))
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;fontsTextView.textStorage?.setAttributedString(attributedString)&nbsp;&nbsp;&nbsp;&nbsp;
}

Do not forget to call it:

override func viewWillAppear() {
&nbsp;&nbsp;&nbsp;&nbsp;// ...
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;showFonts()
}

We are done! Run the app now, select any font family and click on the “Display All” button. You will get all available font variations in one place:

Closing The Window

There is one last thing to do, and that is to enable the Close button so it’s possible to close the window when clicking on it. Doing so is extremely easy as you can see right next:

@IBAction func closeWindow(_ sender: Any) {
&nbsp;&nbsp;&nbsp;&nbsp;view.window?.close()
}

Summary

We came eventually to the end of the tutorial! Through all previous parts it became quite obvious that creating a macOS application involves a lot of steps and details, and this post highlighted the most important ones given our today roadmap. There are definitely more things to explore and discuss, and in future posts we’ll be focusing on more and new stuff about macOS programming. Here we managed to create a small application with just a few graphical controls on its UI, we implemented code to get the font information we wanted, to make visual updates to controls and to “play” with windows. By going into the making process all these, we had the chance to meet important concepts and to talk about standard techniques and practices. I hope this post will become a guide to your efforts in building your own macOS applications. Don’t forget to visit Apple’s documentation and Human Interface Guidelines if you find yourself stuck, or you just want to make sure that you are playing by the rules. See you soon!

For reference, you can download the full project on GitHub.

Thanks for reading ❤

If you liked this post, share it with all of your programming buddies!

#ios #macos #swift

What is GEEK

Buddha Community

Getting Started with macOS Programming

Noah Sykes

1555583133

great

Shubham Ankit

Shubham Ankit

1657081614

How to Automate Excel with Python | Python Excel Tutorial (OpenPyXL)

How to Automate Excel with Python

In this article, We will show how we can use python to automate Excel . A useful Python library is Openpyxl which we will learn to do Excel Automation

What is OPENPYXL

Openpyxl is a Python library that is used to read from an Excel file or write to an Excel file. Data scientists use Openpyxl for data analysis, data copying, data mining, drawing charts, styling sheets, adding formulas, and more.

Workbook: A spreadsheet is represented as a workbook in openpyxl. A workbook consists of one or more sheets.

Sheet: A sheet is a single page composed of cells for organizing data.

Cell: The intersection of a row and a column is called a cell. Usually represented by A1, B5, etc.

Row: A row is a horizontal line represented by a number (1,2, etc.).

Column: A column is a vertical line represented by a capital letter (A, B, etc.).

Openpyxl can be installed using the pip command and it is recommended to install it in a virtual environment.

pip install openpyxl

CREATE A NEW WORKBOOK

We start by creating a new spreadsheet, which is called a workbook in Openpyxl. We import the workbook module from Openpyxl and use the function Workbook() which creates a new workbook.

from openpyxl
import Workbook
#creates a new workbook
wb = Workbook()
#Gets the first active worksheet
ws = wb.active
#creating new worksheets by using the create_sheet method

ws1 = wb.create_sheet("sheet1", 0) #inserts at first position
ws2 = wb.create_sheet("sheet2") #inserts at last position
ws3 = wb.create_sheet("sheet3", -1) #inserts at penultimate position

#Renaming the sheet
ws.title = "Example"

#save the workbook
wb.save(filename = "example.xlsx")

READING DATA FROM WORKBOOK

We load the file using the function load_Workbook() which takes the filename as an argument. The file must be saved in the same working directory.

#loading a workbook
wb = openpyxl.load_workbook("example.xlsx")

 

GETTING SHEETS FROM THE LOADED WORKBOOK

 

#getting sheet names
wb.sheetnames
result = ['sheet1', 'Sheet', 'sheet3', 'sheet2']

#getting a particular sheet
sheet1 = wb["sheet2"]

#getting sheet title
sheet1.title
result = 'sheet2'

#Getting the active sheet
sheetactive = wb.active
result = 'sheet1'

 

ACCESSING CELLS AND CELL VALUES

 

#get a cell from the sheet
sheet1["A1"] <
  Cell 'Sheet1'.A1 >

  #get the cell value
ws["A1"].value 'Segment'

#accessing cell using row and column and assigning a value
d = ws.cell(row = 4, column = 2, value = 10)
d.value
10

 

ITERATING THROUGH ROWS AND COLUMNS

 

#looping through each row and column
for x in range(1, 5):
  for y in range(1, 5):
  print(x, y, ws.cell(row = x, column = y)
    .value)

#getting the highest row number
ws.max_row
701

#getting the highest column number
ws.max_column
19

There are two functions for iterating through rows and columns.

Iter_rows() => returns the rows
Iter_cols() => returns the columns {
  min_row = 4, max_row = 5, min_col = 2, max_col = 5
} => This can be used to set the boundaries
for any iteration.

Example:

#iterating rows
for row in ws.iter_rows(min_row = 2, max_col = 3, max_row = 3):
  for cell in row:
  print(cell) <
  Cell 'Sheet1'.A2 >
  <
  Cell 'Sheet1'.B2 >
  <
  Cell 'Sheet1'.C2 >
  <
  Cell 'Sheet1'.A3 >
  <
  Cell 'Sheet1'.B3 >
  <
  Cell 'Sheet1'.C3 >

  #iterating columns
for col in ws.iter_cols(min_row = 2, max_col = 3, max_row = 3):
  for cell in col:
  print(cell) <
  Cell 'Sheet1'.A2 >
  <
  Cell 'Sheet1'.A3 >
  <
  Cell 'Sheet1'.B2 >
  <
  Cell 'Sheet1'.B3 >
  <
  Cell 'Sheet1'.C2 >
  <
  Cell 'Sheet1'.C3 >

To get all the rows of the worksheet we use the method worksheet.rows and to get all the columns of the worksheet we use the method worksheet.columns. Similarly, to iterate only through the values we use the method worksheet.values.


Example:

for row in ws.values:
  for value in row:
  print(value)

 

WRITING DATA TO AN EXCEL FILE

Writing to a workbook can be done in many ways such as adding a formula, adding charts, images, updating cell values, inserting rows and columns, etc… We will discuss each of these with an example.

 

CREATING AND SAVING A NEW WORKBOOK

 

#creates a new workbook
wb = openpyxl.Workbook()

#saving the workbook
wb.save("new.xlsx")

 

ADDING AND REMOVING SHEETS

 

#creating a new sheet
ws1 = wb.create_sheet(title = "sheet 2")

#creating a new sheet at index 0
ws2 = wb.create_sheet(index = 0, title = "sheet 0")

#checking the sheet names
wb.sheetnames['sheet 0', 'Sheet', 'sheet 2']

#deleting a sheet
del wb['sheet 0']

#checking sheetnames
wb.sheetnames['Sheet', 'sheet 2']

 

ADDING CELL VALUES

 

#checking the sheet value
ws['B2'].value
null

#adding value to cell
ws['B2'] = 367

#checking value
ws['B2'].value
367

 

ADDING FORMULAS

 

We often require formulas to be included in our Excel datasheet. We can easily add formulas using the Openpyxl module just like you add values to a cell.
 

For example:

import openpyxl
from openpyxl
import Workbook

wb = openpyxl.load_workbook("new1.xlsx")
ws = wb['Sheet']

ws['A9'] = '=SUM(A2:A8)'

wb.save("new2.xlsx")

The above program will add the formula (=SUM(A2:A8)) in cell A9. The result will be as below.

image

 

MERGE/UNMERGE CELLS

Two or more cells can be merged to a rectangular area using the method merge_cells(), and similarly, they can be unmerged using the method unmerge_cells().

For example:
Merge cells

#merge cells B2 to C9
ws.merge_cells('B2:C9')
ws['B2'] = "Merged cells"

Adding the above code to the previous example will merge cells as below.

image

UNMERGE CELLS

 

#unmerge cells B2 to C9
ws.unmerge_cells('B2:C9')

The above code will unmerge cells from B2 to C9.

INSERTING AN IMAGE

To insert an image we import the image function from the module openpyxl.drawing.image. We then load our image and add it to the cell as shown in the below example.

Example:

import openpyxl
from openpyxl
import Workbook
from openpyxl.drawing.image
import Image

wb = openpyxl.load_workbook("new1.xlsx")
ws = wb['Sheet']
#loading the image(should be in same folder)
img = Image('logo.png')
ws['A1'] = "Adding image"
#adjusting size
img.height = 130
img.width = 200
#adding img to cell A3

ws.add_image(img, 'A3')

wb.save("new2.xlsx")

Result:

image

CREATING CHARTS

Charts are essential to show a visualization of data. We can create charts from Excel data using the Openpyxl module chart. Different forms of charts such as line charts, bar charts, 3D line charts, etc., can be created. We need to create a reference that contains the data to be used for the chart, which is nothing but a selection of cells (rows and columns). I am using sample data to create a 3D bar chart in the below example:

Example

import openpyxl
from openpyxl
import Workbook
from openpyxl.chart
import BarChart3D, Reference, series

wb = openpyxl.load_workbook("example.xlsx")
ws = wb.active

values = Reference(ws, min_col = 3, min_row = 2, max_col = 3, max_row = 40)
chart = BarChart3D()
chart.add_data(values)
ws.add_chart(chart, "E3")
wb.save("MyChart.xlsx")

Result
image


How to Automate Excel with Python with Video Tutorial

Welcome to another video! In this video, We will cover how we can use python to automate Excel. I'll be going over everything from creating workbooks to accessing individual cells and stylizing cells. There is a ton of things that you can do with Excel but I'll just be covering the core/base things in OpenPyXl.

⭐️ Timestamps ⭐️
00:00 | Introduction
02:14 | Installing openpyxl
03:19 | Testing Installation
04:25 | Loading an Existing Workbook
06:46 | Accessing Worksheets
07:37 | Accessing Cell Values
08:58 | Saving Workbooks
09:52 | Creating, Listing and Changing Sheets
11:50 | Creating a New Workbook
12:39 | Adding/Appending Rows
14:26 | Accessing Multiple Cells
20:46 | Merging Cells
22:27 | Inserting and Deleting Rows
23:35 | Inserting and Deleting Columns
24:48 | Copying and Moving Cells
26:06 | Practical Example, Formulas & Cell Styling

📄 Resources 📄
OpenPyXL Docs: https://openpyxl.readthedocs.io/en/stable/ 
Code Written in This Tutorial: https://github.com/techwithtim/ExcelPythonTutorial 
Subscribe: https://www.youtube.com/c/TechWithTim/featured 

#python 

Bongani  Ngema

Bongani Ngema

1670346000

How to Create & Add Content - Images, Text To Modern SharePoint Pages

Description

Requirement is to create Modern pages with content, which includes images and text. 

The Content is in SharePoint List. The pages are created from a Page Template.

To get Text part from Page template, use below PowerShell,

#get page textpart instance id
$parts=Get-PnPPageComponent -Page <pagename.aspx>

Execute the below PowerShell to create pages with HTML content from SharePoint List.

$logFile = "Logs\LogFile.log"
Start - Transcript - Path $logFile - Append
#Variables
$libName = "Site Pages"
$siteURL = "https://tenant.sharepoint.com/"
$contentType = "Group and Division Page"
$listname = "Content"
$sectionCategoy = "Our organisation"
#End
Try {
    #Connect to PnP Online
    $connection = Connect - PnPOnline - Url $siteURL - UseWebLogin - ReturnConnection - WarningAction Ignore
    #Get items from Content list
    $items = Get - PnPListItem - List $listName - PageSize 100
    foreach($item in $items) {
        if ($null - ne $item["Title"] - and $null - ne $item["Content"]) {
            #Get Page webparts instance Id
            #$parts = Get - PnPPageComponent - Page PageTemplate.aspx
            # load the page template
            $template = Get - PnPClientSidePage - Identity "Templates/Division-page-template"
            #Get page name
            $fullFileName = $item["Title"].Replace(" ", "_") + ".aspx"
            #Create fileURL
            $fileURL = $siteURL + $libName + "/" + $fullFileName
            # save a new SharePoint Page based on the Page Template
            $template.Save($fullFileName)
            $page = Get - PnPPage - Identity $fullFileName
            $htmlToInject = $item["Content"]
            $htmlToInject = $htmlToInject.TrimStart('{"Html":"').TrimEnd('"}') - replace([regex]::Escape('\n')), '' - replace([regex]::Escape('<a href=\')),' < a href = ' -replace ([regex]:: Escape('\
                        ">')),'" > ' -replace ([regex]::Escape(' & bull; % 09 ')),'
                        ' -replace '
                        https:
                        /*','https://'
            #Set PnP Page Text

            Set-PnPPageTextPart -Page $page -InstanceId "9fab3ce6-0638-4008-a9b9-cf2b784245b5" -Text $htmlToInject


            #publish page
            Set-PnPPage -Identity $fullFileName -Title $item["Title"] -ContentType $contentType -Publish

            #get site pages library
            $sitepagelist= Get-PnPList -Identity 'Site Pages'
            #get page Id and page Item to update section category
            $pageItem=Get-PnPListItem -List $sitepagelist -Id $page.PageId
            Set-PnPListItem -Values @{"SectionCategory" = $sectionCategoy} -List $sitepagelist -Identity $pageItem

        }
        else
        {
            Write-Host "Title or Content has no value"
        }
    }
}
Catch {
    Write-Host "Error: $($_.Exception.Message)" -Foregroundcolor Red
}
Stop-Transcript

Original article source at: https://www.c-sharpcorner.com/

#sharepoint #image #text 

How to Create Arrays in Python

In this tutorial, you'll know the basics of how to create arrays in Python using the array module. Learn how to use Python arrays. You'll see how to define them and the different methods commonly used for performing operations on them.

This tutorialvideo on 'Arrays in Python' will help you establish a strong hold on all the fundamentals in python programming language. Below are the topics covered in this video:  
1:15 What is an array?
2:53 Is python list same as an array?
3:48  How to create arrays in python?
7:19 Accessing array elements
9:59 Basic array operations
        - 10:33  Finding the length of an array
        - 11:44  Adding Elements
        - 15:06  Removing elements
        - 18:32  Array concatenation
       - 20:59  Slicing
       - 23:26  Looping  


Python Array Tutorial – Define, Index, Methods

In this article, you'll learn how to use Python arrays. You'll see how to define them and the different methods commonly used for performing operations on them.

The artcile covers arrays that you create by importing the array module. We won't cover NumPy arrays here.

Table of Contents

  1. Introduction to Arrays
    1. The differences between Lists and Arrays
    2. When to use arrays
  2. How to use arrays
    1. Define arrays
    2. Find the length of arrays
    3. Array indexing
    4. Search through arrays
    5. Loop through arrays
    6. Slice an array
  3. Array methods for performing operations
    1. Change an existing value
    2. Add a new value
    3. Remove a value
  4. Conclusion

Let's get started!

What are Python Arrays?

Arrays are a fundamental data structure, and an important part of most programming languages. In Python, they are containers which are able to store more than one item at the same time.

Specifically, they are an ordered collection of elements with every value being of the same data type. That is the most important thing to remember about Python arrays - the fact that they can only hold a sequence of multiple items that are of the same type.

What's the Difference between Python Lists and Python Arrays?

Lists are one of the most common data structures in Python, and a core part of the language.

Lists and arrays behave similarly.

Just like arrays, lists are an ordered sequence of elements.

They are also mutable and not fixed in size, which means they can grow and shrink throughout the life of the program. Items can be added and removed, making them very flexible to work with.

However, lists and arrays are not the same thing.

Lists store items that are of various data types. This means that a list can contain integers, floating point numbers, strings, or any other Python data type, at the same time. That is not the case with arrays.

As mentioned in the section above, arrays store only items that are of the same single data type. There are arrays that contain only integers, or only floating point numbers, or only any other Python data type you want to use.

When to Use Python Arrays

Lists are built into the Python programming language, whereas arrays aren't. Arrays are not a built-in data structure, and therefore need to be imported via the array module in order to be used.

Arrays of the array module are a thin wrapper over C arrays, and are useful when you want to work with homogeneous data.

They are also more compact and take up less memory and space which makes them more size efficient compared to lists.

If you want to perform mathematical calculations, then you should use NumPy arrays by importing the NumPy package. Besides that, you should just use Python arrays when you really need to, as lists work in a similar way and are more flexible to work with.

How to Use Arrays in Python

In order to create Python arrays, you'll first have to import the array module which contains all the necassary functions.

There are three ways you can import the array module:

  • By using import array at the top of the file. This includes the module array. You would then go on to create an array using array.array().
import array

#how you would create an array
array.array()
  • Instead of having to type array.array() all the time, you could use import array as arr at the top of the file, instead of import array alone. You would then create an array by typing arr.array(). The arr acts as an alias name, with the array constructor then immediately following it.
import array as arr

#how you would create an array
arr.array()
  • Lastly, you could also use from array import *, with * importing all the functionalities available. You would then create an array by writing the array() constructor alone.
from array import *

#how you would create an array
array()

How to Define Arrays in Python

Once you've imported the array module, you can then go on to define a Python array.

The general syntax for creating an array looks like this:

variable_name = array(typecode,[elements])

Let's break it down:

  • variable_name would be the name of the array.
  • The typecode specifies what kind of elements would be stored in the array. Whether it would be an array of integers, an array of floats or an array of any other Python data type. Remember that all elements should be of the same data type.
  • Inside square brackets you mention the elements that would be stored in the array, with each element being separated by a comma. You can also create an empty array by just writing variable_name = array(typecode) alone, without any elements.

Below is a typecode table, with the different typecodes that can be used with the different data types when defining Python arrays:

TYPECODEC TYPEPYTHON TYPESIZE
'b'signed charint1
'B'unsigned charint1
'u'wchar_tUnicode character2
'h'signed shortint2
'H'unsigned shortint2
'i'signed intint2
'I'unsigned intint2
'l'signed longint4
'L'unsigned longint4
'q'signed long longint8
'Q'unsigned long longint8
'f'floatfloat4
'd'doublefloat8

Tying everything together, here is an example of how you would define an array in Python:

import array as arr 

numbers = arr.array('i',[10,20,30])


print(numbers)

#output

#array('i', [10, 20, 30])

Let's break it down:

  • First we included the array module, in this case with import array as arr .
  • Then, we created a numbers array.
  • We used arr.array() because of import array as arr .
  • Inside the array() constructor, we first included i, for signed integer. Signed integer means that the array can include positive and negative values. Unsigned integer, with H for example, would mean that no negative values are allowed.
  • Lastly, we included the values to be stored in the array in square brackets.

Keep in mind that if you tried to include values that were not of i typecode, meaning they were not integer values, you would get an error:

import array as arr 

numbers = arr.array('i',[10.0,20,30])


print(numbers)

#output

#Traceback (most recent call last):
# File "/Users/dionysialemonaki/python_articles/demo.py", line 14, in <module>
#   numbers = arr.array('i',[10.0,20,30])
#TypeError: 'float' object cannot be interpreted as an integer

In the example above, I tried to include a floating point number in the array. I got an error because this is meant to be an integer array only.

Another way to create an array is the following:

from array import *

#an array of floating point values
numbers = array('d',[10.0,20.0,30.0])

print(numbers)

#output

#array('d', [10.0, 20.0, 30.0])

The example above imported the array module via from array import * and created an array numbers of float data type. This means that it holds only floating point numbers, which is specified with the 'd' typecode.

How to Find the Length of an Array in Python

To find out the exact number of elements contained in an array, use the built-in len() method.

It will return the integer number that is equal to the total number of elements in the array you specify.

import array as arr 

numbers = arr.array('i',[10,20,30])


print(len(numbers))

#output
# 3

In the example above, the array contained three elements – 10, 20, 30 – so the length of numbers is 3.

Array Indexing and How to Access Individual Items in an Array in Python

Each item in an array has a specific address. Individual items are accessed by referencing their index number.

Indexing in Python, and in all programming languages and computing in general, starts at 0. It is important to remember that counting starts at 0 and not at 1.

To access an element, you first write the name of the array followed by square brackets. Inside the square brackets you include the item's index number.

The general syntax would look something like this:

array_name[index_value_of_item]

Here is how you would access each individual element in an array:

import array as arr 

numbers = arr.array('i',[10,20,30])

print(numbers[0]) # gets the 1st element
print(numbers[1]) # gets the 2nd element
print(numbers[2]) # gets the 3rd element

#output

#10
#20
#30

Remember that the index value of the last element of an array is always one less than the length of the array. Where n is the length of the array, n - 1 will be the index value of the last item.

Note that you can also access each individual element using negative indexing.

With negative indexing, the last element would have an index of -1, the second to last element would have an index of -2, and so on.

Here is how you would get each item in an array using that method:

import array as arr 

numbers = arr.array('i',[10,20,30])

print(numbers[-1]) #gets last item
print(numbers[-2]) #gets second to last item
print(numbers[-3]) #gets first item
 
#output

#30
#20
#10

How to Search Through an Array in Python

You can find out an element's index number by using the index() method.

You pass the value of the element being searched as the argument to the method, and the element's index number is returned.

import array as arr 

numbers = arr.array('i',[10,20,30])

#search for the index of the value 10
print(numbers.index(10))

#output

#0

If there is more than one element with the same value, the index of the first instance of the value will be returned:

import array as arr 


numbers = arr.array('i',[10,20,30,10,20,30])

#search for the index of the value 10
#will return the index number of the first instance of the value 10
print(numbers.index(10))

#output

#0

How to Loop through an Array in Python

You've seen how to access each individual element in an array and print it out on its own.

You've also seen how to print the array, using the print() method. That method gives the following result:

import array as arr 

numbers = arr.array('i',[10,20,30])

print(numbers)

#output

#array('i', [10, 20, 30])

What if you want to print each value one by one?

This is where a loop comes in handy. You can loop through the array and print out each value, one-by-one, with each loop iteration.

For this you can use a simple for loop:

import array as arr 

numbers = arr.array('i',[10,20,30])

for number in numbers:
    print(number)
    
#output
#10
#20
#30

You could also use the range() function, and pass the len() method as its parameter. This would give the same result as above:

import array as arr  

values = arr.array('i',[10,20,30])

#prints each individual value in the array
for value in range(len(values)):
    print(values[value])

#output

#10
#20
#30

How to Slice an Array in Python

To access a specific range of values inside the array, use the slicing operator, which is a colon :.

When using the slicing operator and you only include one value, the counting starts from 0 by default. It gets the first item, and goes up to but not including the index number you specify.

import array as arr 

#original array
numbers = arr.array('i',[10,20,30])

#get the values 10 and 20 only
print(numbers[:2])  #first to second position

#output

#array('i', [10, 20])

When you pass two numbers as arguments, you specify a range of numbers. In this case, the counting starts at the position of the first number in the range, and up to but not including the second one:

import array as arr 

#original array
numbers = arr.array('i',[10,20,30])


#get the values 20 and 30 only
print(numbers[1:3]) #second to third position

#output

#rray('i', [20, 30])

Methods For Performing Operations on Arrays in Python

Arrays are mutable, which means they are changeable. You can change the value of the different items, add new ones, or remove any you don't want in your program anymore.

Let's see some of the most commonly used methods which are used for performing operations on arrays.

How to Change the Value of an Item in an Array

You can change the value of a specific element by speficying its position and assigning it a new value:

import array as arr 

#original array
numbers = arr.array('i',[10,20,30])

#change the first element
#change it from having a value of 10 to having a value of 40
numbers[0] = 40

print(numbers)

#output

#array('i', [40, 20, 30])

How to Add a New Value to an Array

To add one single value at the end of an array, use the append() method:

import array as arr 

#original array
numbers = arr.array('i',[10,20,30])

#add the integer 40 to the end of numbers
numbers.append(40)

print(numbers)

#output

#array('i', [10, 20, 30, 40])

Be aware that the new item you add needs to be the same data type as the rest of the items in the array.

Look what happens when I try to add a float to an array of integers:

import array as arr 

#original array
numbers = arr.array('i',[10,20,30])

#add the integer 40 to the end of numbers
numbers.append(40.0)

print(numbers)

#output

#Traceback (most recent call last):
#  File "/Users/dionysialemonaki/python_articles/demo.py", line 19, in <module>
#   numbers.append(40.0)
#TypeError: 'float' object cannot be interpreted as an integer

But what if you want to add more than one value to the end an array?

Use the extend() method, which takes an iterable (such as a list of items) as an argument. Again, make sure that the new items are all the same data type.

import array as arr 

#original array
numbers = arr.array('i',[10,20,30])

#add the integers 40,50,60 to the end of numbers
#The numbers need to be enclosed in square brackets

numbers.extend([40,50,60])

print(numbers)

#output

#array('i', [10, 20, 30, 40, 50, 60])

And what if you don't want to add an item to the end of an array? Use the insert() method, to add an item at a specific position.

The insert() function takes two arguments: the index number of the position the new element will be inserted, and the value of the new element.

import array as arr 

#original array
numbers = arr.array('i',[10,20,30])

#add the integer 40 in the first position
#remember indexing starts at 0

numbers.insert(0,40)

print(numbers)

#output

#array('i', [40, 10, 20, 30])

How to Remove a Value from an Array

To remove an element from an array, use the remove() method and include the value as an argument to the method.

import array as arr 

#original array
numbers = arr.array('i',[10,20,30])

numbers.remove(10)

print(numbers)

#output

#array('i', [20, 30])

With remove(), only the first instance of the value you pass as an argument will be removed.

See what happens when there are more than one identical values:

import array as arr 

#original array
numbers = arr.array('i',[10,20,30,10,20])

numbers.remove(10)

print(numbers)

#output

#array('i', [20, 30, 10, 20])

Only the first occurence of 10 is removed.

You can also use the pop() method, and specify the position of the element to be removed:

import array as arr 

#original array
numbers = arr.array('i',[10,20,30,10,20])

#remove the first instance of 10
numbers.pop(0)

print(numbers)

#output

#array('i', [20, 30, 10, 20])

Conclusion

And there you have it - you now know the basics of how to create arrays in Python using the array module. Hopefully you found this guide helpful.

Thanks for reading and happy coding!

#python #programming 

Monty  Boehm

Monty Boehm

1659453850

Twitter.jl: Julia Package to Access Twitter API

Twitter.jl

A Julia package for interacting with the Twitter API.

Twitter.jl is a Julia package to work with the Twitter API v1.1. Currently, only the REST API methods are supported; streaming API endpoints aren't implemented at this time.

All functions have required arguments for those parameters required by Twitter and an options keyword argument to provide a Dict{String, String} of optional parameters Twitter API documentation. Most function calls will return either a Dict or an Array <: TwitterType. Bad requests will return the response code from the API (403, 404, etc).

DataFrame methods are defined for functions returning composite types: Tweets, Places, Lists, and Users.

Authentication

Before one can make use of this package, you must create an application on the Twitter's Developer Platform.

Once your application is approved, you can access your dashboard/portal to grab your authentication credentials from the "Details" tab of the application.

Note that you will also want to ensure that your App has Read / Write OAuth access in order to post tweets. You can find out more about this on Stack Overflow.

Installation

To install this package, enter ] on the REPL to bring up Julia's package manager. Then add the package:

julia> ]
(v1.7) pkg> add Twitter

Tip: Press Ctrl+C to return to the julia> prompt.

Usage

To run Twitter.jl, enter the following command in your Julia REPL

julia> using Twitter

Then the a global variable has to be declared with the twitterauth function. This function holds the consumer_key(API Key), consumer_secret(API Key Secret), oauth_token(Access Token), and oauth_secret(Access Token Secret) respectively.

twitterauth("6nOtpXmf...", # API Key
            "sES5Zlj096S...", # API Key Secret
            "98689850-Hj...", # Access Token
            "UroqCVpWKIt...") # Access Token Secret
  • Ensure you put your credentials in an env file to avoid pushing your secrets to the public 🙀.

Note: This package does not currently support OAuth authentication.

Code examples

See runtests.jl for example function calls.

using Twitter, Test
using JSON, OAuth

# set debugging
ENV["JULIA_DEBUG"]=Twitter

twitterauth(ENV["CONSUMER_KEY"], ENV["CONSUMER_SECRET"], ENV["ACCESS_TOKEN"], ENV["ACCESS_TOKEN_SECRET"])

#get_mentions_timeline
mentions_timeline_default = get_mentions_timeline()
tw = mentions_timeline_default[1]
tw_df = DataFrame(mentions_timeline_default)
@test 0 <= length(mentions_timeline_default) <= 20
@test typeof(mentions_timeline_default) == Vector{Tweets}
@test typeof(tw) == Tweets
@test size(tw_df)[2] == 30

#get_user_timeline
user_timeline_default = get_user_timeline(screen_name = "randyzwitch")
@test typeof(user_timeline_default) == Vector{Tweets}

#get_home_timeline
home_timeline_default = get_home_timeline()
@test typeof(home_timeline_default) == Vector{Tweets}

#get_single_tweet_id
get_tweet_by_id = get_single_tweet_id(id = "434685122671939584")
@test typeof(get_tweet_by_id) == Tweets

#get_search_tweets
duke_tweets = get_search_tweets(q = "#Duke", count = 200)
@test typeof(duke_tweets) <: Dict

#test sending/deleting direct messages
#commenting out because Twitter API changed. Come back to fix
# send_dm = post_direct_messages_send(text = "Testing from Julia, this might disappear later $(time())", screen_name = "randyzwitch")
# get_single_dm = get_direct_messages_show(id = send_dm.id)
# destroy = post_direct_messages_destroy(id = send_dm.id)
# @test typeof(send_dm) == Tweets
# @test typeof(get_single_dm) == Tweets
# @test typeof(destroy) == Tweets

#creating/destroying friendships
add_friend = post_friendships_create(screen_name = "kyrieirving")

unfollow = post_friendships_destroy(screen_name = "kyrieirving")
unfollow_df = DataFrame(unfollow)
@test typeof(add_friend) == Users
@test typeof(unfollow) == Users
@test size(unfollow_df)[2] == 40

# create a cursor for follower ids
follow_cursor_test = get_followers_ids(screen_name = "twitter", count = 10_000)
@test length(follow_cursor_test["ids"]) == 10_000

# create a cursor for friend ids - use barackobama because he follows a lot of accounts!
friend_cursor_test = get_friends_ids(screen_name = "BarackObama", count = 10_000)
@test length(friend_cursor_test["ids"]) == 10_000

# create a test for home timelines
home_t = get_home_timeline(count = 2)
@test length(home_t) > 1

# TEST of cursoring functionality on user timelines
user_t = get_user_timeline(screen_name = "stefanjwojcik", count = 400)
@test length(user_t) == 400
# get the minimum ID of the tweets returned (the earliest)
minid = minimum(x.id for x in user_t);

# now iterate until you hit that tweet: should return 399
# WARNING: current versions of julia cannot use keywords in macros? read here: https://github.com/JuliaLang/julia/pull/29261
# eventually replace since_id = minid
tweets_since = get_user_timeline(screen_name = "stefanjwojcik", count = 400, since_id = 1001808621053898752, include_rts=1)

@test length(tweets_since)>=399

# testing get_mentions_timeline
mentions = get_mentions_timeline(screen_name = "stefanjwojcik", count = 300) 
@test length(mentions) >= 50 #sometimes API doesn't return number requested (twitter API specifies count is the max returned, may be much lower)
@test Tweets<:typeof(mentions[1])

# testing retweets_of_me
my_rts = get_retweets_of_me(count = 300)
@test Tweets<:typeof(my_rts[1])

Want to contribute?

Contributions are welcome! Kindly refer to the contribution guidelines.

Linux: Build Status 

CodeCov: codecov

Author: Randyzwitch
Source Code: https://github.com/randyzwitch/Twitter.jl 
License: View license

#julia #api #twitter 

Carmen  Grimes

Carmen Grimes

1595494844

How to start an electric scooter facility/fleet in a university campus/IT park

Are you leading an organization that has a large campus, e.g., a large university? You are probably thinking of introducing an electric scooter/bicycle fleet on the campus, and why wouldn’t you?

Introducing micro-mobility in your campus with the help of such a fleet would help the people on the campus significantly. People would save money since they don’t need to use a car for a short distance. Your campus will see a drastic reduction in congestion, moreover, its carbon footprint will reduce.

Micro-mobility is relatively new though and you would need help. You would need to select an appropriate fleet of vehicles. The people on your campus would need to find electric scooters or electric bikes for commuting, and you need to provide a solution for this.

To be more specific, you need a short-term electric bike rental app. With such an app, you will be able to easily offer micro-mobility to the people on the campus. We at Devathon have built Autorent exactly for this.

What does Autorent do and how can it help you? How does it enable you to introduce micro-mobility on your campus? We explain these in this article, however, we will touch upon a few basics first.

Micro-mobility: What it is

micro-mobility

You are probably thinking about micro-mobility relatively recently, aren’t you? A few relevant insights about it could help you to better appreciate its importance.

Micro-mobility is a new trend in transportation, and it uses vehicles that are considerably smaller than cars. Electric scooters (e-scooters) and electric bikes (e-bikes) are the most popular forms of micro-mobility, however, there are also e-unicycles and e-skateboards.

You might have already seen e-scooters, which are kick scooters that come with a motor. Thanks to its motor, an e-scooter can achieve a speed of up to 20 km/h. On the other hand, e-bikes are popular in China and Japan, and they come with a motor, and you can reach a speed of 40 km/h.

You obviously can’t use these vehicles for very long commutes, however, what if you need to travel a short distance? Even if you have a reasonable public transport facility in the city, it might not cover the route you need to take. Take the example of a large university campus. Such a campus is often at a considerable distance from the central business district of the city where it’s located. While public transport facilities may serve the central business district, they wouldn’t serve this large campus. Currently, many people drive their cars even for short distances.

As you know, that brings its own set of challenges. Vehicular traffic adds significantly to pollution, moreover, finding a parking spot can be hard in crowded urban districts.

Well, you can reduce your carbon footprint if you use an electric car. However, electric cars are still new, and many countries are still building the necessary infrastructure for them. Your large campus might not have the necessary infrastructure for them either. Presently, electric cars don’t represent a viable option in most geographies.

As a result, you need to buy and maintain a car even if your commute is short. In addition to dealing with parking problems, you need to spend significantly on your car.

All of these factors have combined to make people sit up and think seriously about cars. Many people are now seriously considering whether a car is really the best option even if they have to commute only a short distance.

This is where micro-mobility enters the picture. When you commute a short distance regularly, e-scooters or e-bikes are viable options. You limit your carbon footprints and you cut costs!

Businesses have seen this shift in thinking, and e-scooter companies like Lime and Bird have entered this field in a big way. They let you rent e-scooters by the minute. On the other hand, start-ups like Jump and Lyft have entered the e-bike market.

Think of your campus now! The people there might need to travel short distances within the campus, and e-scooters can really help them.

How micro-mobility can benefit you

benefits-micromobility

What advantages can you get from micro-mobility? Let’s take a deeper look into this question.

Micro-mobility can offer several advantages to the people on your campus, e.g.:

  • Affordability: Shared e-scooters are cheaper than other mass transportation options. Remember that the people on your campus will use them on a shared basis, and they will pay for their short commutes only. Well, depending on your operating model, you might even let them use shared e-scooters or e-bikes for free!
  • Convenience: Users don’t need to worry about finding parking spots for shared e-scooters since these are small. They can easily travel from point A to point B on your campus with the help of these e-scooters.
  • Environmentally sustainable: Shared e-scooters reduce the carbon footprint, moreover, they decongest the roads. Statistics from the pilot programs in cities like Portland and Denver showimpressive gains around this key aspect.
  • Safety: This one’s obvious, isn’t it? When people on your campus use small e-scooters or e-bikes instead of cars, the problem of overspeeding will disappear. you will see fewer accidents.

#android app #autorent #ios app #mobile app development #app like bird #app like bounce #app like lime #autorent #bird scooter business model #bird scooter rental #bird scooter rental cost #bird scooter rental price #clone app like bird #clone app like bounce #clone app like lime #electric rental scooters #electric scooter company #electric scooter rental business #how do you start a moped #how to start a moped #how to start a scooter rental business #how to start an electric company #how to start electric scooterrental business #lime scooter business model #scooter franchise #scooter rental business #scooter rental business for sale #scooter rental business insurance #scooters franchise cost #white label app like bird #white label app like bounce #white label app like lime