• Print

Author Topic: GUI experimenting...  (Read 438 times)

mcalkins

  • Hero Member
  • *****
  • Posts: 1279
    • qbasicmichael.com
    • Email
GUI experimenting...
« on: September 11, 2012, 11:36:37 PM »
See topic:
http://www.network54.com/Forum/613583/message/1347407859/just+a+GUI+experiment.
related topic:
http://www.network54.com/Forum/613583/message/1343554437/mingw-w32+incorrectly+declares+HBRUSH.

The translation from C++ was a bit rushed. I'm too tired/lazy to double check things. Also, I'm a noob at GUI stuff. I suspect that even moderately experienced Visual Basic programmers will be able to dramatically improve on this. I am still not in a GUI, event driven, message based mindset. It all seems clumsy and terribly inefficient from a programming point of view, although I must confess that GUI programs tend to be easier to use than command line console programs, at least for some things.

If anyone wants to get serious with this, please read over the relevant parts of the MSDN library, and double check everything I've done.

P.S. I bet Galleon would consider this to be abuse of his language.  ;D

P.S. Please run the program from the command prompt, or else, change the SYSTEM to END.

Edit: changed a bunch of IFs to a SELECT CASE.

Regards,
Michael

win.h
Code: [Select]
ptrszint FUNC_WINDOWPROC(ptrszint*_FUNC_WINDOWPROC_OFFSET_HWND,uint32*_FUNC_WINDOWPROC_ULONG_UMSG,uptrszint*_FUNC_WINDOWPROC_UOFFSET_WPARAM,ptrszint*_FUNC_WINDOWPROC_OFFSET_LPARAM);

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 return FUNC_WINDOWPROC((ptrszint *) (& hwnd), & uMsg, & wParam, (ptrszint *) (& lParam));
}

void * GetWindowProc() {
 return (void *) WindowProc;
}

Code: [Select]
'DEFSTR A-Z

' public domain, michael calkins
' revision 2012 09 12
' very much experimental. I am a noob at GUI stuff, and might be doing multiple things wrong or in unideal ways.
' rough translation of:
' http://www.network54.com/Forum/613583/message/1347419042/
' with a few liberties taken.

' not only might I be doing things wrong, but I am also not doublechecking the function declarations, type definitions, and constant values. They could be wrong.

$CONSOLE
_DEST _CONSOLE
$SCREENHIDE

' get more constants from winuser.h as needed.

CONST IDC_ARROW = &H7F00
CONST COLOR_WINDOW = 5

CONST WS_OVERLAPPED = 0
CONST WS_CHILD = &H40000000
CONST WS_VISIBLE = &H10000000
CONST WS_MAXIMIZE = &H01000000
CONST WS_CAPTION = &H00C00000
CONST WS_VSCROLL = &H00200000
CONST WS_HSCROLL = &H00100000
CONST WS_SYSMENU = &H00080000
CONST WS_THICKFRAME = &H00040000
CONST WS_TABSTOP = &H00010000
CONST WS_MINIMIZEBOX = &H00020000
CONST WS_MAXIMIZEBOX = &H00010000
CONST WS_OVERLAPPEDWINDOW = WS_OVERLAPPED OR WS_CAPTION OR WS_SYSMENU OR WS_THICKFRAME OR WS_MINIMIZEBOX OR WS_MAXIMIZEBOX

CONST CW_USEDEFAULT = &H80000000&

CONST BS_PUSHBUTTON = 0
CONST BS_AUTOCHECKBOX = 3
CONST BS_GROUPBOX = 7
CONST BS_AUTORADIOBUTTON = 9
CONST BS_TEXT = 0

CONST BN_CLICKED = 0

CONST BM_GETCHECK = &HF0

CONST ES_LEFT = 0
CONST ES_MULTILINE = 4
CONST ES_AUTOVSCROLL = &H0040
CONST ES_AUTOHSCROLL = &H0080
CONST ES_WANTRETURN = &H1000

CONST WM_DESTROY = 2
CONST WM_GETTEXT = &H000D
CONST WM_CLOSE = &H0010
CONST WM_COMMAND = &H0111

CONST SW_SHOWDEFAULT = &HA

DECLARE LIBRARY "win"
 FUNCTION GetWindowProc%& ()
END DECLARE

