FreeBasic question

Started by José Roca, August 20, 2015, 07:21:56 PM

Previous topic - Next topic

José Roca

I have installed manually the 32-bit compiler (I had problems with the installer) and my tests work fine without changes.

Unless I'm missing something, there is no need for an ansi version of CWindow.

José Roca

#16
@Paul,

Another possibility is to create a class for each control.

For example:


' ########################################################################################
' Microsoft Windows
' File: CButton.inc
' Contents: Button Control Wrapper Class
' Copyright (c) 2015 Jose Roca
' Compiler: FreeBasic 64-bit, Unicode.
' All Rights Reserved.
' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
' EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
' MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ########################################################################################

#pragma once

#include once "windows.bi"
#include once "Afx/CWindow.inc"
#include once "win/commctrl.bi"

USING Afx.CWindowClass

NAMESPACE Afx.CButtonClass

' ========================================================================================
' CButton class
' ========================================================================================
TYPE CButton

   Private:
      m_pWindow AS CWindow PTR                        ' // CWindow pointer
      m_hCtl AS HWND                                  ' // Button handle

   Public:
      DECLARE CONSTRUCTOR (BYVAL pWindow AS CWindow PTR)
      DECLARE DESTRUCTOR
      DECLARE FUNCTION Create (BYVAL cID AS INTEGER, BYREF wszTitle AS WSTRING = "", _
              BYVAL x AS LONG = 0, BYVAL y AS LONG = 0, BYVAL nWidth AS LONG = 0, BYVAL nHeight AS LONG = 0, _
              BYVAL dwStyle AS DWORD = 0, BYVAL dwExStyle AS DWORD = 0, BYVAL lpParam AS LONG_PTR = 0, BYVAL pWndProc AS WNDPROC = NULL) AS HWND
      DECLARE SUB Click ()
      DECLARE FUNCTION Enable () AS LONG
      DECLARE FUNCTION Disable () AS LONG
      DECLARE FUNCTION GetCheck () AS LONG

END TYPE
' ========================================================================================

' ========================================================================================
' CWindow class constructor
' ========================================================================================
CONSTRUCTOR CButton (BYVAL pWindow AS CWindow PTR)
   m_pWindow = pWindow
END CONSTRUCTOR
' ========================================================================================

' ========================================================================================
' CButton class destructor
' ========================================================================================
DESTRUCTOR CButton
END DESTRUCTOR
' ========================================================================================

' =====================================================================================
' Adds a button to the window
' =====================================================================================
FUNCTION CButton.Create ( _
   BYVAL cID AS INTEGER, _                                ' // Control identifier
   BYREF wszTitle AS WSTRING = "", _                      ' // Control caption
   BYVAL x AS LONG = 0, _                                 ' // Horizontal position
   BYVAL y AS LONG = 0, _                                 ' // Vertical position
   BYVAL nWidth AS LONG = 0, _                            ' // Control width
   BYVAL nHeight AS LONG = 0, _                           ' // Control height
   BYVAL dwStyle AS DWORD = 0, _                          ' // Control style
   BYVAL dwExStyle AS DWORD = 0, _                        ' // Extended style
   BYVAL lpParam AS LONG_PTR = 0, _                       ' // Pointer to custom data
   BYVAL pWndProc AS WNDPROC = NULL _                     ' // Address of the window callback procedure
   ) AS HWND                                              ' // Control handle

   IF m_pWindow = NULL THEN EXIT FUNCTION
   ' // Button styles
   IF dwStyle = 0 THEN dwStyle = WS_VISIBLE OR WS_TABSTOP OR BS_PUSHBUTTON OR BS_CENTER OR BS_VCENTER
   IF dwStyle = BS_FLAT THEN dwStyle = WS_VISIBLE OR WS_TABSTOP OR BS_PUSHBUTTON OR BS_CENTER OR BS_VCENTER OR BS_FLAT
   IF dwStyle = BS_DEFPUSHBUTTON THEN dwStyle = WS_VISIBLE OR WS_TABSTOP OR BS_CENTER OR BS_VCENTER OR BS_DEFPUSHBUTTON
   #if _WIN32_WINNT = &h0602
   IF dwStyle = BS_SPLITBUTTON THEN dwStyle = WS_VISIBLE OR WS_TABSTOP OR BS_CENTER OR BS_VCENTER OR BS_SPLITBUTTON
   IF dwStyle = BS_DEFSPLITBUTTON THEN dwStyle = WS_VISIBLE OR WS_TABSTOP OR BS_CENTER OR BS_VCENTER OR BS_DEFSPLITBUTTON
   #endif
   ' // Make sure that the control has the WS_CHILD style
   dwStyle = dwStyle OR WS_CHILD
   ' // Create the control
   m_hCtl = CreateWindowExW(dwExStyle, "Button", wszTitle, dwStyle, _
            x * m_pWindow->rxRatio, y * m_pWindow->ryRatio, nWidth * m_pWindow->rxRatio, nHeight * m_pWindow->ryRatio, _
            m_pWindow->hWindow, CAST(HMENU, CAST(LONG_PTR, cID)), m_pWindow->GetInstance, CAST(LPVOID, lpParam))
   IF m_hCtl = NULL THEN EXIT FUNCTION
   ' // Set the font
   IF m_pWindow->Font THEN SendMessageW m_hCtl, WM_SETFONT, CAST(WPARAM, m_pWindow->Font), TRUE
   ' // Subclass the control if pWndProc is not null
   IF pWndProc <> NULL THEN SetPropW(m_hCtl, "OLDWNDPROC", CAST(HANDLE, SetWindowLongPtrW(m_hCtl, GWLP_WNDPROC, CAST(LONG_PTR, pWndProc))))
   FUNCTION = m_hCtl
