How To > Use DotNet > Print Using DotNet |
The following tutorials shows the basics of displaying and printing a text file using DotNet.
We load a custom assembly containing 3ds Max specific controls.
This variable will store the name of the file to print.
We create an object instance of the System.Drawing.Font class with font name Arial and size of 10 and store the object in the user variable for later use.
This user variable will hold the stream reader.
We set the size of the form to 640 x 480 using the System.Drawing.Size object.
We also set the border style of the form to the predefined value FixedToolWindow which is exposed by the System.Windows.Forms.FormBorderStyle class.
Alternatively, we could use the fact that the left-hand-side hForm.FormBorderStyle value is the same class we are assigning from at the right-hand-size, so we could say
We set the title of the form to the string...
...and we make sure the new form does not appear in the Windows Taskbar.
Now we need a textbox to display the content of the file to print.
The textbox will allow multiple lines of text and no word wrapping.
txtTextBox.Size = dotNetObject "System.Drawing.Size" 500 430 txtTextBox.Location = dotNetObject "System.Drawing.Point" 10 10
The textbox will have a size of 500x430 pixels and its upper left corner will be placed at coordinates 10,10 relatively to the upper left corner of the form.
We will allow both horizontal and vertical scrollbars.
btnOpenFile = dotNetObject "System.Windows.Forms.Button" btnOpenFile.Location = dotNetObject "System.Drawing.Point" 520 10 btnOpenFile.Text = "Open File"
We will need a button to open a file to print.
We create a new button object and set its position to coordinates 520,10 inside the form. Its caption will read "Open File".
btnPrint = dotNetObject "System.Windows.Forms.Button" btnPrint.Location = dotNetObject "System.Drawing.Point" 520 40 btnPrint.Text = "Print"
We will need another button to start printing.
We create a new button object and set its position to coordinates 520,40 inside the form. Its caption will read "Print".
frmOpenFileDialog = dotNetObject "System.Windows.Forms.OpenFileDialog" frmOpenFileDialog.Filter = "txt files (*.txt)|*.txt|Script Files (*.ms)|*.ms|ini files (*.ini)|*.ini|XML files (*.xml)|*.xml|All files (*.*)|*.*"
In order to select a file for printing, we will need an OpenFileDialog object set to filter the typical file types.
We will need an even handler function to be called when the Open File button is pressed.
We will be using the OpenFileDialog we pre-defined earlier, so we need a user variable containing the class DialogResult to compare the result of the dialog with the predefined results.
We call the ShowDialog() method of the OpenFileDialog object which displays the dialog and lets the user pick a file. Once it returns, we compare the return value of the dialog with the OK value of the DialogResult class to see if the operation finished successfully (as opposed to being canceled by the user).
IOFile = dotNetClass "System.IO.File" txtTextBox.Text = IOFile.ReadAllText frmOpenFileDialog.Filename
If a valid file was picked, we will use the System.IO.File class to read the file and assign its content to the textbox in the form. We simply call the method ReadAllText in the System.IO.File class and pass the filename returned by the OpenFileDialog as argument. The result from this method gets assigned to the text of the textBox.
At this point, we can store the selected filename in the local variable filetoprint so we can use it when printing the file.
Before we define an even handler function for the Print button, will will need a function to perform the whole printing operation. It gets two arguments - the sender and the event.
We will need a count variable to increment the line count as we process the text.
To calculate the number of lines per page, we have to divide the height of the printed document page between the margins by the height of the printing font.
This variable will be used to calculate and store the vertical position to print at.
We grab the left and top margins into user variables, too.
This variable will hold the current line.
We create a solid brush object with black color.
This variable will contain an object required by the DrawString method later on.
While the counter is less than the number of lines per page, we repeat the following
We read a line from the streamreader - the variable was initialized in the beginning and will be assigned in the event handler of the Print button.
If the currentline variable contains undefined (which means we read past the end of the file), we exit the loop.
We now calculate the vertical position to print at by adding the height of the font multiplier by the current line counter to the top margin.
Finally, we can draw the string of the current line using the current font and brush at horizontal position equal to the left margin, vertical position according to the yPos value calculated in the previous step and format based on the string format object.
We increment the counter by one and the loop repeats unless we have reached the end of the page or the end of the file.
We check to see why the loop exited - if the current line is not undefined, then there are more pages to print and we set the corresponding property of the PrintDocument object to notify it whether it should keep on printing or not.
Note that the same can be written shorter as
Now we can define the event handler of the Print button.
If the file name selected to print is not an empty string, we try to perform the following:
We set the streamReader variable initialized in the beginning of the script to a dotNetObject instance of the class System.IO.Streamreader. It is similar to the fileStream values of MAXScript and provides file IO access to files on disk.
We also create a PrintDocument object which will handle the actual printing.
We add an event handler to the PrintDocument object which will call the MAXScript function we defined previously.
Now we can call the Print() method in the PrintDocument object to start printing. This will call out print event handler function once for each page until the hasMorePages property of the PrintDocument is set to false at which point it will return here.
Once we are back, we close the stream.
If there was any problem within the printing code, we catch the error and print the last exception.
)--end if )--end fn dotNet.AddEventHandler btnOpenFile "Click" btnOpenFile_Click dotNet.AddEventHandler btnPrint "Click" btnPrint_Click
Now we can add the two event handler functions we defined previously to the two buttons.
We can also add the textbox and the two buttons to the form.
Since we are adding scripted event handlers to the DotNet controls and placing those controls in a form whose lifetime is longer than the MAXScript values wrapping the controls, we set the lifetime control of the buttons to be controlled by DotNet
Is there any reason this isn’t the default behavior when creating event handlers?
Yes, the above approach is only applicable to DotNet objects that are placed in other DotNet objects.
An example of when you have an event handler and you do not want the object’s lifetime control to change is a timer object. You want the timer object to be deleted when the MAXScript value wrapping the object is deleted. If you set the timer object’s lifetime control to #dotnet, then at some random point in the future the timer object will be deleted by the DotNet garbage collector since no DotNet object holds a reference to the timer object.