change button image dynamically

23 posts / 0 new
Last post
jabirulo
jabirulo's picture
Offline
Last seen: 29 min 49 sec ago
Joined: 2013-05-30 00:53
change button image dynamically

Hi, is ti possible to have a button with an imagen and when I click on antoher object/gadget (listbrowser entry) to change such image in the button?

Alas now everything I tried didn't work, 'cos I'm doing something wrong or missing a step. Or not underdtanding autodocs at all.

  1. #define OBJ(x) Objects[x]
  2. ...
  3. PAGE_Add, OBJ(OBJ_GEN) = IIntuition->NewObject(NULL, "layout.gadget",
  4. ...
  5. LAYOUT_AddChild, OBJ( OBJ_PREVIEW_BTN) = IIntuition->NewObject(NULL, "button.gadget",
  6. GA_ID, OBJ_PREVIEW_BTN,
  7. GA_RelVerify, TRUE,
  8. GA_Underscore, 0,
  9. BUTTON_BevelStyle, BVS_NONE,
  10. BUTTON_Transparent, TRUE,
  11. BUTTON_RenderImage, OBJ(OBJ_PREVIEW_IMG) = IIntuition->NewObject(NULL, "bitmap.image",
  12. IA_Width, 256, IA_Height, 224,
  13. BITMAP_SourceFile, "IMAGE.PNG",
  14. BITMAP_Screen, screen,
  15. TAG_DONE),
  16. TAG_DONE),
  17. CHILD_MaxWidth, 256, // pixels width of preview
  18. CHILD_WeightedHeight, 0, // align image at top
  19. ...
  20. if( (pwindow = (struct Window *)IIntuition->IDoMethod(OBJ(OBJ_MAIN), WM_OPEN, NULL)) )
  21. ...

It shows IMAGE.PNG ok on the button, but how the modify sucg image-button with IMAGE2,.PNG and (re)show it?
One of my try/test is:

  1. ...
  2. case WMHI_GADGETUP:
  3. switch(result & WMHI_GADGETMASK)
  4. {
  5. ...
  6. case OBJ_CHANGE_IMG:
  7. // Remove image-button (but nothing happens) :-(
  8. if( OBJ(OBJ_PREVIEW_IMG) ) {
  9. IIntuition->IDoMethod(OBJ(OBJ_GEN), LM_REMOVECHILD, pwindow, OBJ(OBJ_PREVIEW_IMG) );
  10. OBJ(OBJ_PREVIEW_IMG) = NULL;
  11. }
  12.  
  13. OBJ(OBJ_PREVIEW_IMG) = IIntuition->NewObject(NULL, "bitmap.image",
  14. IA_Width, 256, IA_Height, 224,
  15. BITMAP_SourceFile, "IMAGE2.PNG",
  16. BITMAP_Screen, screen,
  17. TAG_DONE);
  18.  
  19. IIntuition->IDoMethod(OBJ(OBJ_PREVIEW_BTN), LM_ADDCHILD, pwindow, OBJ(OBJ_PREVIEW_IMG), NULL);
  20. IIntuition->IDoMethod(OBJ(OBJ_MAIN), WM_RETHINK);
  21. break;
  22. }
  23. ...

Thanks In Advance

jabirulo
jabirulo's picture
Offline
Last seen: 29 min 49 sec ago
Joined: 2013-05-30 00:53
Re: change button image dynamically

Answering mysefl, maybe is still not very "pro", but seems to work this:

  1. if( OBJ(OBJ_PREVIEW_BTN) ) {
  2. IIntuition->IDoMethod( OBJ(OBJ_PREVIEW), LM_REMOVECHILD, pw, OBJ(OBJ_PREVIEW_BTN) );
  3. OBJ(OBJ_PREVIEW_BTN) = NULL;
  4. }
  5.  
  6. OBJ(OBJ_PREVIEW_BTN) = IIntuition->NewObject(NULL, "button.gadget",
  7. GA_ID, OBJ_PREVIEW_BTN,
  8. GA_RelVerify, TRUE,
  9. GA_Underscore, 0,
  10. BUTTON_BevelStyle, BVS_NONE,
  11. BUTTON_Transparent, TRUE,
  12. //BUTTON_BackgroundPen, BLOCKPEN,
  13. //BUTTON_FillPen, BLOCKPEN,
  14. BUTTON_RenderImage, OBJ(OBJ_PREVIEW_IMG) = IIntuition->NewObject(NULL, "bitmap.image",
  15. IA_Width, 256,
  16. IA_Height, 224,
  17. BITMAP_SourceFile, resul,
  18. BITMAP_Screen, screen,
  19. TAG_DONE),
  20. TAG_DONE);
  21. IIntuition->IDoMethod(OBJ(OBJ_PREVIEW), LM_ADDCHILD, pw, OBJ(OBJ_PREVIEW_BTN), NULL);
  22. IIntuition->IDoMethod(OBJ(OBJ_MAIN), WM_RETHINK);
  23. }

