Page 1 of 4
How to solve class related code issues possible in VO but not in .Net?
Posted: Mon May 04, 2020 9:46 pm
by ic2
Earlier I wrote that I prefer to prepare my VO code as much as possible for an X# conversion so the actual conversion itself would take less time. I found out that having methods of a class in different libraries is not possible in .Net (while I thought an external class would allow that). See
https://www.xsharp.eu/forum/public-vo-v ... er-library
I figured out all the Error XS9016xxx _external_class errors pointed me to such "orphan" methods and I tried to find a solution for all of them. Some could easily be moved to where the class resided, others where just obsolete, some required a bit of work (passing functionality only present in the current lib as a parameter so it could work from the lib where the class resides). That leaves me with some remaining issues, which surprisingly had to do mostly with the (known and even understandable) impossibility to extend standard classes with methods.
I do have a few categories and I wonder if I can solve this either in VO, in X# or in none. Not sure yet (because I am completely unfamiliar with it) if one or more of the issues below could be solved with the invoke Chris recommended in the above link’s post.
1 In some subclassed datawindows I use a method to set a caption on the tab, which I think is not possibly by default, e.g.
SELF:oDCTabControl:SetTabCaption(0, “Something")
For that I use a method:
METHOD SetTabCaption(nIndex, cCaption) CLASS TabControl
which means I extend the standard TabControl class. I think I can not solve this by subclassing aTabControl (so I can change the class in the above method). The window editor allows me to insert tabcontrols, not subclassed tabcontrols.
Or do I overlook something?
2 Some methods have been added to repair bugs in VO, like methods for the DateTimePicker (which suddenly stopped reading values from VO SP4) or METHOD GetItemAtPosition(oPoint) CLASS MONTHCALENDAR which solved an issue with drag & drop to the month calendar.
In VO I prefer to leave the methods where they are. But what to do in X#? Could the issues be solved in X# , assuming I want to start with all VO compatible windows? Or is there another solution to implement these?
3 Some e.g. class windows methods are used in every window inheriting from it so it does make sense to have it once, as a class windows method. Does this mean I have to copy the code for every inheriting window? A nice example is:
METHOD NoMethod() CLASS window which is called when a non existing method is called (e.g. using owner or send, so the compiler doesn’t see it)
4 I also have a METHOD dispatch(oE) CLASS __FormDialogWindow
which allows me to allow users to press ESCape to end certain windows. Not sure how to do this differently?
All together it’s not to bad, in one relatively large library, so your comments how to solve this best (as much as possible in VO, unless impossible or unpractical) are appreciated.
Dick
How to solve class related code issues possible in VO but not in .Net?
Posted: Mon May 04, 2020 11:29 pm
by Chris
Hi Dick,
1-2. Yes, you can use subclassed controls in the VO Window Editor, same way as you can do it in VO. Just set in the "Inherit from" property the name of the subclass. But maybe you do not even need to do this, if the code in the external method does not use private members of the parent classes, then you can simply define an extension method which does the same work and you will practically need to change nothing in your code. Can you please show us the full body of the methods SetTabCaption() and GetItemAtPosition() ?
3. I think the best way is to define a "CLASS MyBaseWindow INHERIT DataWindow", define this or any other common methods in it and then have all your data windows inherit from that class. Same for DataDialogs and DilogWindows, if you need that for them as well.
4. Maybe we could add this functionality directly in the SDK classes. Can you please show us the contents of this method as well?
How to solve class related code issues possible in VO but not in .Net?
Posted: Tue May 05, 2020 12:14 pm
by ic2
Hello Chris,
Thanks for your reply. Option 3 I already thought so. Not a big deal, I do have subclassed windows. Again of course it shows how wonderful efficient VO is compared to .Net. Adding (and maintaining) just one method to an existing class instead of one for every sibling class.
Now you write about the subclassed tabcontrol that I can do it just as I would do it in VO. But that is exactly my point, I don't know how to do it in VO. I have the toolbox window from which I can insert a default tabcontrol, not an inherited tab control (for how it can be done in X# I make a note but that is going to be of (much) later concern.
I think it's better to mail you all the methods we use and look up why we used these. For now here are 2: this is to set a caption to a tab. I think there is no other way to do so, without the method?
METHOD SetTabCaption(nIndex, cCaption) CLASS TabControl
//#s Set caption of tab in tabwindow
//#p nIndex = index of desired tab 0=1e 1 cCaption=Caption of Tab
LOCAL strucTabItem IS _winTC_ITEM
LOCAL pszCaption AS PSZ
LOCAL lResult AS LOGIC
IF (nIndex != -1)
strucTabItem.Mask := TCIF_TEXT
PSZCaption := StringAlloc(cCaption)
strucTabItem.PSZText := StringAlloc(Psz2String(pszCaption))
lResult := TabCtrl_SetItem(SELF:Handle(), nIndex, @strucTabItem)
// Handle to tab control, Index of item, pointer to TC_ITEM STRUCTURE
IF pszCaption != NULL_PSZ
MemFree(PTR(_CAST, pszCaption))
ENDIF
ENDIF
RETURN lResult
This code, from Paul Piko but modified, will close a window when ESC is pressed, unless a class variable lPreventEsc is set to true in that window. It also deals with the correct return value for HoverButtons and for displaying help in a window.
METHOD dispatch(oE) CLASS __FormDialogWindow
//#s Dispatch for datawindows to arrange Escape for leaving it 12-3-2001
//#s P.Piko
//#x
//#l 2-5-2002: JT: dispatch for context sensitive help
//#l This is one of the windows that makes up a DataWindow
//#l Paul Piko: Escape to leave datawindow
//#l
//#p
//#p
//#r
//#e
//#e
LOCAL aNoCloseWindows:={} AS ARRAY
LOCAL lGaDoor AS LOGIC
lGaDoor:=TRUE // Init: ESC closes datawindow
IF IVarGetInfo(SELF:owner:owner,#lPreventEsc)<>0 // Owner:owner=datawindow calling, we have added lPreventesc (set to true) for EVERY of the windows we don't want to close (it does not work in ic2dw!)
lGaDoor:=!SELF:owner:owner:lPreventEsc // Use value as defined (lPreventEsc = true means lGadoor = false!)
ENDIF
IF oE:message == WM_COMMAND .AND. oE:wParam == IDCANCEL
IF lGaDoor // 24-7-2003: do not react on escape if false
PostMessage(SELF:owner:owner:handle(),WM_CHAR,VK_ESCAPE,0)
SELF:oParent:owner:EndWindow() // GS
RETURN 1L
ELSE
RETURN SUPER:dispatch(oE)
ENDIF
ELSEIF oE:OwnerDraw() == 1L // 27-10-2003 for HoverButton
RETURN 1L
ELSE
IF (oE:message = WM_HELP)
IF ! Empty(SELF:owner:owner:Helpfile)
oprgHelp:DisplayTopic(SELF:owner:owner:Helpfile)
RETURN 0L
ENDIF
ENDIF
ENDIF
RETURN SUPER:dispatch(oE)
Dick
How to solve class related code issues possible in VO but not in .Net?
Posted: Tue May 05, 2020 1:18 pm
by FFF
Dick,
I don't know how to do it in VO. I have the toolbox window from which I can insert a default tabcontrol, not an inherited tab control
You add a module, containing myTab inherit Tabcontrol
In the form editor you add the tc, properties, second tab "general" first entry is "inherit from class" - contains "Auto" - overwrite with myTab.
Look into source:
Code: Select all
CLASS MainDialog INHERIT DIALOGWINDOW
PROTECT oCCOKButton AS PUSHBUTTON
PROTECT oCCCancelButton AS PUSHBUTTON
PROTECT oDCFixedText1 AS FIXEDTEXT
PROTECT oDCTabControl1 AS MYTAB
//{{%UC%}} USER CODE STARTS HERE (do NOT remove this line)
How to solve class related code issues possible in VO but not in .Net?
Posted: Tue May 05, 2020 2:36 pm
by Chris
Hi Dick,
As Karl said, for the inherited TabControl (which probably isn't needed anyway, as we discussed) you need to specify it in the Properties window of the Window Editor.
For the SetTabCaption() method, this indeed does not use any non-public members of the class, it also does not participate in inheritance, so it is very easy to workaround it, as it is stated in the help file topics I pointed you to sometime ago. All you need to do is define an extension class/method:
Code: Select all
CLASS MyExtensions
STATIC METHOD SetTabCaption(SELF oTabControl AS Vulcan.VO.TabControl, nIndex AS INT, cCaption AS STRING) AS LOGIC
//#s Set caption of tab in tabwindow
//#p nIndex = index of desired tab 0=1e 1 cCaption=Caption of Tab
LOCAL strucTabItem IS _winTC_ITEM
LOCAL pszCaption AS PSZ
LOCAL lResult AS LOGIC
IF (nIndex != -1)
strucTabItem.Mask := TCIF_TEXT
PSZCaption := StringAlloc(cCaption)
strucTabItem.PSZText := StringAlloc(Psz2String(pszCaption))
lResult := TabCtrl_SetItem(oTabControl:Handle(), nIndex, @strucTabItem)
// Handle to tab control, Index of item, pointer to TC_ITEM STRUCTURE
IF pszCaption != NULL_PSZ
MemFree(PTR(_CAST, pszCaption))
ENDIF
ENDIF
RETURN lResult
END CLASS
Just add this anywhere in your code, and there is absolutely none other change you will need to make!
Also thanks for posting your __FormDialogWindow:Dispatch(), we will review it and will possibly simply include this code in the SDK directly, so again you will need to chnage nothing and maybe other people can make use of this as well if they want. No promises yet though, we'll have a look and will get back to you.
How to solve class related code issues possible in VO but not in .Net?
Posted: Tue May 05, 2020 3:17 pm
by ic2
Hello Karl,
Ah, of course. I think I subclassed controls so long ago doing exactly what you wrote that I forgot that this is all it takes to move this SetTabCaption method to my subclass. Thanks.
Dick
How to solve class related code issues possible in VO but not in .Net?
Posted: Tue May 05, 2020 4:35 pm
by FFF
Glad to help.
And yes, there are a lot of things, which one did soooo many moons ago, it is often difficult to remember - been there, done that
How to solve class related code issues possible in VO but not in .Net?
Posted: Wed May 06, 2020 3:51 pm
by ic2
Hmmm, I got one more thing. What do I overlook?
1 The AutoSize method was of class ListViewColumn so I created a subclass IC2ListViewColumn and made the autosize of that class:
METHOD AutoSize() CLASS ic2ListViewColumn
// This method will adjust the width of
// the column so that the widest item is
// completely visible(P. Piko)
LOCAL dwIndex AS DWORD
LOCAL n AS DWORD
IF oOwner != NULL_OBJECT
dwIndex := oOwner:__GetColumnIndexFromSymbol(SELF:NameSym) - 1
ListView_SetColumnWidth(oOwner:Handle(), INT(dwIndex), SHORTINT(_CAST,LVSCW_AUTOSIZE))
n := DWORD(ListView_GetColumnWidth(oOwner:Handle(), INT(dwIndex)))
ListView_SetColumnWidth(oOwner:Handle(), INT(dwIndex), SHORTINT(_CAST,LVSCW_AUTOSIZE_USEHEADER))
n := Max(n,ListView_GetColumnWidth(oOwner:Handle(), INT(dwIndex)))
ListView_SetColumnWidth(oOwner:Handle(), INT(dwIndex), SHORTINT(n))
ENDIF
RETURN NIL
2 For the autosize method of the (already subclassed) listview I changed the LOCAL o from ListViewColumn to ic2ListViewColumn, see below.
But I can see that o := SELF:getcolumn(i) returns o of ListViewColumn , not of my subclass. Also creating
METHOD getcolumn(xColumnID) CLASS IC2ListView
RETURN SUPER:getcolumn(xColumnID)
does not change that.
It looks like I can not get this method to work except within the default classs?
When I run it I get a No exported method error when it hits the line o:Autosize. In the debugger I can see that despite having set o to ic2ListViewColumn o is still from class ListViewColumn (from which I removed the AutoSize method)
METHOD autosize CLASS IC2ListView
LOCAL i AS DWORD
LOCAL o AS ic2ListViewColumn
FOR i := 1 TO SELF:columncount
o := SELF:getcolumn(i)
o:AutoSize()
NEXT
RETURN NIL
Dick
How to solve class related code issues possible in VO but not in .Net?
Posted: Wed May 06, 2020 4:10 pm
by Chris
Hi Dick,
The problem most probably is that the ListView control still creates columns of the standard type ListViewColumn, instead of your own. So when you construct the columns, you will need to use your subclass, instead of the default one.
How to solve class related code issues possible in VO but not in .Net?
Posted: Wed May 06, 2020 5:30 pm
by ic2
Hello Chris,
Chris wrote:
I can see that this happens but why? The method at the bottom of my post (see here again) uses the subclass for o, and getcolumn is the subclassed method too. Everything in red is (from) the subclass. What else should I do?
Dick
LOCAL o AS ic2ListViewColumn
FOR i := 1 TO SELF:columncount
o := SELF:getcolumn(i)
o:AutoSize()