View Full Version : Function Not Working & Dialog Disappears
marcuslee
23-03-2009, 02:46
I am having at least two problems with a script I am putting together. I have pieced this together with a couple scripts from the community and added a few things myself.
First of all, here is the entire script:
USES "UI"
DECLARE FUNCTION DestroyWindow LIB "user32.dll" ALIAS "DestroyWindow" ( BYVAL hWnd AS LONG ) AS LONG
DECLARE FUNCTION pixelLong LIB "GDI32.DLL" ALIAS "GetPixel" ( hDlg AS DWORD, xVar AS LONG, yVar AS LONG ) AS LONG
GLOBAL hDlg AS LONG
%IMAGE_BITMAP = 0
%STM_SETIMAGE = &H172
DIM JPGFileName AS STRING = APP_SOURCEPATH + "Images\Body.png"
DIM pixel2, xVar, yVar, x AS LONG
DIM hBitmap, hGpBitmap AS LONG
'FUNCTION TBMAIN( )
IF USES( "GDIP" ) <= 0 THEN
MSGBOX 0, "GDI+ lib not found"
STOP
END IF
DIALOG NEW PIXELS, 0, "thinBasic using GDI+", - 1, - 1, 400, 638, _
%WS_DLGFRAME OR _
%DS_CENTER OR _
%WS_CAPTION OR _
%WS_SYSMENU OR _
%WS_OVERLAPPEDWINDOW, _
0 TO hDlg
DIALOG SHOW MODELESS hDlg, CALL mainProc( )
'END FUNCTION
CALLBACK FUNCTION mainProc( ) AS LONG
SELECT CASE CBMSG
CASE %WM_INITDIALOG
CONTROL ADD LABEL, hDlg, 1001, "", 0, 0, 400, 310, %SS_BITMAP
'---Create an image handle
hGpBitmap = GDIp_CreateBitMapFromFile( JPGFileName )
'---Convert to a BMP handle
hBitmap = GDIP_HBitMapFromBitmap( hGpBitmap )
CONTROL SEND hDlg, 1001, %STM_SETIMAGE, %IMAGE_BITMAP, hBitmap
CONTROL REDRAW hDlg, 1001
xVar = 111
yVar = 100
pixel2 = pixelLong( hDlg, xVar, yVar )
x = MSGBOX( 0, pixel2 )
RETURN( 1 )
CASE %WM_SYSCOMMAND
SELECT CASE CBCTL
CASE %SC_CLOSE
IF MSGBOX( 0, "Are you sure you want to exit the program?", %MB_YESNO OR %MB_ICONQUESTION, "CONFIRM EXIT" ) = %IDYES THEN
SENDMESSAGE( hDlg, %WM_CLOSE, 0, 0 )
END IF
RETURN( 1 )
END SELECT
CASE %WM_CLOSE
DestroyWindow( hDlg )
RETURN( 1 )
CASE %WM_DESTROY
END SELECT
END FUNCTION
I am having trouble with the pixelLong function. I'm missing something there because I think the response with the message box shouldn't be -1, which is what I am getting.
Second problem is that the dialog window appears and then disappears right after the message box. I'm a little stumped, and I am tired. So, I will let someone else have a crack at it. I'm going to bed. Good night all!
Mark
P.S. - The zip contains the TB file as well as the image I am using to test it.
Petr Schreiber
23-03-2009, 08:02
Hi,
there were few problems:
- dialog should be MODAL, no MODELESS
- GetPixel takes hDC ( device handle), not hDlg ( dialog handle ) as input
- DestroyWindow is not necessary, DIALOG END will do the job
- getting pixel color during dialog creation is not reliable, dialog is not "ready" at the time
I attach new file, where GetPixel returns at least something :), but still not what you want.
You do not need to use control 1001 for drawing, there are other GDIP commands that will make what you want.
In plain API it would be something like:
Local pImage, pTextureBrush AS DWORD
'...
strFileName = UCODE$(fName)
GdipLoadImageFromFile(STRPTR(strFileName), pImage)
GdipCreateTexture(pImage, %WrapModeClamp, pTextureBrush)
'... then in WM_PAINT
GdipCreateFromHDC(hDc, pGraphics)
GdipFillRectangleI(pGraphics, pTextureBrush, 0, 0, 317, 623)
IF pGraphics THEN GdipDeleteGraphics(pGraphics)
' ... then in WM_Close
IF pImage THEN
GdipDisposeImage(pImage)
pImage = 0
END IF
IF pTextureBrush THEN
GdipDeleteBrush(pTextureBrush)
pTextureBrush = 0
END IF
I am short in time, so could not test it, so attached file does not handle that.
Petr
marcuslee
25-03-2009, 02:46
Thank you, Petr. Your changes fixed the problem. I haven't had a chance to look at your GDIP stuff (but, I will soon). I've made a little further progress on the script. I've hit another wall, though.
I am trying to get the script to know where the cursor is in relation to the image. Then, I will use a data file to tell the script about the image. If that doesn't make sense, don't worry. It will when I get to that stage. Of course, in the mean time, y'all might find a better way to do this. Isn't solving problems fun?
Anyway, I'm using the GetCursorPos function, and it is returning the coordinate as it is designed (at least I copied everything correctly ... whew!) but it is returning the position of the mouse in relation to the screen, not the window/image. What I want is ... no matter where the window is placed on screen, the script will return the same values. The top left corner of the image should be coordinate 0:0. (x=0 and y=0)
Any ideas?
Here's the part of the script where I call the GetCursorPos Function:
CASE %WM_LBUTTONUP
CONTROL SEND hDlg, 1001, %STM_SETIMAGE, %IMAGE_BITMAP, hBitmap2
CONTROL REDRAW hDlg, 1001
GetCursorPos( MyMouse )
MSGBOX( CBHNDL, MyMouse.x )
And here's the latest version of the entire script:
#MINVERSION 1.7.0.0
#SCRIPTVERSION 1.0.0.1
USES "UI"
TYPE POINT
X AS LONG
Y AS LONG
END TYPE
DECLARE FUNCTION GetPixel LIB "GDI32.DLL" ALIAS "GetPixel" ( BYVAL hdc AS DWORD, BYVAL x AS LONG, BYVAL y AS LONG ) AS DWORD
DECLARE FUNCTION GetDC LIB "USER32.DLL" ALIAS "GetDC" ( BYVAL hWnd AS DWORD ) AS DWORD
DECLARE FUNCTION GetCursorPos LIB "USER32.DLL" ALIAS "GetCursorPos" ( lpPoint AS POINT ) AS LONG
GLOBAL hDlg, hMenu, hMenuFile, hWndChild AS LONG
%IMAGE_BITMAP = 0
%STM_SETIMAGE = &H172
DIM JPGFileName AS STRING = APP_SOURCEPATH + "Images\Body.png"
DIM JPGFileName2 AS STRING = APP_SOURCEPATH + "Images\Body2.png"
DIM pixel2, xVar, yVar, x AS LONG
DIM hBitmap, hGpBitmap, hBitmap2, hGpBitmap2 AS LONG
DIM MyMouse AS POINT
FUNCTION TBMAIN( )
IF USES( "GDIP" ) <= 0 THEN
MSGBOX 0, "GDI+ lib not found"
STOP
END IF
DIALOG NEW PIXELS, 0, "thinBasic using GDI+", - 1, - 1, 400, 638, _
%WS_DLGFRAME OR _
%DS_CENTER OR _
%WS_CAPTION OR _
%WS_SYSMENU OR _
%WS_OVERLAPPEDWINDOW, _
0 TO hDlg
DIALOG SHOW MODAL hDlg, CALL mainProc( )
END FUNCTION
CALLBACK FUNCTION mainProc( ) AS LONG
SELECT CASE CBMSG
CASE %WM_INITDIALOG
CONTROL ADD LABEL, hDlg, 1001, "", 0, 0, 400, 310, %SS_BITMAP
'---Create an image handle
hGpBitmap = GDIp_CreateBitMapFromFile( JPGFileName )
'---Convert to a BMP handle
hBitmap = GDIP_HBitMapFromBitmap( hGpBitmap )
'---Create an image handle
hGpBitmap2 = GDIp_CreateBitMapFromFile( JPGFileName2 )
'---Convert to a BMP handle
hBitmap2 = GDIP_HBitMapFromBitmap( hGpBitmap2 )
CONTROL SEND hDlg, 1001, %STM_SETIMAGE, %IMAGE_BITMAP, hBitmap2
CONTROL REDRAW hDlg, 1001
CASE %WM_LBUTTONDOWN
CONTROL SEND hDlg, 1001, %STM_SETIMAGE, %IMAGE_BITMAP, hBitmap
CONTROL REDRAW hDlg, 1001
'xVar = 111
'yVar = 100
'local h as dword
'control handle hDlg, 1001 to h
'local hDc as dword = GetDC(h)
'pixel2 = GetPixel(hDc, xVar, yVar)
'msgbox(cbhndl,pixel2)
CASE %WM_LBUTTONUP
CONTROL SEND hDlg, 1001, %STM_SETIMAGE, %IMAGE_BITMAP, hBitmap2
CONTROL REDRAW hDlg, 1001
GetCursorPos( MyMouse )
MSGBOX( CBHNDL, MyMouse.x )
CASE %WM_SYSCOMMAND
SELECT CASE CBCTL
CASE %SC_CLOSE
IF MSGBOX( 0, "Are you sure you want to exit the program?", %MB_YESNO OR %MB_ICONQUESTION, "CONFIRM EXIT" ) = %IDYES THEN
DIALOG END CBHNDL
END IF
RETURN( 1 )
END SELECT
END SELECT
END FUNCTION
The Zip Attachment contains this latest version.
Mark
EDIT: By the way, since I am asking something completely different from the original question, this topic can be split up if you think that it would work better as two. These probably won't be the last questions I ask about this script. I just didn't know how many topics you want me to start ... when it pertains to the same script.
Petr Schreiber
25-03-2009, 08:19
Marc,
solution to mouse coordinates principle is very simple.
First, declare this API:
DECLARE FUNCTION ScreenToClient LIB "USER32.DLL" ALIAS "ScreenToClient" (BYVAL hWnd AS DWORD, lpPoint AS POINT) AS LONG
Then, in WM_LButtonUp use:
CASE %WM_LBUTTONUP
CONTROL SEND hDlg, 1001, %STM_SETIMAGE, %IMAGE_BITMAP, hBitmap2
control redraw hDlg, 1001
GetCursorPos(MyMouse)
ScreenToClient(cbhndl, MyMouse) ' <- converts global coords to dialog local ones
msgbox(cbhndl, MyMouse.x)
You could also ThinBasify the code to look like:
CASE %WM_LBUTTONUP
CONTROL SEND hDlg, 1001, %STM_SETIMAGE, %IMAGE_BITMAP, hBitmap2
control redraw hDlg, 1001
WIN_GetCursorPos(MyMouse)
WIN_ScreenToClient(cbhndl, MyMouse) ' <- converts global coords to dialog local ones
msgbox(cbhndl, MyMouse.x)
... and you don't need to declare the functions.
Petr
marcuslee
25-03-2009, 09:29
solution to mouse coordinates principle is very simple.
Yes, it was very simple. Thank you.
You could also ThinBasify the code
I like that. "ThinBasify"
Just brainstorming here. Haven't actually encountered this problem or situation. Just wondering about it. The ScreenToClient function works with the window, so as long as the image is in the upper left corner of the window, the coordinates will be correct, methinks. However, what if the image isn't in the upper left corner of the window? Is there an easy way to align the coordinates?
While I was typing that, I think I just answered my own question. If I know the position of the image (which I should since I would have programmed it) in relation to the corner of the window, I can adjust the coordinates to match.
For example, if the image is set 100 pixels to the right, then:
WIN_GetCursorPos(MyMouse)
WIN_ScreenToClient(cbhndl, MyMouse)
xVar = MyMouse.x - 100
msgbox(cbhndl, xVar)
Or, something similar.
I love making progress. Now, I have to get ready for work. But, I can't wait to make some more progress.
Mark
Petr Schreiber
25-03-2009, 10:35
Hi Marc,
yes, that is right way and spirit :)
I think I found the solution to clickable colors and easy image management.
Look inside only when not sure how to continue, exploring the way how to do it is the nicest part of programming!
Petr
marcuslee
27-03-2009, 04:59
Look inside only when not sure how to continue, exploring the way how to do it is the nicest part of programming!
Okay, I couldn't NOT look. In fact, I had to look. That's okay. I was stumped as soon as I tried to put the next piece together.
Here's the info: I am using a Data File named Body.dat to tell the program what body part that pixel represents. I have already built the data file using Liberty Basic. Translating that script so that I can write these data files in Thinbasic will be another task for another day ... if I decide to still go that route.
Anyway, I can't get the info out of the data file. I've tried two methods: File_Get and File_Load. Neither seem to work.
Here's the code:
DIM DataFile AS DWORD
DIM Status AS DWORD
DIM FileName AS STRING
DIM RecordNum AS INTEGER
DIM BodyPart AS INTEGER
DIM LoadedFile AS STRING
' -- Open Data File
FileName = APP_SCRIPTPATH + "Body.dat"
DataFile = FILE_OPEN( FileName, "Random" )
CASE %WM_LBUTTONDOWN
' -- Geting global coords
WIN_GETCURSORPOS( MyMouse )
' -- Getting image local coordinates
tImage_TransformMouse( Image1, CBHNDL, MyMouse )
' -- Calculate RecordNum (where in the data file the pixel info is kept)
IF MyMouse.Y > 0 THEN RecordNum = ( MyMouse.Y * 317 ) + MyMouse.X + 1
IF MyMouse.Y = 0 THEN RecordNum = MyMouse.X + 1
' -- Retrieve info from data file
LoadedFile = FILE_LOAD( DataFile )
BodyPart = MID$( LoadedFile, RecordNum, 1 )
'Status = File_Seek(DataFile, RecordNum)
'BodyPart = File_Get(DataFile, 1)
SELECT CASE BodyPart
CASE "0"
tImage_Render( Image7, CBHNDL )
CASE "1"
tImage_Render( Image10, CBHNDL )
'And so on ... there are more cases in the full file.
CONSOLE_WRITE LoadedFile
Any ideas?
marcuslee
27-03-2009, 13:11
I thought it might be helpful if you could see a final version of this. I do have one, written in Liberty Basic. I think I compiled it correctly. It should run on anyone's machine. Give it try.
Mark
EDIT: The original source code files are in the zip as well ... in case anyone wants to examine them.
Petr Schreiber
27-03-2009, 15:23
Hi,
just few issues:
- You defined body part as integer, this could never take value of "n"
- Integer in ThinBasic is 16bit integer, what you needed for recordnum is Long ( 32bit integer )
- FILE_LOAD is all you need - it loads whole file to string, no need to struggle with handles
Try this version, on my PC it works:
#MINVERSION 1.7.0.0
#SCRIPTVERSION 1.0.0.1
USES "UI"
Uses "FILE"
Uses "Console"
TYPE POINT
X AS LONG
Y AS LONG
END TYPE
DECLARE FUNCTION GetPixel LIB "GDI32.DLL" ALIAS "GetPixel" (BYVAL hdc AS DWORD, BYVAL x AS LONG, BYVAL y AS LONG) AS DWORD
DECLARE FUNCTION GetDC LIB "USER32.DLL" ALIAS "GetDC" (BYVAL hWnd AS DWORD) AS DWORD
DECLARE FUNCTION GetCursorPos LIB "USER32.DLL" ALIAS "GetCursorPos" (lpPoint AS POINT) AS LONG
DECLARE FUNCTION ScreenToClient LIB "USER32.DLL" ALIAS "ScreenToClient" (BYVAL hWnd AS DWORD, lpPoint AS POINT) AS LONG
GLOBAL hDlg, hMenu, hMenuFile, hWndChild AS LONG
TYPE tBodyPart
fileName as string
bodyPart as string
colorCode as long
END TYPE
dim PNGFileName as string = App_SourcePath + "Images\Body2.png"
dim PNGFileName2 as string = App_SourcePath + "Images\Body.png"
dim PNGFileName3 as string = App_SourcePath + "Images\Body_Arms.png"
dim PNGFileName4 as string = App_SourcePath + "Images\Body_Chest.png"
dim PNGFileName5 as string = App_SourcePath + "Images\Body_Feet.png"
dim PNGFileName6 as string = App_SourcePath + "Images\Body_Hands.png"
dim PNGFileName7 as string = App_SourcePath + "Images\Body_Head.png"
dim PNGFileName8 as string = App_SourcePath + "Images\Body_Hips.png"
dim PNGFileName9 as string = App_SourcePath + "Images\Body_Legs.png"
dim PNGFileName10 as string = App_SourcePath + "Images\Body_Neck.png"
dim PNGFileName11 as string = App_SourcePath + "Images\Body_Shoulders.png"
dim PNGFileName12 as string = App_SourcePath + "Images\Body_Stomach.png"
dim Status as DWORD
dim FileName as String
dim RecordNum as long
dim BodyPart as STRING
dim LoadedFile as String
dim pixel2, xVar, yVar, x as long
DIM hBitmap, hGpBitmap, hBitmap2, hGpBitmap2 AS LONG
DIM MyMouse AS POINT
FUNCTION TBMAIN( )
if uses("GDIP") <= 0 then
msgbox 0, "GDI+ lib not found"
stop
end if
DIALOG NEW pixels, 0, "thinBasic using GDI+", -1, -1, 400, 638, _
%WS_DLGFRAME OR _
%DS_CENTER OR _
%WS_CAPTION OR _
%WS_SYSMENU OR _
%WS_OVERLAPPEDWINDOW, _
0 TO hDlg
DIALOG SHOW MODAL hDlg, CALL mainProc( )
END FUNCTION
CALLBACK FUNCTION mainProc( ) AS LONG
static FileContents as string
SELECT CASE CBMSG
Case %WM_INITDIALOG
' -- Loading images using our functions
tImage_Load(Image1, PNGFileName)
tImage_Load(Image2, PNGFileName2)
tImage_Load(Image3, PNGFileName3)
tImage_Load(Image4, PNGFileName4)
tImage_Load(Image5, PNGFileName5)
tImage_Load(Image6, PNGFileName6)
tImage_Load(Image7, PNGFileName7)
tImage_Load(Image8, PNGFileName8)
tImage_Load(Image9, PNGFileName9)
tImage_Load(Image10, PNGFileName10)
tImage_Load(Image11, PNGFileName11)
tImage_Load(Image12, PNGFileName12)
' -- Positioning them
tImage_SetPos(Image1, 10, 10)
tImage_SetPos(Image2, 10, 10)
tImage_SetPos(Image3, 10, 10)
tImage_SetPos(Image4, 10, 10)
tImage_SetPos(Image5, 10, 10)
tImage_SetPos(Image6, 10, 10)
tImage_SetPos(Image7, 10, 10)
tImage_SetPos(Image8, 10, 10)
tImage_SetPos(Image9, 10, 10)
tImage_SetPos(Image10, 10, 10)
tImage_SetPos(Image11, 10, 10)
tImage_SetPos(Image12, 10, 10)
' -- Open Data File
FileName = APP_SOURCEPATH + "Body.dat"
FileContents = File_Load(FileName)
case %WM_PAINT
' -- Rendering Image1
tImage_Render(Image1, cbhndl)
Case %WM_LBUTTONDOWN
' -- Geting global coords
win_GetCursorPos(MyMouse)
' -- Getting image local coordinates
tImage_TransformMouse(Image1, cbhndl, MyMouse)
' -- Calculate RecordNum (where in the data file the pixel info is kept)
if MyMouse.Y > 0 then RecordNum = (MyMouse.Y * 317) + MyMouse.X
if MyMouse.Y = 0 then RecordNum = MyMouse.X
incr RecordNum
' -- Retrieve info from data file
BodyPart = Mid$(FileContents, RecordNum, 1)
'Status = File_Seek(DataFile, RecordNum)
'BodyPart = File_Get(DataFile, 1)
Select Case BodyPart
Case "0"
tImage_Render(Image7, cbhndl)
Case "1"
tImage_Render(Image10, cbhndl)
Case "2"
tImage_Render(Image11, cbhndl)
Case "3"
tImage_Render(Image4, cbhndl)
Case "4"
tImage_Render(Image3, cbhndl)
Case "5"
tImage_Render(Image6, cbhndl)
Case "6"
tImage_Render(Image12, cbhndl)
Case "7"
tImage_Render(Image8, cbhndl)
Case "8"
tImage_Render(Image9, cbhndl)
Case "9"
tImage_Render(Image5, cbhndl)
End Select
CASE %WM_LBUTTONUP
Console_Write LoadedFile
' -- Rendering Image 1
tImage_Render(Image1, cbhndl)
' -- Getting color
'local hDc as dword = GetDC(cbhndl)
'pixel2 = GetPixel(hDc, MyMouse.x+Image1.posX, MyMouse.y+Image1.posY)
'msgbox(cbhndl, "Clicked at"+STR$(MyMouse.x)+STR$(MyMouse.y)+$CRLF+"Color:"+RGBToString(pixel2))
CASE %WM_SYSCOMMAND
SELECT CASE CBCTL
CASE %SC_CLOSE
IF MSGBOX( 0, "Are you sure you want to exit the program?", %MB_YESNO OR %MB_ICONQUESTION, "CONFIRM EXIT" ) = %IDYES THEN
' -- Do not forget to clean up resources
tImage_Clear(Image1)
tImage_Clear(Image2)
tImage_Clear(Image3)
tImage_Clear(Image4)
tImage_Clear(Image5)
tImage_Clear(Image6)
tImage_Clear(Image7)
tImage_Clear(Image8)
tImage_Clear(Image9)
tImage_Clear(Image10)
tImage_Clear(Image11)
tImage_Clear(Image12)
DIALOG END CBHNDL
END IF
RETURN( 1 )
END SELECT
END SELECT
END FUNCTION
' -- Auxiliary function
function RGBToString( rgbval as long ) as string
dim RGB_Bytes(4) as byte at varptr(rgbval)
function = "("+RGB_Bytes(1)+","+RGB_Bytes(2)+","+RGB_Bytes(3)+")"
end function
' -- Image handling functions
type tImage
fileName as string
pImage as dword
posX as long
posY as long
end type
global Image1, Image2, Image3, Image4, Image5, Image6 as tImage
global Image7, Image8, Image9, Image10, Image11, Image12 as tImage
function tImage_Load( myimage as tImage, fileName as string ) as long
myImage.fileName = fileName
myImage.pImage = Gdip_LoadImageFromFile(fileName)
end function
function tImage_SetPos(myimage as tImage, x as long, y as long)
myImage.posX = x
myImage.posY = y
end function
function tImage_TransformMouse(myimage as tImage, hDlg as dword, mouse as POINT)
WIN_ScreenToClient(hDlg, mouse)
mouse.x -= myImage.posX
mouse.y -= myImage.posY
end function
function tImage_Render(myimage as tImage, hDlg as dword )
dim pGraphics as dword
pGraphics = Gdip_CreateFromHDC(GetDC(hDlg))
Gdip_DrawImage(pGraphics, myimage.pImage, myImage.posX, myImage.posY)
IF pGraphics THEN Gdip_DeleteGraphics(pGraphics)
end function
sub tImage_Clear( myimage as tImage )
IF myimage.pImage THEN Gdip_DisposeImage(myimage.pImage)
end sub
Petr