being:

  1. // GENERAL page
  2. PAGE_Add, OBJ(OBJ_GEN) = IIntuition->NewObject(NULL, "layout.gadget",
  3. LAYOUT_Orientation, LAYOUT_ORIENT_VERT,
  4. LAYOUT_SpaceOuter, TRUE,
  5. LAYOUT_SpaceInner, TRUE,
  6. LAYOUT_AddChild, OBJ(OBJ_PREVIEW) = IIntuition->NewObject(NULL, "layout.gadget",
  7. //LAYOUT_Orientation, LAYOUT_ORIENT_VERT,
  8. LAYOUT_SpaceOuter, TRUE,
  9. LAYOUT_BevelStyle, BVS_GROUP,
  10. LAYOUT_Label, "Game / Preview",
  11. ...
  12. LAYOUT_AddChild, OBJ(OBJ_PREVIEW_BTN) = IIntuition->NewObject(NULL, "button.gadget",
  13. GA_ID, OBJ_PREVIEW_BTN,
  14. GA_RelVerify, TRUE,
  15. GA_Underscore, 0,
  16. ...

AOS4.1/SAM460ex/PPC460EX-1155MHZ/2048MB/RadeonHD6570/SSD120GB/DVDRW :-P

TSK
TSK's picture
Offline
Last seen: 5 months 3 weeks ago
Joined: 2011-06-28 02:06
Re: change button image dynamically
  1. IIntuition->SetGadgetAttrs((struct Gadget *)OBJ(OBJ_PREVIEW_BTN),window,NULL,BUTTON_RenderImage,NULL,TAG_DONE);
  2. IIntuition->DisposeObject(OBJ(OBJ_PREVIEW_IMG));
  3. OBJ(OBJ_PREVIEW_IMG)=IIntuition->NewObject(.....);
  4. IIntuition->SetGadgetAttrs((struct Gadget *)OBJ(OBJ_PREVIEW_BTN),window,NULL,BUTTON_RenderImage,OBJ(OBJ_PREVIEW_IMG),TAG_DONE);

Or if it's on a clicktab page then use ILayout->SetPageGadgetAttrs(); instead of SetGadgetAttrs();

  1. ILayout->SetPageGadgetAttrs((struct Gadget *)OBJ(OBJ_PREVIEW_BTN),OBJ(OBJ_GEN),window,NULL,BUTTON_RenderImage,OBJ(OBJ_PREVIEW_IMG),TAG_DONE);
jabirulo
jabirulo's picture
Offline
Last seen: 29 min 49 sec ago
Joined: 2013-05-30 00:53
Re: change button image dynamically

THX will test it ASAP (aka tomorrow). :-)

AOS4.1/SAM460ex/PPC460EX-1155MHZ/2048MB/RadeonHD6570/SSD120GB/DVDRW :-P

jabirulo
jabirulo's picture
Offline
Last seen: 29 min 49 sec ago
Joined: 2013-05-30 00:53
Re: change button image dynamically

Tried and working PERFECT!!!! THX MAN :-)

AOS4.1/SAM460ex/PPC460EX-1155MHZ/2048MB/RadeonHD6570/SSD120GB/DVDRW :-P

broadblues
broadblues's picture
Offline
Last seen: 4 years 1 month ago
Joined: 2012-05-02 21:48
Re: change button image dynamically

A little background info on what is going on here:

You can change the image at any time by setting the BUTTON_RenderImage attribute to a new value via the OM_SET method which for all practical purposes is most usually called vai the SetAttrs() family of calls.

SetAttrs() itself only sets the new value for the attribute, in order to have it display you need to pass some information to the gadget to enable it to render. For this you need to use SetGadgetAttrs() this populates the GadgetInfo structure in the struct opSet message passed to gadget.

In the case of changing the button image it will autmatically rerender, some chnages don't for example setting disabled doesn't in that case you need to use either RefreshSetGadgetAttrs() or a seperate calle to RefreshGList()

As TSK mentioned there are some special versions of SetAttrs for gadgets like the PageGadget (most often used with click tabs) and also the virtual gadget.

hypex
hypex's picture
Offline
Last seen: 1 month 2 weeks ago
Joined: 2011-09-09 16:20
Re: change button image dynamically

Also it is recommended to cache the class pointers. So using IIntuition->OpenClass() to open what classes you need and pass the class pointer to NewObject(). So you save the OS looking up the class name for every GUI object you add.

I'd also apply this to your images and cache these. So that when your gadget images change you program doesn't reload another image off disk every time.

trixie
trixie's picture
Offline
Last seen: 5 months 2 hours ago
Joined: 2011-02-03 13:58
Re: change button image dynamically

Also it is recommended to cache the class pointers. So using IIntuition->OpenClass() to open what classes you need and pass the class pointer to NewObject(). So you save the OS looking up the class name for every GUI object you add.

I second that recommendation. Using a global class pointer in NewObject(), rather than the public class name, can optimize GUI creation times. Especially with more complex GUIs and on lower-end systems (like my Sam440) the speedup is noticeable.

AmigaOne X5000-020 / 2GB RAM / Sapphire Pulse Radeon RX 560 / AmigaOS 4.1 Final Edition Update 2

thomas
thomas's picture
Offline
Last seen: 5 hours 48 min ago
Joined: 2011-05-16 14:23
Re: change button image dynamically

One other hint: if you do not OpenClass() then NewObject() with name might fail if the class you want to use has not yet been opened by another program or flushed from memory by a low-memory condition. NewObject() only searches in memory, it does not load classes from disk.

And if you do OpenClass(), you get a class pointer anyway, so you can as well use it.

hypex
hypex's picture
Offline
Last seen: 1 month 2 weeks ago
Joined: 2011-09-09 16:20
Re: change button image dynamically

I second that recommendation

Yes I actually looked up your guide trixie. I knew you wrote one. A few years now but looks to still be current. I forgot to put the link so for those interested:

http://www.os4coding.net/blog/trixie/recommended-practice-os4-reaction-programming

jabirulo
jabirulo's picture
Offline
Last seen: 29 min 49 sec ago
Joined: 2013-05-30 00:53
Re: change button image dynamically

thx, I do use Classpointer, but I go step by step :-)
When you mean "cache images" do you mean I "preload" and store such images in a bitmap or object variable (or using Alloc.../Free..).
?

