ETABs Plugin - Part 2
Having nailed down the initial steps of creating a plugin, I set out to do some real functional work with the plugin. Being naive, I went off the deep end to begin programming the diaphragm slicer, but was quickly met by a sea of syntax and foreign looking code that was difficult to navigate. I had to go back to what all good programmers do, watching youtube videos.
The Code
The example plugin above will gather all of the load combinations in your ETABs project, populate them in a "datagrid view" and combobox and will report the joint reaction forces at a specific node under the selected load combination. I followed this youtube video, thank you Structure Detailing, the video was very informative and helpful!
The code to make this plugin has been upload on github.
New Syntax
From the video, the syntax of {get; set;} in a C# class appeared multiple times.
public class JointReaction { public string Name { get; set; } public string LoadCase { get; set; } public double F1 { get; set; } public double F2 { get; set; } public double F3 { get; set; } public double M1 { get; set; } public double M2 { get; set; } public double M3 { get; set; } }
This notation appears related to "encapsulation" in C# and allows this class to be both private (hidden from other classes and other parts of the program) and public. The JointReaction class is then instantiated in the main Form1.cs code.
React.Name = Name; JReact.LoadCase = LoadCase[0]; JReact.F1 = F1[0]; JReact.F2 = F2[0]; JReact.F3 = F3[0]; JReact.M1 = M1[0]; JReact.M2 = M2[0]; JReact.M3 = M3[0];
Calling the .F1 attribute on the class JReact somehow triggers the {get; set;} notation. I have to dig into more C# to fully understand this {get; set;} notation.
ETABs API - Unclear Returns
API calls to ETABs are foreign to me, how can there be no explicit return?
Take for example the following code:
string Name = ""; eItemTypeElm ItemTypeElm; int NumberResults = 1; string[] Obj = null; string[] Elm = null; string[] LoadCase = null; string[] StepType = null; double[] StepNum = null; double[] F1 = null; double[] F2 = null; double[] F3 = null; double[] M1 = null; double[] M2 = null; double[] M3 = null; int x = -1; _SapModel.Results.Setup.DeselectAllCasesAndCombosForOutput(); //Method below acts on a string _SapModel.Results.Setup.SetComboSelectedForOutput(LoadCombinationComBox.SelectedItem.ToString()); //unsure why eItemTypeElm.Element does not need to be initiated //anything that is ref is returned, not input x = _SapModel.Results.JointReact("4", eItemTypeElm.Element, ref NumberResults, ref Obj, ref Elm, ref LoadCase, ref StepType, ref StepNum, ref F1, ref F2, ref F3, ref M1, ref M2, ref M3);
The confusing part of this code is that the output of _SapModel.Results.Joint(...), x, is merely an integer, 1. I have no idea how this method writes/returns the values of the results to F1, F2, F3... Anytime I have written methods, I have direct return statement and it would typically be written directly to the output variable, x. If you know what the syntax might look like in C# to make this complicated output, please let me know, I would be interested in learning how to return multiple data types, lists, and values.
FYI, the code above will output the joint reaction forces for the unique node "4" in the ETABs model. These are the values that are populated in the initial video.
DataGridViews - A Ray of Hope for Programming
Data grid views have to be the best thing I have discovered in C#. Coming from python and the miserable experience that was PyQt5 to make a GUI, this is a miracle. The code to make tables is very clean and concise. If I never have to write PyQt5 code again, I will be happy. Side note, I have been meaning to make a post on PyQt5 GUIs with ETABs, another post for a later time. A sample of the mess that is PyQt5:
class TableModel(QtCore.QAbstractTableModel): def __init__(self, data): super(TableModel, self).__init__() self._data = data self._headers = ['Frame Size', 'Cnx Type', 'Demand (kip)', 'Capacity (kip)', 'ETABs Frame #'] def data(self, index, role): if role == QtCore.Qt.DisplayRole: # See below for the nested-list data structure. # .row() indexes into the outer list, # .column() indexes into the sub-list return self._data[index.row()][index.column()] if self._data[index.row()][index.column()] == 'SS/DS cnx NG' and role == QtCore.Qt.BackgroundRole : return QBrush(Qt.red) if self._data[index.row()][index.column()] == 'No Values' and role == QtCore.Qt.BackgroundRole : return QtGui.QColor('#FFA500') if self._data[index.row()][index.column()] == 'DS cnx Ok' and role == QtCore.Qt.BackgroundRole : return QBrush(Qt.yellow) def rowCount(self, index): # The length of the outer list. return len(self._data)
Now that I have learned the basics of the plugin and the ETABs API, I think I should be able to struggle through my first bit of custom coding.