Solved

Dialog box update

Posted on 1998-07-06
8
301 Views
Last Modified: 2013-12-26
I have a full screen modal dialog box with a background picture on it. I can't get the background picture to redraw when an update event occurs. My update function isn't anything special:
      GetPort(&oldPort);
      SetPort(gMainDialog);            
      BeginUpdate(theWindow);
      DrawBackground();
      EndUpdate(theWindow);
      SetPort(oldPort);

This code acts as if the call to DrawBackground() isn't even there. I've followed the flow with the debugger and everything looks like it's executing.

Oddly, if I comment out BeginUpdate(theWindow); and add a call to DrawDialog(gMainDialog); It works, but it redraws everything on the screen. And that's very slow and ugly looking.

Help is always appreciated. Thanks in advance.
0
Comment
Question by:anthonyz
  • 4
  • 3
8 Comments
 
LVL 2

Expert Comment

by:roov
Comment Utility
Things to check are:

Does "DrawBackground" ever work for you? does it have the correct bounds for drawing the picture? Correct clip? If you're using a picture handle, are you sure it's pointing at what you expect to point?

If you'd like to send the code over, I'd be happy to have a look...
0
 

Author Comment

by:anthonyz
Comment Utility
DrawBackground() works fine when I initially draw it. The code is not suprising:

void DrawBackground(void)
  {
    PicHandle  thePic;
    GrafPtr    oldPort;
    Rect       theRect;        

    GetPort(&oldPort);
    SetPort(gMainDialog);

    SetRect(&theRect, 0, 0, 640, 460);
    thePic = GetPicture(1000);
    DrawPicture(thePic, &theRect);
    ReleaseResource((Handle) thePic);

    SetPort(oldPort);
  }
0
 

Accepted Solution

by:
paulsat earned 100 total points
Comment Utility
I assume your update code is in a modal event filter proc.  It's often difficult to intercept the dialog's normal updating event without screwing something up.  If you include the BeginUpdate/EndUpdate, you must add the DrawDialog() call because you would effectively remove the normal way the dialog manager would update everything else in the dialog.  

I would suggest something a little unusual but only because I get the impression you are trying to replace the normal white background of the dialog with this picture.  If this is the case, try getting the picture handle before you display the dialog, get the dialog ptr and then add the lines:

thePic = GetPicture(1000);
SetWindowPic(gMainDialog, thePic);
ShowWindow(gMainDialog);
SetPort(gMainDialog);
DrawDialog(gMainDialog);

Don't forget to dispose of the pic handle later or release the resource, whichever, after you dispose of the dialog ptr.  

Some explanation:  When you set the window pic of a window, you won't get that first update event, so you got to call DrawDialog() one time right after you make the dialog window vissible to get it to draw the other dialog items on top of the picture.  Make sure you get rid of all the update event code.  I also recommend you make the window invisible in the DLOG resource and show it just after you setup the window pic. One more thing, the pictures pci rect must be the same as where you want to display it in the dialog.

If you simply have a picture somewhere on the dialog and everything else does not have to draw on top of it, there is a much more straightforward and better way to do this, use a user item and write a very simply user item proc to simply draw the picture.  The dialog manager will call your user item proc in the order in which it updates items on the dialog, so that would allow the picture to be draw at any time, depending on the item number of the user item.  I did not recommend this at first because I think you want a picture behind all the other items on the dialog, in this case, the OK button would have to be item number 2 and a User item for the picture would have to be item number 1.  Most people want a pushbutton (OK or Cancel) to be the first item so the enter and returns keys will operate it.  It all depends on exactly what you want to do.

If the dialog is a simple splash screen, the window pic methods works great and so would a single enabled user item which would then let you detect a click on the picture, etc.!
0
 

Author Comment

by:anthonyz
Comment Utility
Thanks for the answer! I've pluged in your code and played with it for about an hour and I've got it to work half way. The background picture updates automatically and the update is fast. (Exactly what I want) However, the other dialog items don't update or are even visible for that matter...

Here's more info:

Here's my main:
void main(void)
{
   MaxApplZone();
   MoreMasters();
   MoreMasters();
   MoreMasters();
   InitializeToolbox();
   SetUpMenuBar();                                                                                       LoadPrefs();                                                                                             OpenModelessDialog();                                                                           DisableAndEnablePopUpItems();                                                            
   EventLoop();                                                                                             SavePrefs();
   DisposeDialog(gMainDialog);                                                                   
}