TIA

AOS4.1/SAM460ex/PPC460EX-1155MHZ/2048MB/RadeonHD6570/SSD120GB/DVDRW :-P

thomas
thomas's picture
Offline
Last seen: 5 hours 48 min ago
Joined: 2011-05-16 14:23
Re: change button image dynamically

When you mean "cache images" do you mean I "preload" and store such images in a bitmap or object variable (or using Alloc.../Free..).
?

If you look at TSK's suggestion, he

- detaches the old image from the button
- frees the old image
- loads the new image (which might fail!)
- attaches the new image to the button

There is a lot of unnecessary I/O involved as well as the possible failure and also the button might flicker if you use SetGadgetAttrs in both cases.

The better way is to load all images in the beginning of your program and keep them alive until your program finishes. Then you can change the button imagery by just one call to SetGadgetAttrs.

jabirulo
jabirulo's picture
Offline
Last seen: 29 min 49 sec ago
Joined: 2013-05-30 00:53
Re: change button image dynamically

Ok, but I have 1000 images/previews, is a list with ROM files. Si IMO this time is "ok" to this way. And previously I check if image/file exists:

  1. ...
  2. // Check if filename exists
  3. struct ExamineData *dat = IDOS->ExamineObjectTags(EX_StringNameInput,filename, TAG_END);
  4. if(dat == NULL)
  5. {
  6. IUtility->Strlcpy(filename, ROMS"/Previews/availablepreview.png", 1024);
  7. dat = IDOS->ExamineObjectTags(EX_StringNameInput,filename, TAG_END);
  8. }
  9. if(dat)
  10. {
  11. IDOS->FreeDosObject(DOS_EXAMINEDATA, dat);
  12.  
  13. // "Unbind" preview, remove it, create new, and add/show new image to window/pagetab
  14. ...

AOS4.1/SAM460ex/PPC460EX-1155MHZ/2048MB/RadeonHD6570/SSD120GB/DVDRW :-P

thomas
thomas's picture
Offline
Last seen: 5 hours 48 min ago
Joined: 2011-05-16 14:23
Re: change button image dynamically

Ok, then loading all images in the beginning is not an option.

But anyway I would use this sequence:

  1. new_img = NewObject(....);
  2. SetGadgetAttrs (preview_button, window, NULL, BUTTON_RenderImage, new_img, TAG_END);
  3. DisposeObject (preview_img);
  4. preview_img = new_img;
hypex
hypex's picture
Offline
Last seen: 1 month 2 weeks ago
Joined: 2011-09-09 16:20
Re: change button image dynamically

When you mean "cache images" do you mean I "preload" and store such images in a bitmap

Yes that's what I meant. For any common images. To preload them into a bitmap object.

But your 1,000 images sounds like a lot, is it some type of image requester? Are they all displayed at once? In that case preload what can be seen on screen.

You said ROM images so I wonder if they are names with an image associated with type. But I don't know. Got an image of it? ;-)

jabirulo
jabirulo's picture
Offline
Last seen: 29 min 49 sec ago
Joined: 2013-05-30 00:53
Re: change button image dynamically

Hi, just having sometimes after uniconifying and click on another listbrowser enrty a system freeze that points here (part of changing image on button), but dunnot what I'm doing wrong.

Shoudl I dispose the button image on iconifying?

  1. ...
  2. {
  3. Object *newobj = NULL;
  4. IDOS->FreeDosObject(DOS_EXAMINEDATA, dat);
  5. if( (newobj=IIntuition->NewObject(BitMapClass, NULL, //"bitmap.image",
  6. IA_Scalable,TRUE, BITMAP_Screen,screen,
  7. BITMAP_SourceFile,filename, TAG_DONE)) )
  8. {
  9. IIntuition->SetGadgetAttrs(GAD(OID_PREVIEW_BTN), pw, NULL, BUTTON_RenderImage,newobj, GA_Text,"", TAG_DONE);
  10. IIntuition->DisposeObject( OBJ(OID_PREVIEW_IMG) );
  11. OBJ(OID_PREVIEW_IMG) = newobj;
  12. ILayout->SetPageGadgetAttrs(GAD(OID_PREVIEW_BTN), OBJ(OID_GENERAL), pw, NULL, BUTTON_RenderImage,OBJ(OID_PREVIEW_IMG), TAG_DONE); // pagetab
  13. }
  14. }
  15. ...<code>

AOS4.1/SAM460ex/PPC460EX-1155MHZ/2048MB/RadeonHD6570/SSD120GB/DVDRW :-P

thomas
thomas's picture
Offline
Last seen: 5 hours 48 min ago
Joined: 2011-05-16 14:23
Re: change button image dynamically

I don't know why it crashes. Be aware that the window pointer (pw) and the screen pointer (screen) are different after uniconify and have to be reobtained.

Anyway, another thing which is wrong in your code is the call to SetGadgetAttrs. You must not use SetGadgetAttrs if the gadget is contained in a page. Obviously you are setting the same attribute twice, therefore you should replace SetGadgetAttrs by SetPageGadgetAttrs and remove the second call to SetPageGadgetAttrs alltogether.

jabirulo
jabirulo's picture
Offline
Last seen: 29 min 49 sec ago
Joined: 2013-05-30 00:53
Re: change button image dynamically

THX.
'pw' is passed as argument to that function and 'screen' is global (will look if both get properly updated).
Will change to use SetPageGadgetAttrs and dos ome test.
THX again.

AOS4.1/SAM460ex/PPC460EX-1155MHZ/2048MB/RadeonHD6570/SSD120GB/DVDRW :-P

jabirulo
jabirulo's picture
Offline
Last seen: 29 min 49 sec ago
Joined: 2013-05-30 00:53
Re: change button image dynamically

I have in a page/tab a listbrowser with roms game list and on the right a button with the image of rom game entry selected.

Can I make/code it this way to update the image button?:

  1. ...
  2. if( (newobj=IIntuition->NewObject(BitMapClass, NULL, //"bitmap.image",
  3. IA_Scalable,TRUE, BITMAP_Screen,screen,
  4. BITMAP_SourceFile,filename, TAG_DONE)) )
  5. {
  6. //ILayout->SetPageGadgetAttrs(GAD(OID_PREVIEW_BTN), OBJ(OID_GENERAL), pw, NULL, GA_Text,"", BUTTON_RenderImage,newobj, TAG_DONE); // "clear" gadgets
  7. IIntuition->SetAttrs(OBJ(OID_PREVIEW_BTN), GA_Text,"", BUTTON_RenderImage,newobj, TAG_DONE); // "update"
  8. IIntuition->DisposeObject( OBJ(OID_PREVIEW_IMG) );
  9. OBJ(OID_PREVIEW_IMG) = newobj;
  10. //ILayout->SetPageGadgetAttrs(GAD(OID_PREVIEW_BTN), OBJ(OID_GENERAL), pw, NULL, BUTTON_RenderImage,OBJ(OID_PREVIEW_IMG), TAG_DONE); // pagetab
  11. IIntuition->RefreshSetGadgetAttrs(GAD(OID_PREVIEW_BTN), pw, NULL, BUTTON_RenderImage,OBJ(OID_PREVIEW_IMG), TAG_DONE);
  12. }
  13. }
  14. ...

