Announcement

Collapse
No announcement yet.

Proof of Concept Windows Controls With OOP

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • jcfuller
    replied
    Fred,
    I have to disagree. You may be looking at this more as a C++ programmer which I also did at first. I am now looking at it for what it is: COM with PB implementation inheritance.

    I tried the PBFC approach but now see it may not be the way to go.

    Example. Base Class: cControl with all the basics (left,top,width.....). Next specific controls inheriting from cControl.List box has list, sort others...
    Problem#1: not really a problem but code ugliness All references within Lbox to cControl need the Me. or MyBase. prefixes.
    Problem#2: No Base class auto configuration. There is only one CLASS METHOD CREATE which is in the highest level derived class and this one cannot access "base class(es)" Instance variables. This is the main reason I did not got this route. I want default configurations so I don't have to manually call functions, sendmessages, every time I create a control.
    Taking this to the height of laziness I wrapped the new DISPLAY OPENFILE so I don't have to set anything.
    Just call the Objects GetFile Method and it defaults to *.* in the current directory.

    At present I have one main cControl class. If I need specialization I use containment and create a specialized class within the cControl class and use compound objects to access. I do this with the RAGrid in my example. I also have all color,font,lists (for list box and combo box) built in. It keeps my callback cleaner. Speaking of which I love the CB.'s and probably will continue using a hybrid approach for the near future.

    The server at present is under 60k but that includes RAGrid (not complete), and the complete pcre wrapper I posted in source before.

    This is not meant to hijack just enlighten.

    James

    Leave a comment:


  • StanHelton
    replied
    Originally posted by Kev Peel View Post
    ...
    Note: I must add I don't want to go down the 'open source' route, since 90% of the library code is also used in my commercial products and took years to amass.
    I certainly understand. I feel the same way about some of the apps I've written.

    OTOH, if you have a 'free to use' library in mind, perhaps it would be worthwhile to give a vb2pb user the option of being able to use it without actually sharing the code. We could give the end-user the option of calling the library or using generically generated code. The nag screen would say something like "Kev Peel's Excellent OCX Library found. Do you want to generate code to use this library?" %MB_YESNOCANCEL.

    We have discussed ways to encourage the use of PB. Availability of compatible tools by PB programmers is a big plus. After all, part of the original vb2pb concept is to promote the work of PB Programmers.

    Leave a comment:


  • John Strasser
    replied
    Originally posted by Fred Harris View Post
    I'm beginning to believe that the merit of OOP is in designing classes around the objects for which an application is being built and leaving the actual Windows plumbing alone.
    Fwiw, when doing stuff in the C++ and Delphi worlds I've always found that to be the case. And a heckuva lot more efficient too.

    Think about it - we've got DDT and all the other excellent 3rd party IDEs that make it easier to handle the plumbing. Why reinvent the wheel?

    JS

    Leave a comment:


  • Kev Peel
    replied
    We're ALWAYS listening! Any chance you have a contribution in mind?
    Well I am seriously considering building a Window objects library OCX for free unlimited use. I've got so much code in libraries, hundreds of thousands of lines in fact, it would be nice to share it all by creating a series of object libraries, usable by PB (and other languages). No timeframe of course, but that's the general goal

    Note: I must add I don't want to go down the 'open source' route, since 90% of the library code is also used in my commercial products and took years to amass.

    Leave a comment:


  • Fred Harris
    replied
    The End.

    Well, here's what I added to it and am talking about. I'm glad I finally did this and actually got to see how it works through. There is certainly no magic (other than what Mr. Zale does or how he does it with the compiler). It really does just add another layer that sits in between a direct function call and getting the control created. That would be most readily apparent if you would enter my "Control" class and just make a CreateWindow() Method, and simply put all the parameters from the basic Api CreateWindowEx() call in the CreateWindow() Method in the class, instead of having all those repetitous Property Get/Set Methods for setting each parameter like I have.

    Nonetheless, perhaps there is some value to the approach in terms of the more complicated interfacing with a control in terms of SendMessage() calls and so on and so forth. These could be easily wrapped. But then so can they in regular procedural calls.

    Personally, this may be as far as I want to take this. I most definitely am not interested in something like MFC where an entire app is wrapped within a class. I believe I'm going to stick with the basic Sdk style with my message cracker and routing routines as you see here. I'm beginning to believe that the merit of OOP is in designing classes around the objects for which an application is being built and leaving the actual Windows plumbing alone.

    Code:
    #Compile      Exe
    #Include      "Win32api.inc"
    %IDC_TEXT1    = 1201
    %IDC_BUTTON1  = 1301
    
    Type WndEventArgs
      wParam As Long
      lParam As Long
      hWnd   As Dword
      hInst  As Dword
    End Type
    
    
    Type MessageHandler
      wMessage As Long
      dwFnPtr As Dword
    End Type
    
    
    Class CControl
      Instance ExStyle              As Dword
      Instance ClassName            As String
      Instance WinStyle             As Dword
      Instance x                    As Long
      Instance y                    As Long
      Instance Breadth              As Dword
      Instance Height               As Dword
      Instance hCtrl                As Dword
      Instance hParent              As Dword
      Instance hInstance            As Dword
      Instance WindowCreationData   As Dword Ptr
      Instance ControlID            As Long
    
      Interface IControl : Inherit IUnknown
        Property Get ExStyle() As Dword               'Extended Style For CreateWindowEx()
          Property=ExStyle
        End Property
        Property Set ExStyle(Byval dwExStyle As Dword)
          ExStyle=dwExStyle
        End Property
    
        Property Get ClassName() As String            'Class Name, i.e., edit, button, etc.
          Property=ClassName
        End Property
        Property Set ClassName(Byval strClassName As String)
          ClassName=strClassName
        End Property
    
        Property Get Text() As String                 'Caption; Text Property of Edit Control
          Local pszStr As Asciiz Ptr
          Local iLen As Long
          iLen=GetWindowTextLength(hCtrl)
          Incr iLen
          pszStr=GlobalAlloc(%GPTR,iLen)
          Call GetWindowText(hCtrl,ByVal pszStr,iLen)
          [email protected]
          Call GlobalFree(pszStr)
        End Property
        Property Set Text(Byval strText As String)
          Call SetWindowText(hCtrl,Byval Strptr(strText))
        End Property
    
        Property Get WinStyle() As Dword              'Normal Window Style
          Property=WinStyle
        End Property
        Property Set WinStyle(Byval dwWinStyle As Dword)
          WinStyle=dwWinStyle
        End Property
    
        Property Get x() As Long                      'x position of control
          Property=x
        End Property
        Property Set x(Byval xCoord As Long)
          x=xCoord
        End Property
    
        Property Get y() As Long                      'y position of control
          Property=y
        End Property
        Property Set y(Byval yCoord As Long)
          y=yCoord
        End Property
    
        Property Get Breadth() As Dword               'Width of control
          Property=Breadth
        End Property
        Property Set Breadth(Byval dwWidth As Dword)
          Breadth=dwWidth
        End Property
    
        Property Get Height() As Dword                'Height of control
          Property=Height
        End Property
        Property Set Height(Byval dwHeight As Dword)
          Height=dwHeight
        End Property
    
        Property Get hParent() As Dword               'Parent window of control
          Property=hParent
        End Property
        Property Set hParent(Byval hParentWindow As Dword)
          hParent=hParentWindow
        End Property
    
        Property Get ControlID() As Long              'Control ID
          Property=ControlID
        End Property
        Property Set ControlID(Byval iCtrlID As Long)
          ControlID=iCtrlID
        End Property
    
        Property Get WindowCreationData() As Dword    'Pointer goes here for custom controls, etc.
          Property=WindowCreationData
        End Property
        Property Set WindowCreationData(Byval dwPtr As Dword Ptr)
          WindowCreationData=dwPtr
        End Property
    
        Method CreateWindow() As Dword                'Big create window call
          hCtrl= _
          CreateWindowEx _
          ( _
            ExStyle, _
            Byval Strptr(ClassName), _
            "", _
            WinStyle, _
            x, _
            y, _
            Breadth, _
            Height, _
            hParent, _
            ControlID, _
            GetModuleHandle(Byval %NULL), _
            Byval WindowCreationData _
          )
          Method=hCtrl
        End Method
      End Interface
    End Class
    
    
    Declare Function FnPtr(wea As WndEventArgs) As Long
    Global MsgHdlr()  As MessageHandler
    Global txtTextBox As IControl
    Global cmdButton  As IControl
    
    
    Function fnWndProc_OnCreate(wea As WndEventArgs) As Long
      'Setup Wrapped Edit Control
      txtTextBox=Class "CControl"
      txtTextBox.ClassName="edit"
      txtTextBox.x=55                        : txtTextBox.y=40
      txtTextBox.Breadth=210                 : txtTextBox.Height=25
      txtTextBox.ExStyle=%WS_EX_CLIENTEDGE   : txtTextBox.WinStyle=%WS_CHILD Or %WS_VISIBLE Or %WS_BORDER
      txtTextBox.ControlID=%IDC_TEXT1        : txtTextBox.hParent=wea.hWnd
      txtTextBox.WindowCreationData=%NULL
      txtTextBox.CreateWindow()
      txtTextBox.Text="Compile Without Compromise!"
    
      'Setup Wrapped Button Control
      cmdButton=Class "CControl"
      cmdButton.ClassName="button"
      cmdButton.x=118                        : cmdButton.y=100
      cmdButton.Breadth=80                   : cmdButton.Height=25
      cmdButton.ExStyle=0                    : cmdButton.WinStyle=%WS_CHILD Or %WS_VISIBLE
      cmdButton.ControlID=%IDC_BUTTON1       : cmdButton.hParent=wea.hWnd
      cmdButton.WindowCreationData=%NULL
      cmdButton.CreateWindow()
      cmdButton.Text="Click Me!"
    
      fnWndProc_OnCreate=0
    End Function
    
    
    Function fnWndProc_OnCommand(wea As WndEventArgs) As Long
      If Lowrd(wea.wParam)=%IDC_BUTTON1 And Hiwrd(wea.wParam)=%BN_CLICKED Then
         MsgBox(txtTextBox.Text)
      End If
    
      fnWndProc_OnCommand=0
    End Function
    
    
    Function fnWndProc_OnClose(wea As WndEventArgs) As Long
      Call PostQuitMessage(0)
      fnWndProc_OnClose=0
    End Function
    
    
    Function fnWndProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
      Local wea As WndEventArgs
      Register iReturn As Long
      Register i As Long
    
      For i=0 To 2
        If wMsg=MsgHdlr(i).wMessage Then
           wea.hWnd=hWnd: wea.wParam=wParam: wea.lParam=lParam
           Call Dword MsgHdlr(i).dwFnPtr Using FnPtr(wea) To iReturn
           fnWndProc=iReturn
           Exit Function
        End If
      Next i
    
      fnWndProc=DefWindowProc(hWnd,wMsg,wParam,lParam)
    End Function
    
    
    Sub AttachMessageHandlers()
      ReDim MsgHdlr(2) As MessageHandler  'Associate Windows Message With Message Handlers
      MsgHdlr(0).wMessage=%WM_CREATE   :   MsgHdlr(0).dwFnPtr=CodePtr(fnWndProc_OnCreate)
      MsgHdlr(1).wMessage=%WM_COMMAND  :   MsgHdlr(1).dwFnPtr=CodePtr(fnWndProc_OnCommand)
      MsgHdlr(2).wMessage=%WM_CLOSE    :   MsgHdlr(2).dwFnPtr=CodePtr(fnWndProc_OnClose)
    End Sub
    
    
    Function WinMain(ByVal hIns As Long,ByVal hPrev As Long,ByVal lpCL As Asciiz Ptr,ByVal iShow As Long) As Long
      Local hWnd As Dword
      Local winclass As WndClassEx
      Local szAppName As Asciiz * 16
      Local Msg As tagMsg
    
      szAppName="Api Classes"                                : Call AttachMessageHandlers()
      winclass.lpszClassName=VarPtr(szAppName)               : winclass.lpfnWndProc=CodePtr(fnWndProc)
      winclass.cbSize=SizeOf(winclass)                       : winclass.style=%CS_HREDRAW Or %CS_VREDRAW
      winclass.cbClsExtra=0                                  : winclass.cbWndExtra=0
      winclass.hInstance=hIns                                : winclass.hIcon=LoadIcon(%NULL, ByVal %IDI_APPLICATION)
      winclass.hCursor=LoadCursor(%NULL, ByVal %IDC_ARROW)   : winclass.hbrBackground=%COLOR_BTNFACE+1
      winclass.lpszMenuName=%NULL
      RegisterClassEx winclass
      hWnd=CreateWindow(szAppName,"Control Objects",%WS_OVERLAPPEDWINDOW,200,100,325,200,0,0,hIns,ByVal 0)
      Call ShowWindow(hWnd,iShow)
      While GetMessage(Msg,%NULL,0,0)
        TranslateMessage Msg
        DispatchMessage Msg
      Wend
    
      Function=msg.wParam
    End Function
    And the globals don't thrill me either.
    Last edited by Fred Harris; 21 Aug 2008, 09:35 PM. Reason: Why have dumb static in WndProc()?

    Leave a comment:


  • StanHelton
    replied
    Originally posted by Kev Peel View Post
    ...
    Heck, I might even create a library myself (I use procedural-style libraries at the moment)

    Anyone from the VB2PB project listening?

    We're ALWAYS listening! Any chance you have a contribution in mind?

    Stan

    Leave a comment:


  • Edwin Knoppert
    replied
    True

    Leave a comment:


  • Fred Harris
    replied
    I'm a little slow sometimes and have to actually see the code. Can't always think everything through to the end. I just added some to the code above and it just amonnts to piles of Get/Set property procedures instead of the very concise CreateWindowEx() call for each control. It certainly works though.

    The conclusion I'm coming too though is that the editors with code completion features that display all the Methods/Properties of an object when you hit the '.' have a lot to do with the popularity of OOP. That is certainly a seperate feature of an editor and not a feature of OOP, but there certainly has been a supportive role played by this editor technology in terms of the ascendence of OOP over these past 10 years. A comment Jose made to me sometime ago is certainly true, and that is that if you take away their code editors, some of these .NET programmers can't hardly write code.

    Leave a comment:


  • jcfuller
    replied
    I just updated my Wrapper. It's now a server.

    http://www.powerbasic.com/support/pb...ad.php?t=38317

    James

    Leave a comment:


  • Edwin Knoppert
    replied
    I ever tried that and what frustrated me was a chicken and egg situation.
    A windowclass is a class by itself and is created on demand.
    Addtional oop stuff my need to set things after a control is created or before.
    When will what be done..?

    By itself a windowclass is fine though it lacks additional commands in oop style.
    Like Form1.Text1.Text = "Hello"

    It is possible to create an object reference right when the window is created and delete the reference when the window is getting destroyed.
    But then.. when to set the multiline style for an edit class?

    Leave a comment:


  • Rodney Hicks
    replied
    Anyone from the VB2PB project listening?
    Are you asking in a roundabout way if you can help us out?

    Leave a comment:


  • Kev Peel
    replied
    Creating a "window object engine" is a great idea to help people with the transition from VB. I estimate that a full blown engine with MDI support would probably be in the 200-250kb range. Specific control implementations would be more though. Heck, I might even create a library myself (I use procedural-style libraries at the moment)

    Anyone from the VB2PB project listening?

    Leave a comment:


  • Edwin Knoppert
    replied
    Imo it's *very* easy to make a OOP style for window and control creation.
    But imo the ordinary way of coding will most likely result in smaller app's.

    A full blown object will always be present, normally you'll bring the few parts you need.

    When PB would introduce optimized static linking, then it may be interesting.
    Unless you want to create another 'VB' runtime?

    Borland uses inheritance, you may want to skip that and progam self-contained objects for each control type.
    This would keep the size low.

    Leave a comment:


  • Fred Harris
    started a topic Proof of Concept Windows Controls With OOP

    Proof of Concept Windows Controls With OOP

    Just put this together in an hour or so but it at least flushes out for me some of the issues concerning this idea I have had for some time, and that is wrapping some Sdk style control creation/interface elements in OOP machinery. I had intended trying it in C++ but now with this really awesome PowerBASIC compiler I tried it first with it. It seems to work as far as that goes. The idea is as follows. With Visual Basic it was really easy to interface with controls on a Form/Dialog. Everything was wrapped in OOP syntax. Also, controls were an application global resource. If you had a textbox on a Form named txtTextBox, it could be addressed from anywhere in the project. If you wanted to put text in it all you had to do was this...

    txtTextBox.Text = "Some Text In A Textbox"

    Certainly easier than...

    Local szBuffer As Asciiz*128
    szBuffer="Some Text In A Text Box"
    Call SetWindowText(hTextBox,szBuffer)

    Well, here is a very rough sketch of what it would look like in PowerBASIC OOP.

    Code:
    'For PowerBASIC Windows 9.0
    #Compile     Exe
    #Include     "Win32api.inc"
    %IDC_TEXT1   =1200
    
    Class CEdit
      Instance dwExStyle As Dword
      Instance dwStyle   As Dword
      Instance x         As Long
      Instance y         As Long
      Instance dwWidth   As Dword
      Instance dwHeight  As Dword
      Instance hEdit     As Dword
      Instance hParent   As Dword
      Instance hInstance As Dword
      Instance dwPtr     As Dword Ptr
      Instance Equate    As Long
    
      Interface IEdit : Inherit IUnknown
        Property Set Text(Byval strText As String)
          Local szBuffer As Asciiz*128
          szBuffer=strText
          Call SetWindowText(hEdit,szBuffer)
        End Property
      
        Method CreateWindow(hMain As Dword, iEquate As Dword, hIns As Dword) As Dword
          dwExStyle=0
          dwStyle=%WS_CHILD Or %WS_VISIBLE Or %WS_BORDER
          x=55            :  y=40
          dwWidth=210     :  dwHeight=25
          hParent=hMain   :  Equate=iEquate
          hInstance=hIns  :  dwPtr=0
          hEdit=CreateWindowEx(dwExStyle,"edit","",dwStyle,x,y,dwWidth,dwHeight,hMain,iEquate,hInstance,Byval dwPtr)
          Method=hEdit
        End Method
        
        Method GetWindowHandle(hParent As Dword, iEquate As Dword) As Dword
          Method=GetDlgItem(hParent,iEquate)
        End Method
      End Interface
    End Class
    
                          
    Type WndEventArgs
      wParam As Long
      lParam As Long
      hWnd   As Dword
      hInst  As Dword
    End Type
    
    Declare Function FnPtr(wea As WndEventArgs) As Long
    
    Type MessageHandler
      wMessage As Long
      dwFnPtr As Dword
    End Type
    Global MsgHdlr() As MessageHandler
    Global txtTextBox As IEdit
    
     
    Function fnWndProc_OnCreate(wea As WndEventArgs) As Long
      Local pCreateStruct As CREATESTRUCT Ptr
      Local hEdit As Dword
      
      pCreateStruct=wea.lParam
      [email protected]
      txtTextBox=Class "CEdit"
      hEdit=txtTextBox.CreateWindow(wea.hWnd,%IDC_TEXT1,wea.hInst)
      txtTextBox.Text="Compile Without Compromise!"
      
      fnWndProc_OnCreate=0
    End Function
    
    
    Function fnWndProc_OnNotify(wea As WndEventArgs) As Long
      fnWndProc_OnNotify=0
    End Function
    
    
    Function fnWndProc_OnClose(wea As WndEventArgs) As Long
      Call PostQuitMessage(0)
      fnWndProc_OnClose=0
    End Function
    
    
    Function fnWndProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
      Static wea As WndEventArgs
      Register iReturn As Long
      Register i As Long
    
      For i=0 To 2
        If wMsg=MsgHdlr(i).wMessage Then
           wea.hWnd=hWnd: wea.wParam=wParam: wea.lParam=lParam
           Call Dword MsgHdlr(i).dwFnPtr Using FnPtr(wea) To iReturn
           fnWndProc=iReturn
           Exit Function
        End If
      Next i
    
      fnWndProc=DefWindowProc(hWnd,wMsg,wParam,lParam)
    End Function
    
    
    Sub AttachMessageHandlers()
      ReDim MsgHdlr(2) As MessageHandler  'Associate Windows Message With Message Handlers
      MsgHdlr(0).wMessage=%WM_CREATE   :   MsgHdlr(0).dwFnPtr=CodePtr(fnWndProc_OnCreate)
      MsgHdlr(1).wMessage=%WM_NOTIFY   :   MsgHdlr(1).dwFnPtr=CodePtr(fnWndProc_OnNotify)
      MsgHdlr(2).wMessage=%WM_CLOSE    :   MsgHdlr(2).dwFnPtr=CodePtr(fnWndProc_OnClose)
    End Sub
    
    
    Function WinMain(ByVal hIns As Long,ByVal hPrev As Long,ByVal lpCL As Asciiz Ptr,ByVal iShow As Long) As Long
      Local hWnd As Dword
      Local winclass As WndClassEx
      Local szAppName As Asciiz * 16
      Local Msg As tagMsg
    
      szAppName="Api Classes"
      Call AttachMessageHandlers()
      winclass.cbSize=SizeOf(winclass)
      winclass.style=%CS_HREDRAW Or %CS_VREDRAW
      winclass.lpfnWndProc=CodePtr(fnWndProc)
      winclass.cbClsExtra=0
      winclass.cbWndExtra=0
      winclass.hInstance=hIns
      winclass.hIcon=LoadIcon(%NULL, ByVal %IDI_APPLICATION)
      winclass.hCursor=LoadCursor(%NULL, ByVal %IDC_ARROW)
      winclass.hbrBackground=%COLOR_BTNFACE+1
      winclass.lpszMenuName=%NULL
      winclass.lpszClassName=VarPtr(szAppName)
      RegisterClassEx winclass
      hWnd=CreateWindow(szAppName,"Edit Class",%WS_OVERLAPPEDWINDOW,200,100,325,200,0,0,hIns,ByVal 0)
      Call ShowWindow(hWnd,iShow)
      While GetMessage(Msg,%NULL,0,0)
        TranslateMessage Msg
        DispatchMessage Msg
      Wend
    
      Function=msg.wParam
    End Function
    I hate the global though. However, that is the only way to so easily do it as in VB. I'll not have globals in my programs so I have to give that some thought. Properties or cbWndExtra bytes in one way or another should work.
Working...
X