Paul,
Is adding a new control that is not based on any other control hard to do.
Especially considering I know nothing about C.
I looked in EBasic source for addcontrol etc.
Don't have a clue about the dlgtemplate thingy or class.
With my limited skill set would you just suggest I find something else to get involved in?
For the sake of arguement let's say I wanted a control that was a round gage that you'd pass range, units, high and low alarm limits name and current pointer location to and it in turn would send low and high alarm messages when the alarm limits are exceeded.
Larry
I would like to join in this request.
I have been experimenting with this for a while (in Aurora) and even got some results but an explanation/tutorial from the master would be very appreciated.
Haim
Saw the post, still thinking about the best way to answer ;)
I guess it depends on what you want the control for. If it is just for your own programs then just create yourself a window, without a caption, and go for it. If you want to share the control with other languages then it gets a bit more complicated, you have to create a DLL, register a system wide control class, handle certain messages, etc.
Paul.
I had thought about using a window(since I discovered how to make no rectangle windows).
Then there's the problem of fixin the position of multiple windows on top of the other and not running into focus and positioning issues.
The "window "docking' example takes care of the positioning issue, I think.
Then comes the non-standard messages I would need to send to the main window handler.
I think I can use sendmessage for that but haven't looked into that.
Also, my new control would have to do its "thing" based on a timer in its own handler.
That's were the sendmessage would be created and sent to the main window.
On top of all that there's the fact that I would want to create the new control as a oop class.
That raises another issue of how to automatically trigger the closing of my "control" windows when the main window is closed; without the class user have to hardcode the closing of each of my controls individually.
Have no idea about that?
Does that sound anywhere near close and doable?
Larry
In the old forum CD I found a custom control for a "DrawPad" class.
Don't know if I'm smart enough to sort it out.
Would I need my own controlex routine to handle the different look?
Larry
ControlEx creates any registered control class. It is a generic function.
Quote from: Paul Turley on November 06, 2007, 09:45:16 PM
... have to create a DLL, register a system wide control class, handle certain messages, etc.
I can handle making a dll ( I could share it with other EB users as a lib, couldn't I?)
In the dll/lib I'd have to have an "init" routine to be called at the beginning of the users program in order to "register" a system wide control class before the control was actually used; right? It's a one time deal?
Larry
Found where you create windows in the source code.
I seen where you use the global variable "main_atom" for registering a globalclass.
I seen that I can create my own "atom" so-to-speak to register my class which will keep the user from having to call an init routine.
I'm learning a little.
I've got the skeleton of my class built and I'm working on the drawing aspect of it now.
Larry
Having a problem with drawing my control.
Here's the code that paints my test control: PAINTSTRUCT ps
WINRECT rc
case WM_PAINT
_BeginPaint(hWnd, ps)
_GetClientRect(hWnd, rc)
hdc = _CreateCompatibleDC(ps.hdc)
hBitmap = _SelectObject(hdc, _CreateCompatibleBitmap(ps.hdc, rc.right, rc.bottom))
'set color of panel(background)
brush = _CreateSolidBrush(#pgagep.nPanelColor)
_FillRect(hdc, rc, (brush))
_DeleteObject(brush)
'draw outer gage ring
brush = _CreateSolidBrush(RGB(100, 100, 100))
oldBrush = _SelectObject(hdc,brush)
SetArcDirection(hdc, 2)
Arc(hdc, rc.left, rc.top, rc.right, rc.bottom, 0, 0, 0, 0)
Arc(hdc, rc.left+8, rc.top+8, rc.right-8, rc.bottom-8, 0, 0, 0, 0)
pixelcolor = GetPixelA(hdc,rc.left+3,(rc.bottom-rc.top)/2+rc.top)
ExtFloodFill(hdc,rc.left+3,(rc.bottom-rc.top)/2+rc.top,pixelcolor,1)
_DeleteObject(oldbrush)
'color center of gage
brush = _CreateSolidBrush(RGB(130, 130, 130))
oldBrush = _SelectObject(hdc,brush)
pixelcolor = GetPixelA(hdc,rc.left+100,rc.top+100)
ExtFloodFill(hdc,rc.left+100,rc.top+100,pixelcolor,1)
_DeleteObject(oldbrush)
_SetBkMode(hdc, TRANSPARENT)
DrawText(hdc, szText, wsprintf(szText, TEXT("%u%%"), INT(dPercent * 100)), &rc, DT_CENTER | DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER)
' _BitBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, hdc, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY)
' _StretchBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, (ps.rcPaint.right - ps.rcPaint.left)*.5, (ps.rcPaint.bottom - ps.rcPaint.top)*.5, hdc, ps.rcPaint.left, ps.rcPaint.top, (ps.rcPaint.right - ps.rcPaint.left), (ps.rcPaint.bottom - ps.rcPaint.top), SRCCOPY)
_DeleteObject(_SelectObject(hdc, hBitmap))
_DeleteDC(hdc)
_EndPaint(hWnd, ps)
return 0
Toward the bottom of the code are 2 lines that are remarked out: _BitBlt and _StretchBlt
If I compile with _BitBlt the routine works as I expect it to. (see P1.jpg)
If I minimize the window and then bring it back it still looks the same.
If I compile with _StretchBlt the routine works as I expect it to. It displays at 1/2 height and width (see P2.jpg)
However, if I minimize the window and then bring it back I get bleed-through (no redraw of the original part of the window that is not covered by the reduced image.(see P3.jpg)
I have no idea how to fix it or even if it is fixable or not.
Help
Edit: What I'm wanting to do is draw my control at one fixed size then scale it to fit the size requested in the calling add-control function.
What I think I need is:
1. one bitmap that is sized to height/width passed in by the add-control function.
2. another bitmap that is a fixed size that I do all my drawing to.
3. and then stretchblt the 2nd one into the first one
but I don't know how to do it.
Larry
If you are using a standard Ebasic window as the base for your control then the BeginPaint function is not necessary and will invalidate the update region for the window.
When @IDPAINT (WM_PAINT) is sent to your handler the DC has already been set up for you.
Paul.
I think I'm doing it from scratch.
if gage_atom=0
WNDCLASSEX wc
wc.cbSize = len(WNDCLASSEX)
wc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW
wc.lpfnWndProc = &Gage1Proc_LM
wc.cbClsExtra = 0
wc.cbWndExtra = 0
wc.hInstance = _hinstance
wc.hIcon = NULL
wc.hCursor = LoadCursor(NULL, IDC_ARROW)
wc.hbrBackground = NULL
wc.lpszMenuName = NULL
wc.lpszClassName = "LM_Gage1_Class"
wc.hIconSm = NULL
gage_atom=_RegisterClassEx(wc)
endif
sub AddGage(win as WINDOW,l as INT,t as INT,d as INT,id as UINT)
RegisterGage1Class()
CONTROLEX win,"LM_Gage1_Class","",l,t,d,d,0,0,id
return
endsub
sub Gage1Proc_LM(hWnd:UINT, uMsg:UINT, wParam:UINT, lParam:UINT),UINT
endsub
Like I said, it works fine except I don't know how to implement 2 bitmaps in that section of code.
Well you are doing it yourself,
Don't forget you need to handle background updates as well. WM_PAINT is for the foreground, WM_ERASEBKGRND is for drawing the areas that the control doesn't occupy. Since your class doesn't have a background brush then you'll need to do it. Or load a stock brush for wc.hbrBackground in your WNDCLASSEX structure.
....Which is why you see the undrawn areas when minimized/restored.
Paul.
Quote from: Paul Turley on December 07, 2007, 03:21:58 PM
... Or load a stock brush for wc.hbrBackground in your WNDCLASSEX structure.
Made no difference
Here's what it appears I'm trying to get around:
This bit of code creates a bitmap with user dims (from myadd-control command) say 0,0,150,150
_BeginPaint(hWnd, ps)
_GetClientRect(hWnd, rc)
hdc = _CreateCompatibleDC(ps.hdc)
hBitmap = _SelectObject(hdc, _CreateCompatibleBitmap(ps.hdc, rc.right, rc.bottom))If I use the stretchblt command I can scale the image (say by a 4th) but all I'm doing is is shrinking the image downin size but but the ps. DC has the original area so I'm only writing out to 1/4 of the screen and that's why I get the "bleed-through".
I see the solution as I need 2 bitmaps; a fixed size one to do all my writing to; and the variable sized one to scale the fixed size one into.
I just don't know how to do it yet.
Larry
Fill the background in response to WM_ERASEBKGRND like I suggested
Paul
I can do that but it won't solve my ultimate problem.
If I write over the area that isn't being rewrote because I shrunk the image then what will happen to a 2nd control that is located in that area that isn't being refresh with the 1st control.
My gage control is going to be a round indicator, with a round scale, with tic marks along that round scale. The range of the scale and units is set by the user.
Instead of having to do all the internal drawing with scale factors applied to sines and cosines I want to do all the internal calculations and drawing/text alignment and scaling with one fixed size rectangle which contains my gage (lets say 200X200 pixels) and one font size, etc.
Then, using stretchblt to to enlarge/reduce my internal bitmap to the bitmap that will be outputed to the screen at whatever size the user wanted.
When I can figure out how to implement 2 bitmaps inside the WM_paint routine ALL my problems will be resolved.
The "problem" I have now with the "bleed-thru" is because I'm not sending a big enough picture out to the screen to fill the area that was initialized into the ps structure. I say that because when I send an image out that is the same size as the user's requested size then everything works fine. So that "problem" is just a normal side effect of doing what I did. And that approach won't get me to where I want to go so the WM_ERASEBKGRND issue isn't relative.
Larry
OK so don't listen ::)
I've built more custom controls then you can shake a stick at. When you are handling the updates to your window you have to handle both the background and foreground. Unless the foreground covers the entire area. The WM_ERASEBKGRND message is sent by windows first, using the invalidated update region. Your handler is supposed to fill the entire client area with a brush or solid color at this point, if you don't then you will get the effect you are experiencing.
Then Windows sends the WM_PAINT message with the invalidated area for the foreground, in which case your windows is supposed to draw the foreground elements. Doesn't matter whether you use BitBlt or StretchBlt, that isn't the issue here.
You don't need two bitmaps for what you want to do. But hey, if you want to go to all the trouble don't let me stop you...you will need to create two separate DC's, two bitmaps, etc....just to mimick the same effect that Windows already is trying to do by sending you the WM_ERASEBKGRND.
To each their own.
Paul.
Quote from: Paul Turley on December 07, 2007, 06:19:09 PM
OK so don't listen ::).....To each their own.
I'm sure that you are 100% correct. I have stated numerous times before that I know absolutely nothing about C type coding.
I've gotten as far as I have with this effort via hours of looking at the SDK documentation that I downloaded and searching the internet and with an IBASIC progressbar program I found.
I promise that I won't furthur flaunt my ignorance by asking any more questions concerning MY difficulties in understanding.
I handled the WM_ERASEBKGRND and it took care of the "bleed thru".
However, it in no way got me closer to what I really wanted to do.
What I need to do is fool the wm_paint routine initially, when beginpaint is called, into thinking the client area is bigger than what it is.
While it is fooled do all my drawing then when I do the bitblt or stretchblt un-fool it and use the actual coordinates.
Stretchblt now simply puts a smaller version of the image in the client area.
I want to put a full size image in the client area but I wanted to do my drawing on a bigger version of the final image that is a predefined fixed size. It makes % of small pixel increments and fillrect based upon pixel location work better.
I don't know how to accomplish that on my own and I refuse to ask any other questions on this subject, therefore,
the whole matter has died a natural death.
Thanks for responding.
Larry
Larry,
You don't need to "fool" WM_PAINT. Create your bitmap as big as you want, it has nothing to do with the client size. You can then freely StretchBlt it into the device context.
hdc = _CreateCompatibleDC(NULL)
Will give you a device context without confines, select the oversized bitmap into it and draw to your hearts content. Then StretchBlt it into the paint DC.
Emergence's own window class uses this method for autodrawn windows. The internal bitmap is the same size as your screen, the client size doesn't affect the bitmap. You've got the source code, feel free to use it.
This isn't "C" type coding, it is Windows GDI programming. It isn't intuituve, and not for the feint of heat, it is the Microsoft way of doing things. It can be a real pain in the A** to do at times, but there are set guidelines on how to accomplish your goals.
I wanted you to listen, and start with WM_ERASEBKGRND, because you need to take GDI programming one step at a time. I don't have your source code, just the bits and peices you posted here. I don't even know if you are handling other messages properly. So my recommendations were meant to get you pointed in the right direction. And to solve your immeidate problem.
Setting a background brush in your class should have worked, the fact that it didn't means you are returning from Gage1Proc_LM improperly somewhere. Which was the next step in the progression of what I was trying to show you.
But anyway, since you have given up so quickly I will go back to my own coding.
Paul.
Paul,
Excuse the "bad hair" moment. My wife is dragging me through menopause "kicking and screaming"! ;)
(It's either that or I have started the trip through my 2nd childhood)
Quotehdc = _CreateCompatibleDC(NULL)
Will give you a device context without confines, select the oversized bitmap into it and draw to your hearts content. Then StretchBlt it into the paint DC.
That's the part I was missing AND in words I can understand. Going back, it was in the MSDN docs but just not where I could understand what I was looking at.
QuoteThis isn't "C" type coding, it is Windows GDI programming
Hey, if it ain't EBasic I put it all in the "C" type coding bit bucket. Just means I don't understand/like it.
At any rate, with your normal coding mastery, you have given me the help that I needed.
Hope to have something for others to look at in a few days.
Thanks again,
Larry
UPDATE:
The 2 DC / 2 BITMAP scheme works perfectly. It scales just the way I wanted it to work.
Larry
Ran into a problem with my gage control that I can't seem to find the answer to.
Curious if anyone has seen something act like the attached.
watch the gages cycle between 0 and 5. On the 10th cycle the graphics all go to black and white.
If I cycle between 0 and 10 it still takes the same amount of elapsed time for it to happen.(after the 5th cycle)
If I increase the number of gage controls it happens in fewer cycles. If I decrease the number of controls it goes a little longer before it happens.
And it is not a random duration. It repeats exactly.
Edit: Removed attachment and posted newer one below.
Larry
Believe I've found the problem.
I wasn't following the correct sequence to delete objects and clear handles for pens and brushes but was doing it correctly for regions and bitmaps.
The example quit displaying properly when it ran out of handles(or space for handles and their associated resources).
Now working on label and scale multiplier text.
Next will be figuring out how to properly display user defined scale range.
Larry
Making some headway on my gage control.
Attached is an updated demo.
The following is how it is setup:openwindow main, 0, 0, 660, 500, @CAPTION|@SYSMENU, 0, "Test", &mainHandler
setwindowcolor(main, GetSysColor(15))
AddGage(main,"Gage 1","lbs/hr", 40,21,50,0,100,-1,1,1, GAGE1 )
AddGage(main,"Gage 2","oz", 220,21,100,0,100,0,7,2, GAGE2 )
AddGage(main,"Gage 3",chr$(34)+"H20", 431,21,150,0,100,0,11,3, GAGE3 )
AddGage(main,"Gage 4","psi", 80,221,200,0,100,0,13,4, GAGE4 )
AddGage(main,"Gage 5","feet", 280,221,250,0,100,0,8,5, GAGE5 )
SetGageDialDark(main,GAGE4)
SENDMESSAGE(main, GAGE_SETPANEL_COLOR, RGB(255,0,0),0, GAGE3)
And the gages are updated in a timer routine in the example: for x=gage1 to gage5
SENDMESSAGE main, GAGE_SETPOS, percent, 0, x
next x
Got some cleanup to do before releasing a beta library.
Larry
Edit: removed attachment
Hi,
this is very impressive indeed!
looks great.
can't wait to see the completed control.
haim
Very Cool!
And impressive, looking forward to see more.
/Doug
Release of V1.0 of my Round Gage Control Library GageRLM
The included example contains all documentation.
Read "readme.txt" file before using.
NOTICE: This library works only with windows and NOT dialogs.
Larry
Revision: Removed download - Replaced below by Ver2.0
Good stuff, Larry - just tried it!
Brian
Thanks Brian
I still want to make a dual gage where the scale in down the center with the dial face arcs on each side and the pointer pivot points originating on the far left and right; kinda like \)|(/
Also want to make some rectangle gages (tall but thin) which I want to ultimately turn into
a PID proportional/integral/derivative closed loop controller faceplate.
Larry
I now know why my gage control works in a window but not in a dialog.
Controls in a dialog don't exist until domodal or showdialog is executed.
I'm using sendmessage to configure the gages before that happens in my current version.
To fix the problem will require a structural change to my implementation.
Just a heads up to anyone who might use my gages in an application.
The new library, when I get it done, will not be compatible with the current version.
Just part of my learning curve.
Also a big thanks to Sapero for his help.
Larry
Restructured implementation.
GageRLM Ver 2.0 now supports windows and dialogs.
Increased number of gages from 4 to 10.
Larry
Larry,
The dialog example works great!
I haven't done anything in EBasic, so this is most likely a silly mistake on my part.
I compiled and ran the dialog example, but the window example won't compile. The window example yields this:
Compiling...
GageRLM2_example.eba
File: D:\downloads\GageRLM2\GageRLM2_example.eba (681) Warning: undeclared function 'GetSysColor' - )
D:\downloads\GageRLM2\GageRLM2_example.eba:681: error: symbol `GetSysColor' undefined
D:\downloads\GageRLM2\GageRLM2_example.eba:960: error: phase error detected at end of assembly.
Error(s) in assembling D:\downloads\GageRLM2\GageRLM2_example.a
Put this in:
DECLARE "user32.dll",GetSysColor(nIndex:INT),INT
I have an .incc file that has that declared as a command.
Sorry about that.
Larry
thanks Larry,
I was looking for something like that. On of these days, I'm going to have to learn something about programming.
what other stuff do you have in that .incc?
works great thanks!
Quote from: John S on January 23, 2008, 02:50:49 PM
what other stuff do you have in that .incc?
It's a carry over from IBasic. I put some functions in an incc file as "command$" so I cound use the functions without having to declare them.
Works great with IBasic's PAK setup and/or when you're writting programs for yourself.
But as you saw it can cause problems if you use them in a non-compiled program for others.
Sorry about that.
Larry
Comming soon!
My Annunciator custom control.
Larry
Paul,
Almost afraid to ask. :-\
Do you have an example (source code) of a custom control (that is not based upon another standard control) that was written in I/Ebasic and starts out as a child window with some buttons/radiobuttons/text controls added to it that I can look at? :-[
Larry
Nothing short or public domain at the moment. I do have custom controls written in Emergence but they are not examples.
Did you have a question perhaps?
Paul.
Okay, here goes.
In my custom controls I've made so for I get the custom class registered and I have no problems with using GWL_USERDATA message to save the configuration of each instance of my control.
I have no problem with callinf sendmessage to handle specific (custom) things my controls can do.
I draw everthing in the client area of my control between _BeginPaint(hWnd, ps) and _EndPaint(hWnd, ps) using API calls and objects and all that.
I'm even using regions and mouse clicks inside regions to initiate actions.
What I don't understand is how to add a button, radio button, combobox, edit, etc control to be an integral part of my custom control and for me to be able to use all that built in fuctionallity. I'd like my control to have it's own integral timer etc.
Since I'm not creating a window in the normal EBasic sense I don't know where to start.
I'm hoping there is something simple I can do to accomplish what I want but just am clueless what it will be from what I've been figuring out so far.
Larry
You have to use CreateWindowExA with the class name of the control you are adding to your control. The standard classnames are things like "BUTTON", "EDIT", "SCROLLBAR", etc.
Paul.
What about my custom control having its own timer?
Here comes the dumb one.
Also, is there something I can do when drawing arcs/circles to make the final result display smoother(ie, reduce that sawtooth appearance)? Would "transforms" have anything to do with that?
Larry
I'm pretty sure you have the library source for Emergence Larry. Just look at the timer functions, it's just a couple of API functions.
Paul
Quote from: Paul Turley on February 05, 2008, 09:30:38 AM
Just look at the timer functions, it's just a couple of API functions.
duh :-[
Thanks
Larry
no problem.
If you need further help then I may have some time later.
Paul.
I started the timer in my WMCreate section and deleted it in my WMDestroy section. Worked like a top.
I picked an arbitrary timer id number. Is there some slick way to avoid having a user pick the same timer id for the parent window?
Larry
Timers are window specific.
but my control isn't a window.
It is drawn om a parent window or dialog or am I missing somethin?
Larry
ok. then pick an odd timer id like 31254
Paul.
that's what I did.
Thanks
Ok,
Here's my annunciator (alarm panel) library (AnnunLM) for all to use.
Read the readme for initial directions.
The example contains all the documentation.
Feedback would be appreciated.
Larry
Hi Larry!
Thank you once more for that additional offering :)
here is what i have when i launch the program.see the pic
as you can see the last checkbox is covered by the panel rectangle.
Hower i don't see this as a problem or so as it does not bring any damage to the basic function of the control.
I just want to be sure that everyone has the same results i have.
Cheers! 8)
Having a problem with a custom control I'm working on.
Scenario:
In a dialog I create my custom control. At that point in time I give it a dummy width and height because that has to be calculated in the initdialog message area.
When I calculate the desired width and height along with the original left and top I put those numbers in a RESIZE statement.
The result is that the control kind of moves to an aribtrary location. And if I change the dialog size and rerun the program my control moves.
As the dialog gets wider my control moves to the left and vice versa.
I noticed that the controlex function does some calculations and puts the l,t,w,h in a IBDLGTEMPLATE structure but the
SETSIZE fuction doesn't use that structure.
I'm missing something in my control's handler but I'm not sure what.
I'm thinking maybe I need to add a @IDSIZE section in my custom control handler but have no idea of what to put there.
Sure could use a nudge or two in the right direction.
Larry
I would need to see some code. If you're using API functions to change the controls size then your would need to do the conversion between dialog units and pixels.
Quote from: Paul Turley on February 20, 2008, 11:52:08 AM
.... conversion between dialog units and pixels.
Let me look into that and see what I can find before I have to bother you any further.
Thanks
Larry
Update:
New version of my annunciator (alarm panel) library (AnnunLM) available at:
http://www.ionicwind.com/forums/index.php/topic,2100.msg19514.html#msg19514
V1.1 Fixes
Problem with proper positioning of annunciator
deleted example.exe and added example.eba
Larry
Larry,
Just dl'ed zip file. Found example.exe but no example.eba.
Pardon my ignorance, but what is it used for?
Oops,
I just uploaded the old version back on by mistake.
The correct v1.1 is uploaded as of the time of this posting.
REDEBOLT:
The alarm panel controls are patterned after those found in refineries/chemical plants and similiar to those found on old fighter aircraft.
If you were building an application that simulated the controls found in a plant or the controls of an airplane you could use the annunciators just like they are used in real life. (I spent 11 years in the AirForce working on planes and 25 years working in a chemical plant.)
I'm currently working on a plotting control and intend to create some PID (proportional/integral/derivative) feedback controls in the future.
I'm also building the controls to learn how to build them and because the challenge is fun.
Larry