AOS4.1/SAM460ex/PPC460EX-1155MHZ/2048MB/RadeonHD6570/SSD120GB/DVDRW :-P

thomas
thomas's picture
Offline
Last seen: 5 hours 48 min ago
Joined: 2011-05-16 14:23
Re: change button image dynamically

Well, you are still in a page, so RefreshSetGadgetAttrs is a no-go, too.

Please keep in mind that all functions of intuition.library assume that the gadgets they work on are visible in the window. If you call SetGadgetAttrs, RefreshGadgets, RefreshGList, RefreshSetGadgetAttrs and so on, these funtions will immediately redraw the gadget into the window.

But gadgets which are part of a page might be hidden. Now if you call one of the intuition.library functions, they will draw the gadget into the window, no matter if it was visible before or not and no matter if it fits into the currently visible page or not.

You should never call intuition.library's gadget functions for gadgets which are part of a page. Only use the functions of page.gadget for these gadgets.

Regarding the sequence of your function calls, you still unnecessarily set the value of BUTTON_RenderImage twice. You use a different variable name, but the value is the same in both cases. Instead of the RefreshSetGadgetAttrs you could use RefreshPageGadget. Attributes don't need to be changed and it is the right function for refresh a gadget contained in a page.

jabirulo
jabirulo's picture
Offline
Last seen: 29 min 49 sec ago
Joined: 2013-05-30 00:53
Re: change button image dynamically

