📜 ⬆️ ⬇️

Using Table View

Good day!

For a long time now I have been trying to force myself to learn another language / programming platform for Mac OS X / iOS. It is interested in developing applications with native GUI, since console applications can be developed on anything from C and C ++ to fashionable now Nodejs. As practice has shown, cross-platform frameworks like Qt are not very suitable here, if only because they do not provide the native Look and Feel, which users of this OS are used to.

At Habré there is a sufficient amount of materials on the Objective-C language and the Cocoa framework. From the point of view of the GUI, Cocoa is of interest, and here most of the articles are limited to buttons and text fields. I will try to correct this misunderstanding and describe the work with the Table View on the example of an application that displays a list of processes.
')
The article does not pretend to the completeness of the presentation and the absolute correctness of the material and is aimed primarily at novice developers. Errors and constructive criticism are happy to hear in the comments. Who cares, welcome under cat.


Theory


To develop, we need some knowledge about the Table View. Let's start with them. A detailed description of working with the Table View is given in [1], here I will limit myself to a brief summary of the main ideas.

Table View Types

There are two types of table views:

In this article we will look at working with the cell-based table view , since we only have enough of its functions, the solution will be simpler and will work not only with new versions of OS X.

Data Transfer to Table View

Data in the Table View can be transmitted in two ways:

Cocoa bindings

Cocoa Bindings appeared in Mac OS X, starting with version 10.3. Its main goal is to reduce the amount of controller code for connecting objects of the Model and the View.
Cocoa Bindings is based on two mechanisms:

More details about Cocoa Bindings can be found in [3].

At the end of this theory, you can proceed to practice.

Practice


Open Xcode and create a new project “Cocoa Application”. Let's call it “Process Monitor”. I use the latest Xcode version (4.2.1) at the time of publication, so some steps may differ.

GUI creation

Open the file MainMenu.xib, in it choose Window. Set it to 480 by 500. This is done in the Size Inspector (the ruler icon in the right sidebar). In the same place we will establish the minimum sizes - the checkbox and the necessary sizes.

Add the Table View element from the Object Library to the window (the cube icon in the lower right sidebar) (search for the word “table”). By default, a cell-based table is created. You can verify this by opening Attributes Inspector (in the right sidebar, to the left of the ruler). Resize the Table View so that it takes up the entire window. Then open the Size inspector and select all elements in the Autosizing picture - this is necessary so that the Table View stretches along with the window.

Now we need to add columns to the table. We will display three columns - the PID of the process, the icon and the name of the process. By default, two columns are added to the table. It is necessary to change this number to 3. To do this, select the table (Table View) by clicking in the window. Here you need to make a small digression. The fact is that window objects are nested inside each other and it is not easy to select the one you need. There are two options: this is either the choice of the desired element in the hierarchy of objects in the Objects window (I think it appeared in Xcode 4, I have not seen it before), or Command + Control + Shift Click on the window with the choice of the desired object. After selecting the table, go to Attributes Inspector and set the value of Columns to 3.

Now assign the names to the columns. This is done by double clicking on the column header. The name of the first column is PID, the second is left blank, the third is the Process Name.

Resize the columns of the table. To do this, select the column and in Size Inspector set its size. For the first (PID): 60, for the second (Icon): 40, for the third (Process Name) - all the remaining space.

Replace the type of the second column of the table from text to image. To do this, find the Image Cell in the Object Library (search by “image”) and drag it to the second column.

After all these actions, you can click the Run button and see this window:


Adding Controller and Binding

Now add a controller that will interact with the table. The most suitable type of controller for the table is NSArrayController. Find it in the Object Library (search by “array”) and drag it to the Objects list.

We set the bindings for the table. To do this, select the Table View and go to the Bindings Inspector (the penultimate tab in the right sidebar). There, in the Table Content section, select Content and install Bind to: Array Controller with the Controller Key: arrangedObjects.

Now we will use the KVC technique and indicate what data each column should display. To do this, we in turn select each column (Table Column) and in the Bindings Inspector set the Value to Bind to: Array Controller with the Controller Key: arrangedObjects. And for each column, the Model Key Path values ​​are respectively: processIdentifier, icon, localizedName. Why such values ​​are set will be described below.

So we linked the table with the controller. It remains to associate the controller with the data.

First of all, we define these same data. Open the file AppDelegate.h and define the contents property of type NSArray:
@property (retain) NSArray* contents; 

In the file AppDelegate.m we write:
 @synthesize contents; 

Now back to MainMenu.xib and tell the controller what data to use. Go to the Bindings Inspector and in the Controller Content section, set the Content Array to Bind to: App Delegate, and Model Key Path: contents.
This completes the installation of the bindings, we just need to fill in the array of contents in AppDelegate with the necessary data.

Getting a list of running processes

There are several ways to get a list of all running processes. I will write about this somehow in a separate article. Now consider the simplest and most obvious way - using Cocoa. It does not receive a complete list of processes, but let us not care about it yet.
Define the updateProcessList method in AppDelegate:
 - (void)updateProcessList { NSWorkspace* workspace = [NSWorkspace sharedWorkspace]; self.contents = [NSArray arrayWithArray:[workspace runningApplications]]; } 

Let's make this method first in the class so that it can be called from other methods without defining it in the header file.
A little comment on the code. In the first line we get an object of class NSWorkspace . The object of this class exists in the program in a single copy, a kind of singleton, and is obtained by the method of sharedWorkspace .
This object has a runningApplications method that returns a list of running applications in an array. It's simple. And we use this array as data for the controller.

Each element of this array is an object of class NSRunningApplication . This class has several properties, among which is processIdentifier , icon , localizedName . Remember we set them for table columns? So, thanks to KVC, these values ​​from NSRunningApplication will be used when the table is displayed .

Now add a call to the created method during the application launch. To do this, add the line:
 [self updateProcessList]; 

to the applicationDidFinishLaunching method.

Application Completion

In Mac OS X, it is accepted that the application does not have to terminate after the last window is closed. In our example, this makes little sense, so we’ll add an automatic completion. This is done very simply - by adding one method to AppDelegate.m:
 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender { return YES; } 

Conclusion


Now our application is ready. If everything is done correctly, then after launch you can see something like this:

As an exercise, I suggest the reader to implement a periodic update of the list of processes. To do this, you can use the NSTimer class and the scheduledTimerWithTimeInterval method of this class [5].

So, in this article we covered the process of creating a simple application using the Table View. Most of the work was done in Interface Builder and did not require programming at all. Everything that could be simplified was simplified - window controllers ( NSWindowController ), view controllers ( NSViewController ), memory management, and much more were not considered.

In the next article, I plan to review a hierarchical list ( NSOutlineView ) to display the process tree. And, if the code there is enough, I will make a repository on github'e.

Thank you all for your attention!

Links


  1. Table View Programming Guide (en)
  2. Model – view – controller pattern (en)
  3. Cocoa Bindings Job (ru)
  4. NSWorkspace Class Reference (en)
  5. NSTask Class Reference (en)


Upd. Gained karma and transferred to Mac OS X.

Source: https://habr.com/ru/post/136265/


All Articles