END FUNCTION
' =====================================================================================

' ========================================================================================
' Simulates the user clicking a button.
' ========================================================================================
SUB CButton.Click
   SendMessageW m_hCtl, BM_CLICK, 0, 0
END SUB
' ========================================================================================

' ========================================================================================
' Enables a button.
' ========================================================================================
FUNCTION CButton.Enable () AS LONG
   FUNCTION = .EnableWindow(m_hCtl, TRUE)
END FUNCTION
' ========================================================================================

' ========================================================================================
' Disables a button.
' ========================================================================================
FUNCTION CButton.Disable () AS LONG
   FUNCTION = .EnableWindow(m_hCtl, FALSE)
END FUNCTION
' ========================================================================================

' ========================================================================================
' Retrieves the check state of a radio button or check box.
' ========================================================================================
FUNCTION CButton.GetCheck () AS LONG
   FUNCTION = SendMessageW(m_hCtl, BM_GETCHECK, 0, 0)
END FUNCTION
' ========================================================================================

.....

More procedures

END NAMESPACE


Usage example:


DIM pButton AS CButton = @pWindow
pButton.Create(IDCANCEL, "&Close", 350, 250, 75, 23)


What do you think?

The only problem will be the bloat.

José Roca

We can also use the class of each control to store all kind of data we find useful.

To access it, we can store the class pointer using SetPropW, retrieve it with GetPropW and cast it to a variable declared as CButton PTR.

There are plenty of possibilities.

Paul Squires

I like the idea of having the controls in separate classes. You could create a base class with all the common properties and then use the EXTENDS keyword to inherit to your specific class. This is something that I had been playing with in FreeBASIC.

I like the idea of classes and objects because then I can modify Firefly to allow codetip popups/dropdowns whenever someone types a variable referencing a control.
eg.

Firefly would generate the shared variable for the control based on that control's name.
DIM Shared frmMain_cmdOK As clsButton

frmMain_cmdOK.Caption = "OK"

...or something like that.

There will be a little bit of bloat but the benefits would outweigh the size increases especially for users who are not API savvy.

Paul Squires
PlanetSquires Software

Paul Squires

The more that I use FB's OOP capabilities, the more that I love it. I am able to write incredibly easy to use code using the TYPE syntax. It is easy to write functions, subs, properties, public/private variables etc to extend the TYPE structures. Inheriting from base class and using constructors and destructors.

The best feature I have found so far is the extremely easy way to overload subs/functions (and constructors). I am just finishing writing a keylist/hash table/dictionary/associative array class and adding data of different types is as easy as the following:

      Declare Function AddItem Overload ( ByRef sKey  As String, ByRef sData As String) ByRef As clsListNode   
      Declare Function AddItem Overload ( ByRef sKey  As String, ByRef nData As Integer) ByRef As clsListNode   
      Declare Function AddItem Overload ( ByRef sKey  As String, ByRef nData As Double) ByRef As clsListNode   
      Declare Function AddItem Overload ( ByRef sKey  As String, ByRef nAddr As Any Ptr, ByRef nSize As Integer) ByRef As clsListNode   

Depending on what kind of data the programmer is adding, the compiler picks the appropriate function. I have used this in C++ before but now that I have it in FB it makes things sooooo much easier.

' Add a string
cList.AddItem( "12345", "Paul Squires" ) 

' Add an integer
cList.AddItem( "12345", 500 ) 

' Add a double
cList.AddItem( "12345", 3.14587 ) 

' Add a specific area of memory (e is a TYPE variable representing, say, an employee record)
cList.AddItem( "12345", @e, len(e) ) 



Paul Squires
PlanetSquires Software