okidoki. Now I use:

  1. ...
  2. {
  3. OBJ(OID_PREVIEW_IMG) = newobj;
  4. ILayout->SetPageGadgetAttrs(GAD(OID_PREVIEW_BTN), OBJ(OID_GENERAL), pw, NULL, BUTTON_RenderImage,OBJ(OID_PREVIEW_IMG), TAG_DONE); // pagetab
  5. ILayout->RefreshPageGadget(GAD(OID_PREVIEW_BTN), OBJ(OID_GENERAL), pw, NULL);
  6. }
  7. ...

BTW I'm not sure if before i should use 'IIntuition->DisposeObject( OBJ(OID_PREVIEW_IMG) )'?

An to refresh a whole page? I'm checking first in what tab/page am and perform 'IIntuition->RefreshGadgets()'

  1. ...
  2. IIntuition->GetAttr(CLICKTAB_Current, OBJ(OID_PAGE), &res_value);
  3. DefaultSettings(); // load default snes9x settings
  4. SetGUIGadgets(); // set in GUI snes9x settings
  5. // Refresh settings gadgets
  6. IIntuition->RefreshGadgets(GAD(OID_SETTINGS_GLOBAL), pwindow, NULL); // this one is "outside" tabs/pages
  7. if(res_value == OID_SETTINGS) IIntuition->RefreshGadgets(GAD(OID_SETTINGS), pwindow, NULL);
  8. if(res_value == OID_AMIGAINPUT) IIntuition->RefreshGadgets(GAD(OID_AMIGAINPUT), pwindow, NULL);
  9. ...

