Goto page 1, 2, 3  Next

Subject: GUI skin (sort of)
I'm trying to use a bmp for the background of a window that will have controls. I've been able to do that but the problem I'm having is I can't close the window without using Ctrl+Alt+Del. Here is the code:

Code:

nomainwin

    open "WMLiberty" for dll as #wmlib

    loadbmp "skin", "bmp\skin.bmp"

    WindowWidth = 520
    WindowHeight = 400

    UpperLeftX=int((DisplayWidth-WindowWidth)/2)
    UpperLeftY=int((DisplayHeight-WindowHeight)/2)

    open "Skinned Window" for window_nf as #skin
    #skin "trapclose [QUIT]"

    callback lpfn, OnPaint ( ulong, ulong, ulong, ulong ), long

    hwndSkin = hwnd(#skin)

    calldll #wmlib, "SetWMHandler", _
        hwndSkin as ulong, _
        _WM_PAINT as ulong, _
        lpfn as ulong, _
        0 as long, _
        ret as long

    #skin "hide"
    #skin "show"


[LOOP]
    scan
    calldll #kernel32, "Sleep", _ 'Minimize CPU usage
        50 as long, _
        ret as void
    goto [LOOP]


[QUIT]
    close #skin
    close #wmlib
    end


function OnPaint(hwnd, uMsg, wParam, lParam)
    hdc = GetDC(hwnd)
    dcSkin = CreateCompatibleDC(hdc)
    r = SelectObject(dcSkin, hbmp("skin"))
    r = BitBlt(hdc, 0,0,520,400, dcSkin, 0, 0, _SRCCOPY)
    r = DeleteDC(dcSkin)
    r = ReleaseDC(hwnd, hdc)
    r = DeleteObject(hbmp("skin"))
end function

function GetDC(h)
    calldll #user32, "GetDC",_
        h as ulong,_ 'graphicbox handle
        GetDC as ulong 'returns handle to device context
end function

function ReleaseDC(h, hdc)
    calldll #user32, "ReleaseDC",_
        h as ulong,_    'window handle
        hdc as ulong,_  'device context
        ReleaseDC as long
end function

function DeleteDC(hDCM)
    calldll #gdi32, "DeleteDC", _
        hDCM as ulong, _
        DeleteDC as long
end function

function CreateCompatibleDC(hDC)
    calldll #gdi32, "CreateCompatibleDC", _
        hDC as ulong, _ 'current screen
        CreateCompatibleDC as ulong 'handle of memory DC
end function

function SelectObject(hDC,hImage)
    calldll #gdi32, "SelectObject", _
        hDC as ulong, _
        hImage as ulong, _
        SelectObject as ulong
end function

function DeleteObject(memBmp)
    calldll #gdi32, "DeleteObject", _
        memBmp as ulong, _
        DeleteObject as long
end function

function BitBlt(hDCdest, xDest, yDest, xWidth, yHeight, hDCsource, xSrc, ySrc, ROP)
    CallDll #gdi32, "BitBlt", _
        hDCdest as ulong,_ 'The destination DC
        xDest as long,_ 'x location on destination
        yDest as long,_ 'y location on destination
        xWidth as long,_ 'width to transfer
        yHeight as long,_ 'height to transfer
        hDCsource as ulong,_ 'The source DC
        xSrc as long,_ 'x location in source
        ySrc as long,_ 'y location in source
        ROP as ulong,_ 'The operation to be performed
        BitBlt as long 'nonzero if successful
end function


Here is a link to download the image: skin.bmp

Subject: Re: GUI skin (sort of)
Mattestion wrote:
I'm trying to use a bmp for the background of a window that will have controls.

This may be a silly question, but have you tried the simple approach of using a graphics window? I know the docs say "They are not intended to contain controls" and "some controls do not work properly" but you may find that in practice they work fine. I believe I'm right in saying that in LB Βooster any control which works in a window of type 'Window' will also work in a window of type 'Graphics'.

Richard.
http://lbbooster.com/

Subject: Re: GUI skin (sort of)
Hello and welcome,

Sorry about the slow response--bad thunderstorms here. Anyway, I think I found a way to do what you want.
Code:
struct ps,_ 'PAINTSTRUCT
    hdc as ulong, _
    fErase as long, _
    rcPaint.left as long, _
    rcPaint.top as long, _
    rcPaint.right as long, _
    rcPaint.bottom as long, _
    fRestore as long, _
    fIncUpdate as long, _
    rgbReserved as char[32]

    open "WMLiberty" for dll as #wmlib

    loadbmp "skin", "bmp\skin.bmp"

    WindowWidth = 520
    WindowHeight = 400

    UpperLeftX=int((DisplayWidth-WindowWidth)/2)
    UpperLeftY=int((DisplayHeight-WindowHeight)/2)

    open "Skinned Window" for window_nf as #skin
    #skin "trapclose [QUIT]"

    callback lpfn, OnPaint ( ulong, ulong, ulong, ulong ), long

    hwndSkin = hwnd(#skin)

    calldll #wmlib, "SetWMHandler", _
        hwndSkin as ulong, _
        _WM_PAINT as ulong, _
        lpfn as ulong, _
        0 as long, _
        ret as long

    Call EraseWindow hwnd(#skin)


[LOOP]
    scan
    calldll #kernel32, "Sleep", _ 'Minimize CPU usage
        50 as long, _
        ret as void
    goto [LOOP]


[QUIT]
    close #skin
    close #wmlib
    unloadbmp "skin"
    end


function OnPaint(hwnd, uMsg, wParam, lParam)
    hSkinBmp = hbmp("skin")
    dcSkin = CreateCompatibleDC(0)
    hOldBmp = SelectObject(dcSkin, hSkinBmp)
    CallDLL #user32, "BeginPaint", hwnd as ulong, ps as struct, ret as long
    r = BitBlt(ps.hdc.struct, 0,0,520,400, dcSkin, 0, 0, _SRCCOPY)
    CallDLL #user32, "EndPaint", hwnd as ulong, ps as struct, ret as long
    ret = DeleteObject(dcSkin)
 end function

function GetDC(h)
    calldll #user32, "GetDC",_
        h as ulong,_ 'graphicbox handle
        GetDC as ulong 'returns handle to device context
end function

function ReleaseDC(h, hdc)
    calldll #user32, "ReleaseDC",_
        h as ulong,_    'window handle
        hdc as ulong,_  'device context
        ReleaseDC as long
end function

function DeleteDC(hDCM)
    calldll #gdi32, "DeleteDC", _
        hDCM as ulong, _
        DeleteDC as long
end function

function CreateCompatibleDC(hDC)
    calldll #gdi32, "CreateCompatibleDC", _
        hDC as ulong, _ 'current screen
        CreateCompatibleDC as ulong 'handle of memory DC
end function

function SelectObject(hDC,hImage)
    calldll #gdi32, "SelectObject", _
        hDC as ulong, _
        hImage as ulong, _
        SelectObject as ulong
end function

function DeleteObject(memBmp)
    calldll #gdi32, "DeleteObject", _
        memBmp as ulong, _
        DeleteObject as long
end function

function BitBlt(hDCdest, xDest, yDest, xWidth, yHeight, hDCsource, xSrc, ySrc, ROP)
    CallDll #gdi32, "BitBlt", _
        hDCdest as ulong,_ 'The destination DC
        xDest as long,_ 'x location on destination
        yDest as long,_ 'y location on destination
        xWidth as long,_ 'width to transfer
        yHeight as long,_ 'height to transfer
        hDCsource as ulong,_ 'The source DC
        xSrc as long,_ 'x location in source
        ySrc as long,_ 'y location in source
        ROP as ulong,_ 'The operation to be performed
        BitBlt as long 'nonzero if successful
end function

Sub EraseWindow hWnd
    flags = _RDW_ERASE Or _RDW_INVALIDATE
    CallDLL #user32, "RedrawWindow", _
        hWnd  as ulong, _
        _NULL  as ulong, _
        _NULL as ulong, _
        flags as ulong, _
        ret   as long
End Sub

Subject: Re: GUI skin (sort of)
Thanks, that works perfectly. Could you explain to me why this method works?

Subject: Re: GUI skin (sort of)
The EraseWindow API function forces a WM_PAINT message.

You will better succeed, if you get some information about handling GUI windows in plain ANSI C without using any GUI framework.

Subject: Re: GUI skin (sort of)
Mattestion wrote:
Thanks, that works perfectly.

Yes, it works in LBB too, somewhat to my surprise. What I don't understand, though, is why (in LB) you need this code instead of a simple wait:

Code:
[LOOP]
    scan
    calldll #kernel32, "Sleep", _ 'Minimize CPU usage
        50 as long, _
        ret as void
    goto [LOOP]

Substituting a wait appears to cause the program to ignore the trapclose and not to respond to the the close button. In LBB a wait works fine, but that's not surprising because internally it does exactly the same as the above loop (although it sleeps for only 1 ms).

And I still wonder what advantage this approach has over a graphics window. Is it true, as the docs imply, that some controls don't work properly, and if so which ones are they?

Richard.

Subject: Re: GUI skin (sort of)
The SCAN-loop is a requirement of using WMLiberty, so Brent will surly have the correct answer.

Static text controls do not work in a graphics control and some of the notifications for other controls are eaten by the graphics control, so the controls do not respond to user actions.

Subject: Re: GUI skin (sort of)
STPendl wrote:
Static text controls do not work in a graphics control and some of the notifications for other controls are eaten by the graphics control, so the controls do not respond to user actions.

Ah, OK. I'll have to add that to the list of advantages of LBB, because it uses exactly the same window class for both GRAPHICS and WINDOW, so should handle control notifications the same way.

Richard.

Subject: Re: GUI skin (sort of)
STPendl wrote:
Static text controls do not work in a graphics control.

Actually as far as I can see they do work, so long as you force an initial redraw (which you can do for example using a font command):

Code:
  statictext #main.st, " Static text ", 40, 40, 240, 60
  open "Statictext in a graphics window" for graphics_nsb as #main
  #main "down; backcolor blue; boxfilled 320 340; flush"
  #main.st "!font Arial 36"
  wait

However you can't change the colour, so that might be one reason why this isn't an acceptable approach.

Richard.

Subject: Re: GUI skin (sort of)
STPendl wrote:
some of the notifications for other controls are eaten by the graphics control.

I haven't managed to find any notifications that are 'eaten' by the graphics window; this is the program I used:

Code:
  nomainwin

  array$(1) = "Some"
  array$(2) = "items"
  array$(3) = "for"
  array$(4) = "the"
  array$(5) = "Combobox"
  array$(6) = "and"
  array$(7) = "Listbox"

  button #main.button, "Button", Notify, UR, 40, 10
  checkbox #main.checkbox, "Checkbox", Notify, Notify, 10, 10, 120, 20
  combobox #main.combobox, array$(), Notify, 10, 50, 120, 130
  listbox #main.listbox, array$(), Notify, 160, 50, 120, 130
  radiobutton #main.radiobutton1, "Radiobutton 1", Notify, Notify, 10, 200, 120, 20
  radiobutton #main.radiobutton2, "Radiobutton 2", Notify, Notify, 160, 200, 120, 20

  open "Notifications in a graphics window" for graphics_nsb as #main
  #main "down; backcolor blue; boxfilled 320 340; flush"
  #main "trapclose [Quit]"
  wait

[Quit]
  close #main
  end

sub Notify handle$
  notice handle$
end sub

I wonder if this is yet another example of something which used to be the case in an earlier version of LB but no longer is, but the help file hasn't been updated.

Richard.

Subject: Re: GUI skin (sort of)
With respect to WAIT not working with callbacks, I can only guess the reason. I seem to recall that when callbacks were added, Carl said the functionality was in a Smalltalk library. It may be that that library makes some assumptions about how callbacks are used. There might be more than one event loop, or maybe there's a flag that the WAIT statement doesn't set which causes LB to ignore events when it is in "callback mode."

Subject: Re: GUI skin (sort of)
Brent wrote:
Code:
    ret = DeleteObject(dcSkin)
 end function

Shouldn't that be DeleteDC rather than DeleteObject?

Code:
    ret = DeleteDC(dcSkin)
 end function

Richard.

Subject: Re: GUI skin (sort of)
RichardRussell wrote:
Shouldn't that be DeleteDC rather than DeleteObject?

http://msdn.microsoft.com/en-us/library/dd183489%28v=vs.85%29.aspx
In CreateCompatibleDC, MSDN wrote:
When you no longer need the memory DC, call the DeleteDC function. We recommend that you call DeleteDC to delete the DC. However, you can also call DeleteObject with the HDC to delete the DC.

Subject: Re: GUI skin (sort of)
Brent wrote:
In CreateCompatibleDC, MSDN wrote:
We recommend that you call DeleteDC to delete the DC. However, you can also call DeleteObject.

MSDN at its worst! If DeleteDC is recommended why would one ever use anything else? This wording (which is a recent addition) is possibly because current versions of Windows (2000 onwards) have accepted either, whereas earlier ones may have accepted only DeleteDC.

Richard.

Subject: Re: GUI skin (sort of)
RichardRussell wrote:
If DeleteDC is recommended why would one ever use anything else?
Richard.


Why not? DeleteObject works on many graphics objects, such as pen, brush, font, bitmap, region, and palette. The programmer only needs to remember the syntax for a single API call. Also, if APIs are wrapped in user-functions, one function is all that is needed and can be called many times.

That argument is off-topic for this thread, however. Brent did not make an error in his code and that is all that is pertinent to the OP.

Regarding Richard's message, "I haven't managed to find any notifications that are 'eaten' by the graphics window; this is the program I used: " I tried the code. I added to it and "setfocus" to the graphics window to trap user events. I added graphics statements to trap mouse events and keypresses. Even with the added focus and traps, the controls appeared to work correctly. It may be that the caveat against putting controls over graphics is no longer needed, but before I'd count on that, I'd try it with a graphicbox instead of a graphics window, and I'd test it on different versions of Windows. I never use a graphics window, other than for short demos. I use a graphicbox inside a regular window, which gives me more control and flexibility.

Goto page 1, 2, 3  Next

Page 1 of 3


Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum

Full Version
Powered by phpBB © phpBB Group
Design by phpBBXS.Com | Lo-Fi Mod.