Here's OpenModelessDialog():
void OpenModelessDialog(void)
{
//vars here...

theStorage = NewPtr(sizeof(DialogRecord));
gMainDialog = GetNewDialog( rModalDialog, theStorage,(WindowPtr)-1L );
thePic = GetPicture(1000);
SetWindowPic(gMainDialog, thePic);
SetPort(gMainDialog);
ShowWindow(gMainDialog);
DrawDialog(gMainDialog);

//other drawing here
}

I deleted the update code as you suggested.
When I run the program, the dialog box appears (it's a full screen dialog box the exists until the program quits) the background picture (which is also full screen) appears instantly on the dialog, but none of the buttons or other pictures that I draw appear. I can click where the buttons are and they "pop through" the picture, but when I hide the program or cover the button with another window, the button vanishes "under" the background picture.

Interestingly, when I step through the code with the debuger, everything appears to work! The background picture draws then the call to DrawDialog(gMainDialog) draws all the dialog items. It looks great. However when I hide the program, everything besides the background vanishes.

Weird.

I want to thank you for getting me close. The SetWindowPic function is a great function I didn't know about before. If you have any pointers for getting the other DITLs to update please let me know! Again thanks for the help.

-Anthony
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Expert Comment

by:paulsat
Comment Utility
What other items are on the dialog?   I did not know you were doing a modeless dialog.  You need to be calling IsDialogEvent() and DialogSelect() in you main event loop, are you doing that.  If you do not need to have a pushbutton as the first item and have the enter key work with it automatically, I highly suggest the user item and user update proc, then I guarantee everything will work the way you want.  If that is the case let me know and I'll send a code snippet.  Modeless dialogs are quite different from Modal, you have to do more of the work that ModalDialog() would normally do with a modal dialog.  When you say:

Interestingly, when I step through the code with the debuger, everything appears to work! The background picture draws then the call to DrawDialog(gMainDialog) draws all the dialog items. It looks great. However when I hide the program, everything besides the background vanishes.

It amy be because you are not calling IsDialogEvent() and DialogSelect() in your main event loop.  If you would EMail me your Dialog resources DITL and DLOG and any others they use like CNTL's, I can give you a better way to do it.  My EMail adr is paulsat@Esper.com.

0
 

Expert Comment

by:paulsat
Comment Utility
Anthony,

Now that I see what you are trying to do, the best solution is NOT to use SetWindowPic().  Instead create a user item for your main dialog, make it item number 1, the first one in the list.  Make its bounds rectangle the same as the picture bounds rect, i.e., left/top = zero, right = 640, bottom = 460.  Make sure the item is disabled or you will get itemHit results from DialogSelect() that you do not want.  With this user item as item number one, anytime the normal updating mechanism in DialogSelect() draws the dialog, it will attempt first to call a user item proc.  Since you have a FAT app, you must provide a UPP to this user item proc and set it up just anytime after you get the dialog.  When the dialog is finally disposed of, after the dispose, you will also have to dispose the routine descriptor (UPP).  I will EMail you some code that I believe to be the best and most robust and correct way to do this that will work for both 68k and Power Mac.  Watch for my EMail and post the snippet here as a comment if it works out for you.  That way others will see the answer.
0
 

Author Comment

by:anthonyz
Comment Utility
For those following this comment thred, here's the e-mail Paul sent me:

Anthony,

I looked at your application and combined with the resources, I think I have a feel for what you want to do.  Assuming I have no typo's, here is one way to do it:

1. Get rid of all the old code dealing with the picture drawing,
especially the SetWindowPic() stuff I suggested earlier.

2. What you really need is to let the dialog manager take care of drawing that pic entirely and the one way to do that is to first create a User Item Draw Proc like this.

  void pascal drawBgPicUserItemProc(DialogPtr dialogPtr, short itemNum)
  {
      PictureHandle picHndl;
      short itemType;
      Handle itemHndl;
      Rect itemRect;

      // No need to save, set, and restore port..
      // ..dialog manager will already have the port set to dialogPtr!

      // First, we need to get the user items bounds rect...
      GetDialogItem(dialogPtr, itemNum, &itemType, &itemHndl, &itemRect);
     
      // Then get the picture handle...
      picHndl  = GetPicture(1000); // or whatever you picture res ID is
      if (picHndl == 0L) return;   // bug out if not enough memory to get the pic!

      // Then draw the picture...
      DrawPicture(picHndl, &itemRect);

      // Finally, allow the picture handle to be purged until needed again.
      ReleaseResource(picHndl);
  }

3. Now that you have this user item draw proc, we need to install it into the user item.  You will probably need a global to hold the universal proc pointer you will need to make this work on both 68k and PPC platforms.  Declare a global somewhere:

      UserItemUPP drawBgPicUserItemUPP;

4. Now, after your call to get the dialog and preferrably before you make the dialog visible and assuming you created that user item as the first item in the dialog, add the following lines of code:

      // some local variables this code will need...
      short itemType;
      Handle itemHndl;
      Rect itemRect;

      // create a universal proc ptr for the user item draw proc...
      drawBgPicUserItemUPP = NewUserItemProc(drawBgPicUserItemProc);

      // get everything there is to know about that first user item...
      GetDialogItem(gMainDialog, 1, &itemType, &itemHndl, &itemRect);

      // Change only the itemHndl to the UPP to our user item draw proc
      // the cast of drawBgPicUsetItemUPP is needed to get by the compiler
      SetDialogItem(gMainDialog, 1, itemType,
(Handle)drawBgPicUserItemUPP, &itemRect);

5. Almost done, bear with me.  At this point you would have what you want, DialogSelect() will see item 1 as a disabled user item, it will see it has a item handle, it will assume the item handle is a universal proc ptr for a draw update proc and it will call it automatically, thus the picture will draw first, every time, then any other items will be drawn.  The only thing left is to clean up after ourselves.  When you call DisposeDialog(gMainDialog), add a line of code, i.e.:

      DisposeDialog(gMainDialog);
      DisposeRoutineDescriptor((UniversalProcPtr)drawBgPicUserItemUPP);

This will free up any memory used by the UPP since it will no longer be needed.  

That should do it, give it a try.

You know, there is even a simpler way to do what you want.  Forget all the code entirely, get rid of everything dealing with that picture.  Make that first user item a pic item instead of a user item.  Make sure it is disabled, and designate it's pict res id to be 1000.  That should give you a picture behind all the other dialog items and it will automatically draw itself.  Also, you should make the Pic Resource non-purgeable.   I would have deleted all the above stuff and left only this paragraph, but
it may be useful to you some day when you want to do some other automatic drawing on a dialog that the dialog manager can do directly.  But pictures are well supported, just create a new first item in the dialog item list as a pict item and enter its ID and make sure you make it disabled.  

You would have to use the user item approach if the picture was not in a resource, i.e., if you had created it at runtime using OpenPicture().

BTW, you can use Pict type dialog items for those arrow pictures that will make dialog manager automatically draw them and detect clicks on them too.  In this case, make the arrow pic items enabled so DialogSelect() will return itemHit when the user clicks an arrow.  You can then process those arrows in your switch statement after DialogSelect(), but you really should be using scroll bars instead!

Have fun, hope this helps.

- Paul

=====================================================
I had tried the pict idea before without success, but just to make sure I tried it again. Even though the pic is the first item in the DITL it still blankets the rest of the items. Clicking where buttons usually are doesn't pop them through the picture nor does it register the click on the item. I verified that the pict is non-pureable and not enabled.

With that approach not working, I tried the UPP. I put the code that Paul suggested, but when I run the program the background and all the items that are not enabled (My text, and edit text items) appear in the window. The push buttons, radio buttons, and controls are hidden behind the picture and can not be pushed/activated.

When I bring up the calculator and move it over various parts of the window(I do this to see how the update is working), I can see the buttons appear for an instant then the background picture covers them.

As an experiement I made the userItem (that holds the background picture) 10 instead of 1. In that instance, the radio buttons near the top (they have DITL numbers under 10) didn't appear when the program starts, but do appear if I click where they should be. (In other words they pop through the picture) I'd make them all appear, but when I dragged the calculator over them, they wouldn't update.

Another interesting "effect" is when I call DrawDialog(gMainDialog). All the user items appear for an instant then are hidden by the picture (except for those that are not enabled).
0
 

Author Comment

by:anthonyz
Comment Utility
I finally found a solution. It's not really ideal, but at least it works. I've chopped up the picture into many little rectangles and built the entire picture piece by piece, leaving out the white spaces. In this way, the PICT doesn't cover the any of the other dialog box items, and thus doesn't screw them up.

I really appreciate paulsat's help!
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Introduction: The undo support, implementing a stack. Continuing from the eigth article about sudoku.   We need a mechanism to keep track of the digits entered so as to implement an undo mechanism.  This should be a ‘Last In First Out’ collec…
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now