DECLARE DYNAMIC LIBRARY "user32"
 FUNCTION SendMessageA%& (BYVAL hWnd%&, BYVAL Msg~&, BYVAL wParam~%&, BYVAL lParam%&)
 FUNCTION DefWindowProcA%& (BYVAL hWnd%&, BYVAL Msg~&, BYVAL wParam~%&, BYVAL lParam%&)
 SUB PostQuitMessage (BYVAL nExitCode&)
 FUNCTION LoadCursorW%& (BYVAL hInstance%&, BYVAL lpCursorName%&)
 FUNCTION RegisterClassA~% (BYVAL lpWndClass%&)
 FUNCTION CreateWindowExA%& (BYVAL dwExStyle~&, BYVAL lpClassName%&, BYVAL lpWindowName%&, BYVAL dwStyle~&, BYVAL x&, BYVAL y&, BYVAL nWidth&, BYVAL nHeight&, BYVAL hWndParent%&, BYVAL hMenu%&, BYVAL hInstance%&, BYVAL lpParam%&)
 FUNCTION ShowWindow& (BYVAL hWnd%&, BYVAL nCmdShow&)
 FUNCTION UpdateWindow& (BYVAL hWnd%&)
 FUNCTION GetMessageA& (BYVAL lpMsg%&, BYVAL hWnd%&, BYVAL wMsgFilterMin~&, BYVAL wMsgFilterMax~&)
 FUNCTION TranslateMessage& (BYVAL lpMsg%&)
 FUNCTION DispatchMessageA%& (BYVAL lpmsg%&)
END DECLARE

DECLARE DYNAMIC LIBRARY "kernel32"
 FUNCTION GetModuleHandleW%& (BYVAL lpModuleName%&)
 FUNCTION GetLastError~& ()
END DECLARE

TYPE POINT
 x AS LONG
 y AS LONG
END TYPE

TYPE MSG
 hwnd AS _OFFSET
 message AS _UNSIGNED LONG
 wParam AS _UNSIGNED _OFFSET 'unsigned pointer sized integer
 lParam AS _OFFSET 'pointer sized integer
 time AS _UNSIGNED LONG
 pt AS POINT
END TYPE

TYPE WNDCLASSA
 style AS _UNSIGNED LONG
 lpfnWndProc AS _OFFSET
 cbClsExtra AS LONG
 cbWndExtra AS LONG
 hInstance AS _OFFSET
 hIcon AS _OFFSET
 hCursor AS _OFFSET
 hbrBackground AS _OFFSET
 lpszMenuName AS _OFFSET
 lpszClassName AS _OFFSET
END TYPE

DIM SHARED hi AS _OFFSET
DIM SHARED bRet AS LONG
DIM SHARED hw AS _OFFSET
DIM SHARED hwb0 AS _OFFSET
DIM SHARED hwb1 AS _OFFSET
DIM SHARED hwcb AS _OFFSET
DIM SHARED hwgb AS _OFFSET
DIM SHARED hwr0 AS _OFFSET
DIM SHARED hwr1 AS _OFFSET
DIM SHARED hwe AS _OFFSET
DIM SHARED wc AS WNDCLASSA
DIM SHARED msg AS MSG
DIM SHARED at AS _UNSIGNED INTEGER

DIM SHARED buf AS STRING * 4096

DIM SHARED discardb AS LONG
DIM SHARED discardp AS _OFFSET
DIM SHARED t0 AS STRING
DIM SHARED t1 AS STRING

DIM SHARED MainClassName AS STRING * 5
MainClassName = "main" + CHR$(0)
DIM SHARED crlf AS STRING * 2
crlf = MKI$(&HA0D)

hi = GetModuleHandleW(0)

wc.style = 0
wc.lpfnWndProc = GetWindowProc
wc.cbClsExtra = 0
wc.cbWndExtra = 0
wc.hInstance = hi
wc.hIcon = 0
wc.hCursor = LoadCursorW(0, IDC_ARROW)
wc.hbrBackground = COLOR_WINDOW + 1
wc.lpszMenuName = 0
wc.lpszClassName = _OFFSET(MainClassName)

at = RegisterClassA(_OFFSET(wc)): IF 0 = at THEN SYSTEM

