In order to improve my understanding of how OOP is used to dynamically generate buttons in a LayoutManagement controlled panel in OA, I reverse engineered the System Management panel and analyzed each line of code, stripping out all lines not relevant for my goal which was to learn the relation between panels and object instances.
Before I modified any of the files, I made a copy of the following panels and renamed them accordingly (note that I deliberately ignored the Breadcrumb part in the System Management panel to simplify things):
- classes/Tile.ctl -> classes/NETile/NETile.ctl
- classes/TileScreen.ctl -> classes/NETile/NETileScreen.ctl
- vision/SystemMgm/sysMgm_iconview_icon.pnl -> vision/NETile/NETile_overview_icon.pnl
- vision/SystemMgm/sysMgm_GridPanel.pnl -> vision/NETile/NETile_GridPanel.pnl
Then I started removing all references to para and the sysMgm library and replaced the information with local variables. Instead of getting the icon and label text from a data point like the original SysMgm panel, I simply modified the NETile.ctl class to also store this information as properties and adjusted the sysMgm_iconview_icon.pnl (now known as NETile_overview_icon.pnl) to get the required information from NETile instead of a DP.
Eventually, I got everything up and running without any use of datapoints. I still had one line of code that kept me from removing the reference to the #SysMgm library, and that was smDbLoadRoot(dps). The weird thing here is that the buttons would not be drawn unless that line of code was included and run as the panel was started. If I commented it out, a call to getShape() in NETile.ctl failed to execute. This is unchanged from Tile.ctl:
Code: Select all
grid = getShape(moduleName + "." + panelName + ":" + layout);
Code: Select all
Line: 178, In "getShape()": Object "NEGridTest_Module.panel:GRID" does not existSince we are using multiple panel objects spread over three different files, this sort of makes sense. The keyword here is synchronization. The panels need to know about each other at some point since dynamically placed buttons needs to be dynamically addressed in a CONTROL++ function that runs outside of the panel. Failure to do causes the getShape() function to fail as it was not properly synchronized to VISION (yet). At this point, the getShape failed to get a reference to an object whose name had been modified in CONTROL during runtime(NEGridTest_Module.panel:GRID which originally was called SysMgmt_Module.panel:GRID). By forcing a 10ms delay however, getShape() was successfully run.
My question in all of this is; what is considered best practice for solving this timing issue with CONTROL? The current solution with delay is ugly and more of a hack than anything else. I am interested in discussing the proper way of addressing this issue. Obviously a mutex of sorts is required. Is there a built-in function in CONTROL for knowing when a dynamically created panelobject is ready for processing (i.e. retrievable by getShape)? Can it be solved using the synchronized keyword on certain classes as discussed in qthelp://wincc_oa/doc/OOP/oop_basics.htm or is there a better way? I feel that using a triggerEvent with a uiConnect to a callback for solving this is a bit excessive..
I have attached my code for those interested. Simply extract the zip file in your project folder, restart GEDI and run NEGridTest.pnl. Note that resizing is not properly handled yet. https://www.winccoa.com/fileadmin/image ... OPTest.zip