Hello José,
Can you give me a small example how to draw (line, point, box, etc) on a dialog.
I use DDT with afxnova.
On powerbasic there is graphic attach, graphic line... etc...
Thanx for any help.
I'm not going to replicate the GRAPHIC statements. Instead, I'm working in my own Graphic control that works with GDI, GDI+ and OpenGL. It is a SDK custom control. I will see if I can make it to work with dialogs.
To draw in a dialog using GDI, you have to do it processing the WM_PAINT message ad, if the dialog is resizable, also the WM_ERASEBKGND message.
Here is an small example:
#define UNICODE
#define _WIN32_WINNT &h0602
#include once "AfxNova/DDT.inc"
USING AfxNova
DECLARE FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
BYVAL hPrevInstance AS HINSTANCE, _
BYVAL pwszCmdLine AS WSTRING PTR, _
BYVAL nCmdShow AS LONG) AS LONG
END wWinMain(GetModuleHandleW(NULL), NULL, wCommand(), SW_NORMAL)
DECLARE FUNCTION DlgProc (BYVAL hDlg AS HWND, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LPARAM) AS INT_PTR
CONST IDC_OK = 1001
' ========================================================================================
' Main
' ========================================================================================
FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
BYVAL hPrevInstance AS HINSTANCE, _
BYVAL pwszCmdLine AS WSTRING PTR, _
BYVAL nCmdShow AS LONG) AS LONG
' // Set process DPI aware
SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)
' // Create a new dialog using dialog units
DIM hDlg AS HWND = DialogNewPixels(0, "DDT Dialog - GDI Line Demo", 0, 0, 400, 220, WS_POPUP OR WS_CAPTION OR WS_SYSMENU OR DS_CENTER)
' // Set the dialog's backgroung color
DialogSetColor(hDlg, -1, RGB_WHITE)
' // Display and activate the dialog as modal
DialogShowModal(hDlg, @DlgProc)
RETURN DialogEndResult(hDlg)
END FUNCTION
' ========================================================================================
' ========================================================================================
' Dialog callback procedure
' ========================================================================================
FUNCTION DlgProc (BYVAL hDlg AS HWND, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LPARAM) AS INT_PTR
STATIC cxClient AS LONG, cyClient AS LONG
SELECT CASE uMsg
CASE WM_INITDIALOG
RETURN TRUE
CASE WM_COMMAND
SELECT CASE CBCTL(wParam, lParam)
CASE IDCANCEL
' // If ESC key pressed, close the application by sending an WM_CLOSE message
IF CBCTLMSG(wParam, lParam) = BN_CLICKED THEN
SendMessageW hDlg, WM_CLOSE, 0, 0
END IF
CASE IDC_OK
MsgBox("OK button pressed", MB_ICONEXCLAMATION OR MB_TASKMODAL, "Message")
END SELECT
CASE WM_PAINT
DIM ps AS PAINTSTRUCT
DIM hdc AS HDC = BeginPaint(hDlg, @ps)
Rectangle hdc, cxClient / 8, cyClient / 8, 7 * cxClient / 8, 7 * cyClient / 8
MoveToEx hdc, 0, 0, NULL
LineTo hdc, cxClient, cyClient
MoveToEx hdc, 0, cyClient, NULL
LineTo hdc, cxClient, 0
Ellipse hdc, cxClient / 8, cyClient / 8, 7 * cxClient / 8, 7 * cyClient / 8
RoundRect hdc, cxClient / 4, cyClient / 4, 3 * cxClient / 4, 3 * cyClient / 4, cxClient / 4, cyClient / 4
EndPaint hDlg, @ps
RETURN TRUE
CASE WM_SIZE
cxClient = LOWORD(lParam)
cyClient = HIWORD(lParam)
RETURN TRUE
CASE WM_CLOSE
' // End the application
DialogEnd(hDlg)
END SELECT
RETURN FALSE
END FUNCTION
For documentation about GDI see: https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-rectangle
My GdiPlus classes (working on it) can also be used. You can't compile it because I'm still working in the GdiPlus classes.
#define UNICODE
#define _WIN32_WINNT &h0602
#include once "AfxNova/DDT.inc"
#include once "AfxNova/CGdiPlus.inc"
USING AfxNova
DECLARE FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
BYVAL hPrevInstance AS HINSTANCE, _
BYVAL pwszCmdLine AS WSTRING PTR, _
BYVAL nCmdShow AS LONG) AS LONG
END wWinMain(GetModuleHandleW(NULL), NULL, wCommand(), SW_NORMAL)
DECLARE FUNCTION DlgProc (BYVAL hDlg AS HWND, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LPARAM) AS INT_PTR
CONST IDC_OK = 1001
' ========================================================================================
' Main
' ========================================================================================
FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
BYVAL hPrevInstance AS HINSTANCE, _
BYVAL pwszCmdLine AS WSTRING PTR, _
BYVAL nCmdShow AS LONG) AS LONG
' // Set process DPI aware
SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)
' // Create a new dialog using dialog units
DIM hDlg AS HWND = DialogNewPixels(0, "DDT Dialog - GDI Line Demo", 0, 0, 400, 220, WS_POPUP OR WS_CAPTION OR WS_SYSMENU OR DS_CENTER)
' // Set the dialog's backgroung color
DialogSetColor(hDlg, -1, RGB_WHITE)
' // Display and activate the dialog as modal
DialogShowModal(hDlg, @DlgProc)
RETURN DialogEndResult(hDlg)
END FUNCTION
' ========================================================================================
' ========================================================================================
' The following example creates an AdjustableArrowCap, myArrow, and sets the height of the
' cap. The code then creates a Pen, assigns myArrow as the ending line cap for the Pen,
' and draws a capped line. Next, the code gets the height of the arrow cap, creates a new
' arrow cap with height equal to the height of myArrow, assigns the new arrow cap as the
' ending line cap for the Pen, and draws another capped line.
' ========================================================================================
SUB Example_GetHeight (BYVAL hdc AS HDC)
' // Create a graphics object from the window device context
DIM graphics AS CGpGraphics = hdc
' // Get the DPI scaling ratios
DIM rxRatio AS SINGLE = graphics.GetDpiX / 96
DIM ryRatio AS SINGLE = graphics.GetDpiY / 96
' // Set the scale transform
graphics.ScaleTransform(rxRatio, ryRatio)
' // Create an AdjustableArrowCap with a height of 10 pixels
DIM myArrow AS CGpAdjustableArrowCap = CGpAdjustableArrowCap(10, 10, TRUE)
' // Adjust to DPI by setting the scale width
myArrow.SetWidthScale(rxRatio)
' // Create a Pen, and assign myArrow as the end cap
DIM arrowPen AS CGpPen = ARGB_Violet
arrowPen.SetCustomEndCap(@myArrow)
' // Draw a line using arrowPen
graphics.DrawLine(@arrowPen, 0, 20, 100, 20)
' // Create a second arrow cap using the height of the first one
DIM AS CGpAdjustableArrowCap otherArrow = CGpAdjustableArrowCap(myArrow.GetHeight, 20, TRUE)
otherArrow.SetWidthScale(rxRatio)
' // Assign the new arrow cap as the end cap for arrowPen
arrowPen.SetCustomEndCap(@otherArrow)
' // Draw a line using arrowPen
graphics.DrawLine(@arrowPen, 0, 55, 100, 55)
END SUB
' ========================================================================================
' ========================================================================================
' Dialog callback procedure
' ========================================================================================
FUNCTION DlgProc (BYVAL hDlg AS HWND, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LPARAM) AS INT_PTR
SELECT CASE uMsg
CASE WM_INITDIALOG
RETURN TRUE
CASE WM_COMMAND
SELECT CASE CBCTL(wParam, lParam)
CASE IDCANCEL
' // If ESC key pressed, close the application by sending an WM_CLOSE message
IF CBCTLMSG(wParam, lParam) = BN_CLICKED THEN
SendMessageW hDlg, WM_CLOSE, 0, 0
END IF
CASE IDC_OK
MsgBox("OK button pressed", MB_ICONEXCLAMATION OR MB_TASKMODAL, "Message")
END SELECT
CASE WM_PAINT
DIM ps AS PAINTSTRUCT
DIM hdc AS HDC = BeginPaint(hDlg, @ps)
Example_GetHeight(hdc)
EndPaint hDlg, @ps
RETURN TRUE
CASE WM_CLOSE
' // End the application
DialogEnd(hDlg)
END SELECT
RETURN FALSE
END FUNCTION
My graphic control features persistence, so you don't have to be constantly repainting it. This is a SDK test. You can't compile it because I'm still working in the GdiPlus classes.
' ########################################################################################
' Microsoft Windows
' File: AdjustableArrowCapGetHeight.bas
' Contents: GDI+ - AdjustableArrowCapGetHeight example
' Compiler: FreeBasic 32 & 64 bit
' Copyright (c) 2025 José Roca. Freeware. Use at your own risk.
' 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.
' ########################################################################################
#define UNICODE
#INCLUDE ONCE "AfxNova/CGdiPlus.inc"
#INCLUDE ONCE "AfxNova/CGraphCtx.inc"
USING AfxNova
CONST IDC_GRCTX = 1001
DECLARE FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
BYVAL hPrevInstance AS HINSTANCE, _
BYVAL pwszCmdLine AS WSTRING PTR, _
BYVAL nCmdShow AS LONG) AS LONG
END wWinMain(GetModuleHandleW(NULL), NULL, wCOMMAND(), SW_NORMAL)
' // Forward declaration
DECLARE FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
' ========================================================================================
' The following example creates an AdjustableArrowCap, myArrow, and sets the height of the
' cap. The code then creates a Pen, assigns myArrow as the ending line cap for the Pen,
' and draws a capped line. Next, the code gets the height of the arrow cap, creates a new
' arrow cap with height equal to the height of myArrow, assigns the new arrow cap as the
' ending line cap for the Pen, and draws another capped line.
' ========================================================================================
SUB Example_GetHeight (BYVAL hdc AS HDC)
' // Create a graphics object from the window device context
DIM graphics AS CGpGraphics = hdc
' // Get the DPI scaling ratios
DIM rxRatio AS SINGLE = graphics.GetDpiX / 96
DIM ryRatio AS SINGLE = graphics.GetDpiY / 96
' // Set the scale transform
graphics.ScaleTransform(rxRatio, ryRatio)
' // Create an AdjustableArrowCap with a height of 10 pixels
DIM myArrow AS CGpAdjustableArrowCap = CGpAdjustableArrowCap(10, 10, TRUE)
' // Adjust to DPI by setting the scale width
myArrow.SetWidthScale(rxRatio)
' // Create a Pen, and assign myArrow as the end cap
DIM arrowPen AS CGpPen = ARGB_Violet
arrowPen.SetCustomEndCap(@myArrow)
' // Draw a line using arrowPen
graphics.DrawLine(@arrowPen, 0, 20, 100, 20)
' // Create a second arrow cap using the height of the first one
DIM AS CGpAdjustableArrowCap otherArrow = CGpAdjustableArrowCap(myArrow.GetHeight, 20, TRUE)
otherArrow.SetWidthScale(rxRatio)
' // Assign the new arrow cap as the end cap for arrowPen
arrowPen.SetCustomEndCap(@otherArrow)
' // Draw a line using arrowPen
graphics.DrawLine(@arrowPen, 0, 55, 100, 55)
END SUB
' ========================================================================================
' ========================================================================================
' Main
' ========================================================================================
FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
BYVAL hPrevInstance AS HINSTANCE, _
BYVAL pwszCmdLine AS WSTRING PTR, _
BYVAL nCmdShow AS LONG) AS LONG
' // Set process DPI aware
SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)
' // Enable visual styles without including a manifest file
AfxEnableVisualStyles
' // Create the main window
DIM pWindow AS CWindow = "MyClassName"
pWindow.CreateOverlapped(NULL, "GDI+ AdjustableArrowCapGetHeight", @WndProc)
' // Size it by setting the wanted width and height of its client area
pWindow.SetClientSize(400, 250)
' // Center the window
pWindow.Center
' // Add a graphic control
DIM pGraphCtx AS CGraphCtx = CGraphCtx(@pWindow, IDC_GRCTX, "", 0, 0, pWindow.ClientWidth, pWindow.ClientHeight)
pGraphCtx.Clear RGB_FLORALWHITE
' // Get the memory device context of the graphic control
DIM hdc AS HDC = pGraphCtx.GetMemDc
' // Draw the graphics
Example_GetHeight(hdc)
' // Displays the window and dispatches the Windows messages
FUNCTION = pWindow.DoEvents(nCmdShow)
END FUNCTION
' ========================================================================================
' ========================================================================================
' Main window procedure
' ========================================================================================
FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
SELECT CASE uMsg
' // If an application processes this message, it should return zero to continue
' // creation of the window. If the application returns –1, the window is destroyed
' // and the CreateWindowExW function returns a NULL handle.
CASE WM_CREATE
AfxEnableDarkModeForWindow(hwnd)
EXIT FUNCTION
' // Theme has changed
CASE WM_THEMECHANGED
AfxEnableDarkModeForWindow(hwnd)
EXIT FUNCTION
CASE WM_COMMAND
SELECT CASE CBCTL(wParam, lParam)
CASE IDCANCEL
' // If ESC key pressed, close the application by sending an WM_CLOSE message
IF CBCTLMSG(wParam, lParam) = BN_CLICKED THEN
SendMessageW hwnd, WM_CLOSE, 0, 0
EXIT FUNCTION
END IF
END SELECT
CASE WM_DESTROY
' // Ends the application by sending a WM_QUIT message
PostQuitMessage(0)
EXIT FUNCTION
END SELECT
' // Default processing of Windows messages
FUNCTION = DefWindowProcW(hwnd, uMsg, wParam, lParam)
END FUNCTION
' ========================================================================================
Hi José,
Thanx for the explanations.
I test and learn for porting my powerbasic apps.
Is the new graphic control soon available ?
Yes. I just have finished the integration. Using my GDI+ classes, that replicate the Microsoft ones, and setting the DPI ratios with ScaleTransform, the graphics are DPI aware and scale automatically. Contrarily to the PowerBasic graphic control, that is a subclassed static control that only works with 24-bit images, CGraphCtx is 32 bit, allowing the use of alpha blended images with transparency and, as it uses DIBs, it has not the 4 MB limitation.
Test example (the attachment contains a 64-bit executable):
' ########################################################################################
' Microsoft Windows
' File: DDT_AdjustableArrowCapGetHeight.bas
' Contents: GDI+ - AdjustableArrowCapGetHeight example
' Compiler: FreeBasic 32 & 64 bit
' Copyright (c) 2025 José Roca. Freeware. Use at your own risk.
' 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.
' ########################################################################################
#define UNICODE
#INCLUDE ONCE "AfxNova/CGdiPlus.inc"
#INCLUDE ONCE "AfxNova/CGraphCtx.inc"
#INCLUDE ONCE "AfxNova/DDT.inc"
#INCLUDE ONCE "AfxNova/AfxExt.bi" ' // optional: For dark mode
USING AfxNova
CONST IDC_GRCTX = 1001
DECLARE FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
BYVAL hPrevInstance AS HINSTANCE, _
BYVAL pwszCmdLine AS WSTRING PTR, _
BYVAL nCmdShow AS LONG) AS LONG
END wWinMain(GetModuleHandleW(NULL), NULL, wCOMMAND(), SW_NORMAL)
' // Forward declaration
DECLARE FUNCTION DlgProc (BYVAL hDlg AS HWND, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LPARAM) AS INT_PTR
' ========================================================================================
' The following example creates an AdjustableArrowCap, myArrow, and sets the height of the
' cap. The code then creates a Pen, assigns myArrow as the ending line cap for the Pen,
' and draws a capped line. Next, the code gets the height of the arrow cap, creates a new
' arrow cap with height equal to the height of myArrow, assigns the new arrow cap as the
' ending line cap for the Pen, and draws another capped line.
' ========================================================================================
SUB Example_GetHeight (BYVAL hdc AS HDC)
' // Create a graphics object from the window device context
DIM graphics AS CGpGraphics = hdc
' // Get the DPI scaling ratios
DIM rxRatio AS SINGLE = graphics.GetDpiX / 96
DIM ryRatio AS SINGLE = graphics.GetDpiY / 96
' // Set the scale transform
graphics.ScaleTransform(rxRatio, ryRatio)
' // Create an AdjustableArrowCap with a height of 10 pixels
DIM myArrow AS CGpAdjustableArrowCap = CGpAdjustableArrowCap(10, 10, TRUE)
' // Adjust to DPI by setting the scale width
myArrow.SetWidthScale(rxRatio)
' // Create a Pen, and assign myArrow as the end cap
DIM arrowPen AS CGpPen = ARGB_Violet
arrowPen.SetCustomEndCap(@myArrow)
' // Draw a line using arrowPen
graphics.DrawLine(@arrowPen, 0, 20, 100, 20)
' // Create a second arrow cap using the height of the first one
DIM AS CGpAdjustableArrowCap otherArrow = CGpAdjustableArrowCap(myArrow.GetHeight, 20, TRUE)
otherArrow.SetWidthScale(rxRatio)
' // Assign the new arrow cap as the end cap for arrowPen
arrowPen.SetCustomEndCap(@otherArrow)
' // Draw a line using arrowPen
graphics.DrawLine(@arrowPen, 0, 55, 100, 55)
END SUB
' ========================================================================================
' ========================================================================================
' Main
' ========================================================================================
FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
BYVAL hPrevInstance AS HINSTANCE, _
BYVAL pwszCmdLine AS WSTRING PTR, _
BYVAL nCmdShow AS LONG) AS LONG
' // The recommended way is to use a manifest.
' // Optional: Set process DPI aware.
SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)
' // Optional: Enable visual styles without including a manifest file
AfxEnableVisualStyles
' // Create a new custom dialog using pixels
' DIM hDlg AS HWND = DialogNewPixels("MyClassName", 0, "DDT - GraphCtx Test", 0, 0, 400, 250, WS_OVERLAPPEDWINDOW OR DS_CENTER)
' // Alternate way: Provides an exact control of the client size
DIM hDlg AS HWND = DialogNewPixels("MyClassName", 0, "DDT - GraphCtx Test", 0, 0, 0, 0, WS_OVERLAPPEDWINDOW)
DialogSetClient(hDlg, 400, 250)
DialogCenter(hDlg)
' // Optional: Caption dark mode
AfxEnableDarkModeForWindow(hDlg)
' // Add a graphic control
DIM nWidth AS LONG = DialogGetClientWidth(hDlg)
DIM nHeight AS LONG = DialogGetClientHeight(hDlg)
DIM pGraphCtx AS CGraphCtx = CGraphCtx(hDlg, IDC_GRCTX, "", 0, 0, nWidth, nHeight)
' // Make the control resizable
pGraphCtx.Resizable = TRUE
' // Optional: Clear the graphic control background
pGraphCtx.Clear RGB_FLORALWHITE
' // Get the memory device context of the graphic control
DIM hdc AS HDC = pGraphCtx.GetMemDc
' // Pointer version:
' DIM pGraphCtx AS CGraphCtx = NEW CGraphCtx(hDlg, IDC_GRCTX, "", 0, 0, nWidth, nHeight)
' --or--
' DIM pGraphCtx AS CGraphCtx PTR = ControlAddGraphic(hDlg, IDC_GRCTX, "", 0, 0, nWidth, nHeight)
' pGraphCtx->Resizable = TRUE
' pGraphCtx->Clear RGB_FLORALWHITE
' DIM hdc AS HDC = pGraphCtx->GetMemDc
' // Draw the graphics
Example_GetHeight(hdc)
' // Display and activate the dialog as modal
DialogShowModal(hDlg, @DlgProc)
' // Pointer version: Delete the graphic control
' IF pGraphCtx THEN Delete pGraphCtx
' // Return the result code set with DialogEnd
RETURN DialogEndResult(hDlg)
END FUNCTION
' ========================================================================================
' ========================================================================================
' Dialog callback procedure
' ========================================================================================
FUNCTION DlgProc (BYVAL hDlg AS HWND, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LPARAM) AS INT_PTR
SELECT CASE uMsg
CASE WM_INITDIALOG
RETURN TRUE
' // Optional: Theme has changed
' CASE WM_THEMECHANGED
' AfxEnableDarkModeForWindow(hDlg)
CASE WM_COMMAND
SELECT CASE CBCTL(wParam, lParam)
CASE IDCANCEL
' // If ESC key pressed, close the application by sending an WM_CLOSE message
IF CBCTLMSG(wParam, lParam) = BN_CLICKED THEN
SendMessageW hDlg, WM_CLOSE, 0, 0
END IF
END SELECT
CASE WM_CLOSE
' // End the application
DialogEnd(hDlg)
END SELECT
END FUNCTION
' ========================================================================================
It also allows to mix the use of GDI, GDI+ and OpenGL.
' ########################################################################################
' Microsoft Windows
' Contents: CWindow OpenGL Graphic Control Skeleton
' Graphic control, GDI+ classes and OpenGL working together
' Compiler: FreeBasic 32 & 64 bit
' Copyright (c) 2025 José Roca. Freeware. Use at your own risk.
' 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.
' ########################################################################################
#define UNICODE
#INCLUDE ONCE "AfxNova/CWindow.inc"
#INCLUDE ONCE "AfxNova/CGdiPlus.inc"
#INCLUDE ONCE "AfxNova/CGraphCtx.inc"
USING AfxNova
CONST IDC_GRCTX = 1001
DECLARE FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
BYVAL hPrevInstance AS HINSTANCE, _
BYVAL pwszCmdLine AS WSTRING PTR, _
BYVAL nCmdShow AS LONG) AS LONG
END wWinMain(GetModuleHandleW(NULL), NULL, wCOMMAND(), SW_NORMAL)
' // Forward declaration
DECLARE FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
' ========================================================================================
' The following sample code draws a line.
' Change it with your own code.
' ========================================================================================
SUB GDIP_Render (BYVAL hDC AS HDC)
' // Create a graphics object from the window device context
DIM graphics AS CGpGraphics = hdc
' // Get the DPI scaling ratios
DIM rxRatio AS SINGLE = graphics.GetDpiX / 96
DIM ryRatio AS SINGLE = graphics.GetDpiY / 96
' // Set the scale transform
graphics.ScaleTransform(rxRatio, ryRatio)
' // Create a Pen object
DIM pen AS CGpPen = CGpPen(ARGB_GREEN, 15)
' // Draw a line
graphics.DrawLine(@pen, 0, 0, 200, 100)
END SUB
' ========================================================================================
' =======================================================================================
' All the setup goes here
' =======================================================================================
SUB RenderScene (BYVAL nWidth AS LONG, BYVAL nHeight AS LONG)
' // Specify clear values for the color buffers
glClearColor 0.0, 0.0, 0.0, 0.0
' // Specify the clear value for the depth buffer
glClearDepth 1.0
' // Specify the value used for depth-buffer comparisons
glDepthFunc GL_LESS
' // Enable depth comparisons and update the depth buffer
glEnable GL_DEPTH_TEST
' // Select smooth shading
glShadeModel GL_SMOOTH
' // Prevent divide by zero making height equal one
IF nHeight = 0 THEN nHeight = 1
' // Reset the current viewport
glViewport 0, 0, nWidth, nHeight
' // Select the projection matrix
glMatrixMode GL_PROJECTION
' // Reset the projection matrix
glLoadIdentity
' // Calculate the aspect ratio of the window
gluPerspective 45.0!, nWidth / nHeight, 0.1!, 100.0!
' // Select the model view matrix
glMatrixMode GL_MODELVIEW
' // Reset the model view matrix
glLoadIdentity
' // Clear the screen buffer
glClear GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT
' // Reset the view
glLoadIdentity
glTranslatef -1.5!, 0.0!, -6.0! ' Move left 1.5 units and into the screen 6.0
glBegin GL_TRIANGLES ' Drawing using triangles
glColor3f 1.0!, 0.0!, 0.0! ' Set the color to red
glVertex3f 0.0!, 1.0!, 0.0! ' Top
glColor3f 0.0!, 1.0!, 0.0! ' Set the color to green
glVertex3f 1.0!,-1.0!, 0.0! ' Bottom right
glColor3f 0.0!, 0.0!, 1.0! ' Set the color to blue
glVertex3f -1.0!,-1.0!, 0.0! ' Bottom left
glEnd ' Finished drawing the triangle
glTranslatef 3.0!,0.0!,0.0! ' Move right 3 units
glColor3f 0.5!, 0.5!, 1.0! ' Set the color to blue one time only
glBegin GL_QUADS ' Draw a quad
glVertex3f -1.0!, 1.0!, 0.0! ' Top left
glVertex3f 1.0!, 1.0!, 0.0! ' Top right
glVertex3f 1.0!,-1.0!, 0.0! ' Bottom right
glVertex3f -1.0!,-1.0!, 0.0! ' Bottom left
glEnd ' Done drawing the quad
' // Required: force execution of GL commands in finite time
glFlush
END SUB
' =======================================================================================
' ========================================================================================
' Main
' ========================================================================================
FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
BYVAL hPrevInstance AS HINSTANCE, _
BYVAL pwszCmdLine AS WSTRING PTR, _
BYVAL nCmdShow AS LONG) AS LONG
' // Set process DPI aware
SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)
' // Enable visual styles without including a manifest file
AfxEnableVisualStyles
' // Create the main window
DIM pWindow AS CWindow
pWindow.Create(NULL, "CWindow+CGraphCtx+CGdiPlus+OpenGL", @WndProc)
pWindow.SetClientSize(400, 250)
pWindow.Center
' // Add a graphic control with OPENGL enabled
DIM pGraphCtx AS CGraphCtx = CGraphCtx(@pWindow, IDC_GRCTX, "OPENGL", 0, 0, pWindow.ClientWidth, pWindow.ClientHeight)
' // Anchor the control
pWindow.AnchorControl(IDC_GRCTX, AFX_ANCHOR_HEIGHT_WIDTH)
' // Clear the background
pGraphCtx.Clear RGB_WHITE
' // Make the control resizable
pGraphCtx.Stretchable = TRUE
' // Make current the rendering context
pGraphCtx.MakeCurrent
' // Render the OpenGL scene
RenderScene pGraphCtx.GetVirtualBufferWidth, pGraphCtx.GetVirtualBufferHeight
' // Draw the GDI+ graphics
GDIP_Render pGraphCtx.GetMemDC
' // Dispatch Windows events
FUNCTION = pWindow.DoEvents(nCmdShow)
END FUNCTION
' ========================================================================================
' ========================================================================================
' Main window callback procedure
' ========================================================================================
FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
SELECT CASE uMsg
CASE WM_COMMAND
SELECT CASE CBCTL(wParam, lParam)
CASE IDCANCEL
' // If ESC key pressed, close the application by sending an WM_CLOSE message
IF CBCTLMSG(wParam, lParam) = BN_CLICKED THEN
SendMessageW hwnd, WM_CLOSE, 0, 0
EXIT FUNCTION
END IF
END SELECT
CASE WM_DESTROY
' // End the application
PostQuitMessage(0)
EXIT FUNCTION
END SELECT
' // Default processing of Windows messages
FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)
END FUNCTION
' ========================================================================================
Hi, nice examples !!
After try the exe, i try to compile code... but my version afxnova is incomplete... i wait.
Good job.
@jose
I know your are in mid of your work - but there some findings for the graphics control
Nvertheless - thank for the great work --
' Graphic control, GDI+ classes and OpenGL working together
' DEMO FILE : GdiPlusAndOpenGL.bas
! wrong folder reference in line 1188...1198 of AfxNova\CGdiPlu.inc
! causes error 23: File not found in '#include once "AfxNova/CGdiPlus/.....inc"'
! starting with
#include once "AfxNova/CGdiPlus/CGpBitmap.inc"
#include once "AfxNova/CGdiPlus/CGpBrush.inc"
#include once "AfxNova/CGdiPlus/CGpFont.inc"
#include once "AfxNova/CGdiPlus/CGpGraphics.inc"
#include once "AfxNova/CGdiPlus/CGpImageAttributes.inc"
#include once "AfxNova/CGdiPlus/CGpLineCaps.inc"
#include once "AfxNova/CGdiPlus/CGpMatrix.inc"
#include once "AfxNova/CGdiPlus/CGpPath.inc"
#include once "AfxNova/CGdiPlus/CGpPen.inc"
#include once "AfxNova/CGdiPlus/CGpRegion.inc"
#include once "AfxNova/CGdiPlus/CGpStringFormat.inc"
! BUT using a correct reference will follow-up with " declaration outside namespace...."
! FOR "CGpBitmap.inc ... CGpGraphics.inc"
! trying to correct this
! will cause an follow-up segmentation error
Thanks very much for reporting it.
Modified "CGdiPlus.inc" and "CGpGraphics.inc"
and uploaded them to the AfxNova repository in GitHub.
For GDI+ I'm using my own declarations file, "AfxGdiplus.bi", because the ones provided with the FreeBasic compiler for 32-bit are a truly mess and incompatible with the ones for 64-bit, so I have unified them. The import 32-bit library for GDI+ is also partially broken. Paul Squires has generated a new one that works correctly and that will be included with the new Tiko release. Meanwhile, it is advisable to compile with the 64-bit compiler.