t1 = "title" + CHR$(0)
hw = CreateWindowExA(0, at AND &HFFFF~&, _OFFSET(t1), WS_HSCROLL OR WS_OVERLAPPEDWINDOW OR WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hi, 0): IF 0 = hw THEN SYSTEM
t0 = "BUTTON" + CHR$(0)
t1 = "Button 0" + CHR$(0)
hwb0 = CreateWindowExA(0, _OFFSET(t0), _OFFSET(t1), WS_TABSTOP OR WS_VISIBLE OR WS_CHILD OR BS_PUSHBUTTON OR BS_TEXT, 10, 10, 150, 40, hw, 0, hi, 0): IF 0 = hw THEN SYSTEM
t1 = "Button 1" + CHR$(0)
hwb1 = CreateWindowExA(0, _OFFSET(t0), _OFFSET(t1), WS_TABSTOP OR WS_VISIBLE OR WS_CHILD OR BS_PUSHBUTTON OR BS_TEXT, 10, 60, 150, 40, hw, 0, hi, 0): IF 0 = hwb0 THEN SYSTEM
t1 = "Chk box" + CHR$(0)
hwcb = CreateWindowExA(0, _OFFSET(t0), _OFFSET(t1), WS_TABSTOP OR WS_VISIBLE OR WS_CHILD OR BS_AUTOCHECKBOX OR BS_TEXT, 10, 110, 150, 40, hw, 0, hi, 0): IF 0 = hwb1 THEN SYSTEM
t1 = "Group box" + CHR$(0)
hwgb = CreateWindowExA(0, _OFFSET(t0), _OFFSET(t1), WS_VISIBLE OR WS_CHILD OR BS_GROUPBOX OR BS_TEXT, 10, 160, 400, 80, hw, 0, hi, 0): IF 0 = hwgb THEN SYSTEM
t1 = "Radio 0" + CHR$(0)
hwr0 = CreateWindowExA(0, _OFFSET(t0), _OFFSET(t1), WS_TABSTOP OR WS_VISIBLE OR WS_CHILD OR BS_AUTORADIOBUTTON OR BS_TEXT, 10, 30, 150, 30, hwgb, 0, hi, 0): IF 0 = hwr0 THEN SYSTEM
t1 = "Radio 1" + CHR$(0)
hwr1 = CreateWindowExA(0, _OFFSET(t0), _OFFSET(t1), WS_TABSTOP OR WS_VISIBLE OR WS_CHILD OR BS_AUTORADIOBUTTON OR BS_TEXT, 210, 30, 150, 30, hwgb, 0, hi, 0): IF 0 = hwr1 THEN SYSTEM
t0 = "EDIT" + CHR$(0)
t1 = "This is a" + crlf + "multiline edit control." + crlf + "Click in me and type." + crlf + "It should scroll automatically in both directions, but there aren't any scroll bars." + crlf + "Close the window to see the text printed to the console." + CHR$(0)
hwe = CreateWindowExA(0, _OFFSET(t0), _OFFSET(t1), WS_TABSTOP OR WS_VISIBLE OR WS_CHILD OR ES_AUTOHSCROLL OR ES_AUTOVSCROLL OR ES_LEFT OR ES_MULTILINE OR ES_WANTRETURN, 10, 300, 400, 200, hw, 0, hi, 0): IF 0 = hwe THEN SYSTEM

discardb = ShowWindow(hw, SW_SHOWDEFAULT)
discardb = UpdateWindow(hw)
DO
 bRet = GetMessageA(_OFFSET(msg), 0, 0, 0)
 SELECT CASE bRet
  CASE 0, -1: EXIT DO
 END SELECT
 discardb = TranslateMessage(_OFFSET(msg))
 discardp = DispatchMessageA(_OFFSET(msg))
LOOP

_DELAY .5
' Hopefully the user is running this console program from the command prompt.
' If not, the half second delay should remind them.
' I think that Sleep is okay here, because I assume we shouldn't be getting any more messages.
' We're out of the message loop anyway...
SYSTEM

FUNCTION WindowProc%& (hWnd AS _OFFSET, uMsg AS _UNSIGNED LONG, wParam AS _UNSIGNED _OFFSET, lParam AS _OFFSET)

SELECT CASE uMsg

 CASE WM_CLOSE

  discardp = SendMessageA(hwe, WM_GETTEXT, LEN(buf), _OFFSET(buf))
  PRINT: PRINT "First part of the edit control text:": PRINT
  PRINT buf: PRINT
  PRINT "Radio 0: 0x"; HEX$(SendMessageA(hwr0, BM_GETCHECK, 0, 0))
  PRINT "Radio 1: 0x"; HEX$(SendMessageA(hwr1, BM_GETCHECK, 0, 0))

  WindowProc = DefWindowProcA(hWnd, uMsg, wParam, lParam): EXIT FUNCTION

 CASE WM_DESTROY

  PostQuitMessage 0
  WindowProc = 0: EXIT FUNCTION

 CASE WM_COMMAND

  IF wParam \ &H10000 = BN_CLICKED THEN
   SELECT CASE lParam
    CASE hwb0: PRINT "Button 0 pressed"
    CASE hwb1: PRINT "Button 1 pressed"
    CASE hwcb: PRINT "Check box pressed"

     ' The following two lines are useless, because the Group Box is getting the message, not us.
    CASE hwr0: PRINT "Radio 0 pressed"
    CASE hwr1: PRINT "Radio 1 pressed"
   END SELECT
   WindowProc = 0: EXIT FUNCTION
  ELSE
   WindowProc = DefWindowProcA(hWnd, uMsg, wParam, lParam): EXIT FUNCTION
  END IF

 CASE ELSE

  WindowProc = DefWindowProcA(hWnd, uMsg, wParam, lParam): EXIT FUNCTION
END SELECT

END FUNCTION

Edit: 2013 05 10

changed:
 return (void *) (& WindowProc);
to:
 return (void *) WindowProc;
