Estimado Miguel Angel,
1) Theme en la barra de título
Hoy el theme de FWH (FW_SetDarkMode / SetDarkMode) pinta el área de cliente y los controles, pero no la barra de título: esa la dibuja Windows (DWM), y FWH todavía no la toca. Se puede hacer tú mismo con DwmSetWindowAttribute. Barra oscura: DWMWA_USE_IMMERSIVE_DARK_MODE. Color a medida del fondo y del texto del título: DWMWA_CAPTION_COLOR / DWMWA_TEXT_COLOR. Microsoft lo documenta para Windows 11. El modo oscuro también suele funcionar en Windows 10 reciente. En versiones antiguas simplemente no hace nada.
#include "FiveWin.ch"
function Main()
local oDlg
FW_SetDarkMode( .T. )
DEFINE DIALOG oDlg TITLE "Título con el theme" SIZE 400, 200 PIXEL
ACTIVATE DIALOG oDlg CENTERED ON INIT TitleTheme( oDlg )
return nil
// Sirve igual para una WINDOW: ACTIVATE WINDOW oWnd ON INIT TitleTheme( oWnd )
function TitleTheme( oWnd )
local lDark := FW_SetDarkMode()
SetTitleColors( oWnd:hWnd, If( lDark, RGB( 30, 30, 30 ), nil ), ;
If( lDark, RGB( 220, 220, 220 ), nil ), lDark )
return nil
#pragma BEGINDUMP
#include <windows.h>
#include <hbapi.h>
typedef HRESULT ( WINAPI * PDWMSETATTR )( HWND, DWORD, LPCVOID, DWORD );
// SetTitleColors( hWnd, nClrCaption, nClrText, lDark ) -> lOk
HB_FUNC( SETTITLECOLORS )
{
HMODULE hDwm = LoadLibrary( TEXT( "dwmapi.dll" ) );
BOOL bOk = FALSE;
if( hDwm )
{
PDWMSETATTR pSet = ( PDWMSETATTR ) GetProcAddress( hDwm, "DwmSetWindowAttribute" );
if( pSet )
{
HWND hWnd = ( HWND ) ( HB_PTRDIFF ) hb_parnint( 1 );
BOOL bDark = hb_parl( 4 );
COLORREF clr;
pSet( hWnd, 20, &bDark, sizeof( bDark ) ); // DWMWA_USE_IMMERSIVE_DARK_MODE
if( HB_ISNUM( 2 ) )
{
clr = ( COLORREF ) hb_parnl( 2 );
bOk = SUCCEEDED( pSet( hWnd, 35, &clr, sizeof( clr ) ) ); // DWMWA_CAPTION_COLOR
}
if( HB_ISNUM( 3 ) )
{
clr = ( COLORREF ) hb_parnl( 3 );
pSet( hWnd, 36, &clr, sizeof( clr ) ); // DWMWA_TEXT_COLOR
}
}
FreeLibrary( hDwm );
}
hb_retl( bOk );
}
#pragma ENDDUMP
Carga dwmapi.dll en tiempo de ejecución, así que no hay que enlazar ninguna lib extra.
Una aclaración honesta: el ejemplo compila, enlaza y corre, y el área de cliente sale oscura. El color de la barra de título solo lo pude comprobar a medias, porque lo probé en Wine, que dibuja su propio título y no lo tematiza. Para ver el título con el theme hace falta un Windows 11 real.
2) Scroll vertical y horizontal en una window
Sí se puede. lVScroll / lHScroll (o DEFINE WINDOW ... VSCROLL HSCROLL) crean las dos barras (oWnd:oVScroll y oWnd:oHScroll), pero FWH no mueve el contenido solo: el rango por defecto es 1..2 y no llevan acciones asignadas, por eso "no pasa nada". Habría que darles rango y acciones (ON UP / ON DOWN / ON LEFT / ON RIGHT) y hacer ScrollWindow a mano (hay un ejemplo en samples\test\testwscr.prg). En DIALOG esos parámetros no existen.
Lo más cómodo es TScrollPanel: un panel con las dos barras que calcula el rango solo a partir de los controles que contiene y soporta rueda del ratón y arrastre. Este ejemplo está compilado, enlazado y probado:
#include "FiveWin.ch"
function Main()
local oWnd, oPanel, n
local cNombre := Space( 30 ), cCiudad := Space( 30 ), cNotas := Space( 30 )
FW_SetUnicode( .T. ) // si guardas el .prg en UTF-8
DEFINE WINDOW oWnd TITLE "Scroll vertical y horizontal" ;
FROM 0, 0 TO 400, 600 PIXEL
oPanel := TScrollPanel():New( 0, 0, 360, 580, oWnd, .T. )
// Contenido más alto que la ventana -> scroll vertical
for n := 1 to 40
@ ( n - 1 ) * 30 + 10, 10 SAY "Línea " + LTrim( Str( n ) ) OF oPanel SIZE 100, 20 PIXEL
next
@ 10, 150 GET cNombre OF oPanel SIZE 200, 22 PIXEL
@ 40, 150 GET cCiudad OF oPanel SIZE 200, 22 PIXEL
// Contenido más ancho que la ventana -> scroll horizontal
@ 10, 900 GET cNotas OF oPanel SIZE 200, 22 PIXEL
@ 40, 900 BUTTON "Aceptar" OF oPanel SIZE 100, 30 PIXEL ACTION oWnd:End()
oPanel:SetRange() // llamarlo después de crear todos los controles
// Evita que al hacer scroll horizontal el foco devuelva el panel al GET activo
AEval( oPanel:aControls, { |o| o:bGotFocus := nil } )
oWnd:oClient := oPanel // el panel se ajusta al tamaño de la ventana
ACTIVATE WINDOW oWnd CENTERED
return nil
Ojo con la línea del AEval: al probarlo vimos que el scroll horizontal se atascaba. Es un bug de TScrollPanel: SetRange() pone en cada control un bGotFocus que, tras un scroll horizontal, vuelve a traer a la vista el control con el foco (solo lo evita en el vertical). Ya lo hemos corregido en la librería (master); mientras tanto, esa línea lo soluciona. El único efecto es que, al pasar con Tab a un control que está fuera de la vista, el panel no se desplaza solo hasta él.
Un abrazo