AOS4.1/SAM460ex/PPC460EX-1155MHZ/2048MB/RadeonHD6570/SSD120GB/DVDRW :-P

thomas
thomas's picture
Offline
Last seen: 5 hours 48 min ago
Joined: 2011-05-16 14:23
Re: change button image dynamically

BTW I'm not sure if before i should use 'IIntuition->DisposeObject( OBJ(OID_PREVIEW_IMG) )'?

You've got a memory leak of you don't. But be sure to use the right pointer in DisposeObject. You must not dispose the old object while it is still connected to the gadget. And of course you don't want to dispose the image you allocated just before.

SetPageGadgetAttrs(page,button,new_img);
Dispose (old_img);

That's the right sequence.

An to refresh a whole page? I'm checking first in what tab/page am and perform 'IIntuition->RefreshGadgets()'

Isn't it sufficient to refresh the page gadget? I would expect it to refresh all its contents.

I would not use RefreshGadgets in a ReAction environment. RefreshGadgets starts at the given gadget and refreshes all gadgets which are linked together by the NextGadget pointer. But in a hierarchical layout structure you never know what the NextGadget field is used for. Therefore I would always use RefreshGList with a counter of 1.

jabirulo
jabirulo's picture
Offline
Last seen: 29 min 49 sec ago
Joined: 2013-05-30 00:53
Re: change button image dynamically

About Dispose(): ok, that's what I was thinking of. THX for clarifying.

About refresh whole page: but if I click on 'initial settings' All (most of them) gadgets from Settings (or AmigaInput) page should be refreshed:

  1. ...
  2. case OID_LOAD:
  3. IIntuition->GetAttr(CLICKTAB_Current, OBJ(OID_PAGE), &res_value);
  4. DefaultSettings(); // load default snes9x settings
  5. SetGUIGadgets(); // set in GUI snes9x settings
  6. // Refresh settings gadgets
  7. IIntuition->RefreshGadgets(GAD(OID_SETTINGS_GLOBAL), pwindow, NULL); // are "outside" pages/tabs
  8. if(res_value == OID_SETTINGS) IIntuition->RefreshGadgets(GAD(OID_SETTINGS), pwindow, NULL);
  9. if(res_value == OID_AMIGAINPUT) IIntuition->RefreshGadgets(GAD(OID_AMIGAINPUT), pwindow, NULL);
  10. break;
  11. ...

AOS4.1/SAM460ex/PPC460EX-1155MHZ/2048MB/RadeonHD6570/SSD120GB/DVDRW :-P

Log in or register to post comments