As the function name is already a pointer.
« Last Edit: May 10, 2013, 03:34:23 AM by mcalkins »
The QBASIC Forum Community: http://www.network54.com/index/10167 Includes off-topic subforums.
QB64 Off-topic subforum: http://qb64offtopic.freeforums.org/

Clippy

  • Hero Member
  • *****
  • Posts: 16446
  • I LOVE π = 4 * ATN(1)    Use the QB64 WIKI >>>
    • Pete's Qbasic Site
    • Email
Re: GUI experimenting...
« Reply #1 on: September 12, 2012, 05:08:55 AM »
Nice! You found a bug too!  ;)

POINT shouldn't work as a TYPE

Do they come in colors?

SLEEP doesn't work in the console, but the delay can be longer.
QB64 WIKI: Main Page
Download Q-Basics Code Demo: Q-Basics.zip
Download QB64 BAT, IconAdder and VBS shortcuts: QB64BAT.zip
Download QB64 DLL files in a ZIP: Program64.zip

mcalkins

  • Hero Member
  • *****
  • Posts: 1279
    • qbasicmichael.com
    • Email
Re: GUI experimenting...
« Reply #2 on: September 12, 2012, 10:14:36 AM »
Do you mean the background of the window?

wc.hbrBackground = COLOR_WINDOW + 1

http://msdn.microsoft.com/en-us/library/ms633576%28v=vs.85%29
http://msdn.microsoft.com/en-us/library/dd183395%28v=vs.85%29

You can either load an HBRUSH, or you can use one of the COLOR_ constants + 1.

Here are some constants from winuser.h. I'm guessing the CTLCOLOR ones might be used somewhere else, but I'm including them anyway.

Code: [Select]
const CTLCOLOR_MSGBOX = 0
const CTLCOLOR_EDIT = 1
const CTLCOLOR_LISTBOX = 2
const CTLCOLOR_BTN = 3
const CTLCOLOR_DLG = 4
const CTLCOLOR_SCROLLBAR = 5
const CTLCOLOR_STATIC = 6
const CTLCOLOR_MAX = 7

const COLOR_SCROLLBAR = 0
const COLOR_BACKGROUND = 1
const COLOR_ACTIVECAPTION = 2
const COLOR_INACTIVECAPTION = 3
const COLOR_MENU = 4
const COLOR_WINDOW = 5
const COLOR_WINDOWFRAME = 6
const COLOR_MENUTEXT = 7
const COLOR_WINDOWTEXT = 8
const COLOR_CAPTIONTEXT = 9
const COLOR_ACTIVEBORDER = 10
const COLOR_INACTIVEBORDER = 11
const COLOR_APPWORKSPACE = 12
const COLOR_HIGHLIGHT = 13
const COLOR_HIGHLIGHTTEXT = 14
const COLOR_BTNFACE = 15
const COLOR_BTNSHADOW = 16
const COLOR_GRAYTEXT = 17
const COLOR_BTNTEXT = 18
const COLOR_INACTIVECAPTIONTEXT = 19
const COLOR_BTNHIGHLIGHT = 20

const COLOR_3DDKSHADOW = 21
const COLOR_3DLIGHT = 22
const COLOR_INFOTEXT = 23
const COLOR_INFOBK = 24

const COLOR_HOTLIGHT = 26
const COLOR_GRADIENTACTIVECAPTION = 27
const COLOR_GRADIENTINACTIVECAPTION = 28
const COLOR_MENUHILIGHT = 29
const COLOR_MENUBAR = 30

const COLOR_DESKTOP = COLOR_BACKGROUND
const COLOR_3DFACE = COLOR_BTNFACE
const COLOR_3DSHADOW = COLOR_BTNSHADOW
const COLOR_3DHIGHLIGHT = COLOR_BTNHIGHLIGHT
const COLOR_3DHILIGHT = COLOR_BTNHIGHLIGHT
const COLOR_BTNHILIGHT = COLOR_BTNHIGHLIGHT

For example,

wc.hbrBackground = COLOR_ACTIVECAPTION + 1

makes the window content blue for me, but it might be other colors for other people depending on what they have their title bar color set to.

It should be possible to customize the buttons also, even giving them icons, but I didn't spend any time reading about that kind of thing.

I meant the Windows Sleep function, which I called in the C++ version, and which is called by _DELAY in the QB64 version. You're not supposed to use Sleep from threads that create windows, but I'm assuming that it's okay, because the window should have been destroyed by then, and shouldn't (I assume) be getting any more messages. Since we're out of the message loop, they wouldn't be processed anyway.

Interesting that QB64's SLEEP doesn't work for consoles. It should be another addition to my console library...

Regards,
Michael
The QBASIC Forum Community: http://www.network54.com/index/10167 Includes off-topic subforums.
QB64 Off-topic subforum: http://qb64offtopic.freeforums.org/

  • Print