|
Netscape, ahah, love this browser man
|
|
|
|
|
Great.. I got some idea.. Thanks
|
|
|
|
|
Why the dialog as well as the pages are of instances of CSAPrefsDialog class?
|
|
|
|
|
the dialog itself is CSAPrefsDialog.
the pages are CSAPrefsSubDlg
|
|
|
|
|
In CSAPrefsDialog::OnGetdispinfoPageTree(...)
you wrote
strcpy(pTVDispInfo->item.pszText, pPS->csCaption);
But pTVDispInfo->item.pszText is a pointer to an empty string.
Do you overwrite anything?
I changed it to
LPTSTR pBuffer = pPS->csCaption.GetBuffer();
pTVDispInfo->item.pszText = pBuffer;
pPS->csCaption.ReleaseBuffer();
Is that right?
|
|
|
|
|
the MSDN for TVITEM says :
pszText
Address of a null-terminated string that contains the item text if the structure specifies item attributes. If this member is the LPSTR_TEXTCALLBACK value, the parent window is responsible for storing the name. In this case, the tree view control sends the parent window a TVN_GETDISPINFO notification message when it needs the item text for displaying, sorting, or editing and a TVN_SETDISPINFO notification message when the item text changes.
If the structure is receiving item attributes, this member is the address of the buffer that receives the item text.
i take that last sentence to mean that: in the situation like we have here, where we are responding to a request for the item's text, the pszText pointer is valid and we can copy our text into the buffer it points to. (i think there should probably be a check in there to prevent copying strings larger than item.cchTextMax, however)
|
|
|
|
|
Hi,Chirs,I use SAPrefs in my application, it works great!
thx a lot!;P
and now ,I want to use it as a tab control item,it doesnt' works right.
Did you try to do this before?
any suggestion will be appreciated!
Best regards!
|
|
|
|
|
hi,
no i've never tried to do that, sorry.
|
|
|
|
|
I am using SAPrefs in my app. Works great!
Now I need to dynamically add/delete pages (dialogs, subdialogs) depending on user selection. Is there a way to do this?
|
|
|
|
|
Hi ! Chis. I am using your SAPrefs in my program. According to my requirements i have to use button to change the pages and take out all tree control code. But i face some problem which when i click the "Junk" button the screen will change "Junk" page then i click the "Weapon" button the "Weapon" page will appear. After that when i click the "Junk" button for 2nd time that is not function at all.
CSAPrefsDialog::CSAPrefsDialog(CWnd* pParent /*=NULL*/)
: CDialog(CSAPrefsDialog::IDD, pParent)
{
//{{AFX_DATA_INIT(CSAPrefsDialog)
//}}AFX_DATA_INIT
m_iCurPage = -1;
m_pages.RemoveAll();
m_pStartPage = NULL;
}
/////////////////////////////////////////////////////////////////////////////
CSAPrefsDialog::~CSAPrefsDialog()
{
// clean up
for (int i=0;i<m_pages.getsize();i++)
{
="" pagestruct="" *pps="(pageStruct" *)m_pages.getat(i);
="" if="" (pps)
="" delete="" pps;
="" }
}
=""
void="" csaprefsdialog::dodataexchange(cdataexchange*="" pdx)
{
="" cdialog::dodataexchange(pdx);
="" {{afx_data_map(csaprefsdialog)
="" ddx_control(pdx,="" idc_dlg_frame,="" m_boundingframe);
="" }}afx_data_map
}
begin_message_map(csaprefsdialog,="" cdialog)
="" {{afx_msg_map(csaprefsdialog)
="" on_wm_create()
="" on_bn_clicked(idc_button1,="" onbacktopage1)
="" on_bn_clicked(idc_button2,="" onbutton2)
="" on_bn_clicked(idc_button3,="" onbutton3)
="" on_bn_clicked(idc_button4,="" onbutton4)
="" }}afx_msg_map
="" on_message(wm_change_page,="" onchangepage)
="" on_message(wm_set_focus_wnd,="" onsetfocuswnd)
end_message_map()
=""
="" csaprefsdialog="" message="" handlers
bool="" csaprefsdialog::pretranslatemessage(msg*="" pmsg)=""
{
="" assert(pmsg="" !="NULL);
" assert_valid(this);
="" assert(m_hwnd="" don't="" let="" cdialog="" process="" the="" escape="" key.
="" ((pmsg-="">message == WM_KEYDOWN) && (pMsg->wParam == VK_ESCAPE))
{
return TRUE;
}
if (CWnd::PreTranslateMessage(pMsg))
return TRUE;
// don't translate dialog messages when
// application is in help mode
CFrameWnd* pFrameWnd = GetTopLevelFrame();
if (pFrameWnd != NULL && pFrameWnd->m_bHelpMode)
return FALSE;
// ensure the dialog messages will not
// eat frame accelerators
pFrameWnd = GetParentFrame();
while (pFrameWnd != NULL)
{
if (pFrameWnd->PreTranslateMessage(pMsg))
return TRUE;
pFrameWnd = pFrameWnd->GetParentFrame();
}
return PreTranslateInput(pMsg);
}
/////////////////////////////////////////////////////////////////////////////
int CSAPrefsDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
return 0;
}
/////////////////////////////////////////////////////////////////////////////
BOOL CSAPrefsDialog::OnInitDialog()
{
CDialog::OnInitDialog();
// where will the dlgs live?
m_boundingFrame.GetWindowRect(m_frameRect);
ScreenToClient(m_frameRect);
m_frameRect.DeflateRect(2,2);
// start with page 0
if (m_pStartPage==NULL)
{
if (ShowPage(0))
{
m_iCurPage = 0;
}
}
else
{
// find start page
for (int i=0; i<m_pages.getsize(); i++)
="" {
="" pagestruct="" *pps="(pageStruct" *)m_pages.getat(i);
="" assert(pps);
="" if="" (pps)
="" assert(pps-="">pDlg);
if (pPS->pDlg == m_pStartPage)
{
ShowPage(i);
m_iCurPage = i;
break;
}
}
}
}
return TRUE;
// return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
/////////////////////////////////////////////////////////////////////////////
bool CSAPrefsDialog::AddPage(CSAPrefsSubDlg &dlg, CSAPrefsSubDlg* pDlgParent /*=NULL*/)
{
if (m_hWnd)
{
// can't add once the window has been created
ASSERT(0);
return false;
}
pageStruct *pPS = new pageStruct;
pPS->pDlg = &dlg;
pPS->id = dlg.GetID();
pPS->pDlgParent = pDlgParent;
m_pages.Add(pPS);
return true;
}
/////////////////////////////////////////////////////////////////////////////
BOOL CSAPrefsDialog::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CWnd::PreCreateWindow(cs))
return FALSE;
cs.lpszClass = AfxRegisterWndClass(CS_DBLCLKS, NULL, NULL, NULL);
cs.style |= WS_CLIPCHILDREN;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
bool CSAPrefsDialog::ShowPage(CSAPrefsSubDlg * pPage)
{
// find that page
for (int i=0;i<m_pages.getsize();i++)
{
="" pagestruct="" *pps="(pageStruct" *)m_pages.getat(i);
="" assert(pps);
="" if="" (pps)
="" {
="" assert(pps-="">pDlg);
if (pPS->pDlg == pPage)
{
ShowPage(i);
m_iCurPage = i;
return true;
}
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////////
bool CSAPrefsDialog::ShowPage(int iPage)
{
if (iPage == NULL)
iPage = 0;
// turn off the current page
if ((m_iCurPage >= 0) && (m_iCurPage < m_pages.GetSize()))
{
pageStruct *pPS = (pageStruct *)m_pages.GetAt(m_iCurPage);
ASSERT(pPS);
if (pPS)
{
ASSERT(pPS->pDlg);
if (pPS->pDlg)
{
if (::IsWindow(pPS->pDlg->m_hWnd))
{
pPS->pDlg->ShowWindow(SW_HIDE);
}
}
}
else
{
return false;
}
}
// show the new one
if ((iPage >= 0) && (iPage < m_pages.GetSize()))
{
pageStruct *pPS = (pageStruct *)m_pages.GetAt(iPage);
ASSERT(pPS);
if (pPS)
{
ASSERT(pPS->pDlg);
if (pPS->pDlg)
{
// if we haven't already, Create the dialog
if (!::IsWindow(pPS->pDlg->m_hWnd))
{
pPS->pDlg->Create(pPS->pDlg->GetID(), this);
}
// move, show, focus
if (::IsWindow(pPS->pDlg->m_hWnd))
{
pPS->pDlg->MoveWindow(m_frameRect.left, m_frameRect.top, m_frameRect.Width(), m_frameRect.Height());
pPS->pDlg->ShowWindow(SW_SHOW);
//pPS->pDlg->SetFocus();
}
//return true;
}
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////////
LONG CSAPrefsDialog::OnChangePage(UINT u, LONG l)
{
if (ShowPage(u))
{
m_iCurPage = u;
}
return 0L;
}
/////////////////////////////////////////////////////////////////////////////
LONG CSAPrefsDialog::OnSetFocusWnd(UINT u, LONG l)
{
if (::IsWindow((HWND)u))
{
::SetFocus((HWND)u);
}
return 0L;
}
void CSAPrefsDialog::OnBackToPage1()
{
// TODO: Add your control notification handler code here
ShowPage(0);
}
void CSAPrefsDialog::OnButton2()
{
// TODO: Add your control notification handler code here
ShowPage(1);
}
void CSAPrefsDialog::OnButton3()
{
// TODO: Add your control notification handler code here
ShowPage(2);
}
void CSAPrefsDialog::OnButton4()
{
// TODO: Add your control notification handler code here
ShowPage(3);
}
Terry (VC++ newbie)
|
|
|
|
|
IHi Chris. I'm using your SAPrefs stuff in a priogram, and my requirements included being able to update various pages BEFORE the user had clicked on them the first time. I use PostMessage to post a message to all of tghe pages, and as you might expect, this causes problems because none of the pages except the start page has been created when I post the message.
To alleviate the problem, I added the following code to the CSAPrefsDialog. Adnmittedly, it ain't pretty or even elegant, but it fixed my issue...
void CSAPrefsDialog::PreLoadPages()
{
int nCount = m_pages.GetSize();
for (int iPage = 0; iPage < nCount; iPage++)
{
pageStruct *pPS = (pageStruct *)m_pages.GetAt(iPage);
ASSERT(pPS);
if (pPS)
{
ASSERT(pPS->pDlg);
if (pPS->pDlg)
{
if (!::IsWindow(pPS->pDlg->m_hWnd))
{
pPS->pDlg->Create(pPS->pDlg->GetID(), this);
}
if (::IsWindow(pPS->pDlg->m_hWnd))
{
pPS->pDlg->MoveWindow(m_frameRect.left, m_frameRect.top, m_frameRect.Width(), m_frameRect.Height());
pPS->pDlg->ShowWindow(SW_HIDE);
}
}
}
}
}
It's nothing more than some of the ShowPage function copied to a new function, and call it from the OnInitDialog function of the CSAPrefsDialog class just before it shows the start page. Voila - no more ASSERTS caused by hWnd = "0xbaadf00d"...
Thanks for the classes though - they saved me a buttload of time.
------- sig starts
"I've heard some drivers saying, 'We're going too fast here...'. If you're not here to race, go the hell home - don't come here and grumble about going too fast. Why don't you tie a kerosene rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt
"...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001
|
|
|
|
|
I've never had to do that before and can't quite figure it out.
Do you open the .rc file and copy from there, or is it something more simple?
Thanks in advance.
John
|
|
|
|
|
open the resource view. get to where you see the resource for the dialog (IDD_MY_DIALOG), select it. Ctrl-C to copy. then to paste, use Ctrl-V.
ImgSource | CheeseWeasle
|
|
|
|
|
Hi Chris (or anyone who might have an idea how to do this)-
I implemented this into my app (it works great!). I changed the tree on the left that is used to select a page to a CListBox and it seems to be working fine. However I would like to select the first item in the list box when the dialog comes up. I tried setting focus to it at the end of CSAPrefsDialog::OnInitDialog, but it's not being selected. I am wondering if the focus is being taken by something else (the current page?). Any ideas would be greatly appreciated! Thanks for a great article!
Rachael
"It seems that we're getting to the bottom of the barrel of squirrels." - my boss
|
|
|
|
|
I have got sick of managing modeless dialogs and am going to try using SAPrefs as the basis for a dialog-based application.
Has anyone done this before and were there any tip/pitfalls I should be aware of?
Cheers
|
|
|
|
|
|
Thanks for your reply, and example. I've got the basics going, but have now come up against a bit of a hurdle.
I want to have all the data that the application is going to use in the same place. I initially thought the main dialog (CSAPrefsDialog) would be the right place, and thought each sub dialog (CSAPrefsSubDlg) could then have a pointer to the main dialog (m_pDlgMain) to access the data. But to do this I needed to #include "SAPrefsDialog.h" in "SAPrefsSubDlg.h" but this gave me major problems. I think (maybe) that the fact that "SAPrefsDialog.h" was already #including "SAPrefsSubDlg.h" was causing this. But they are both protected from multiple #includes by #ifndef ABC, #define ABC.
Am I missing something about C++ here??
I am currently pursuing the path of having CPrefsApp store the data and letting all the dialogs access it from there. Which seems to be working, and maybe is a better way anyway.
I would appreciate any thoughts...
Thanks again for a great class... 
|
|
|
|
|
Docta G wrote:
I am currently pursuing the path of having CPrefsApp store the data and letting all the dialogs access it from there. Which seems to be working, and maybe is a better way anyway.
yeah. that might be better.
to store it in the dialog, you could have the subdialogs each #include "SAPrefsDialog.h" - put this in MySubDlg1.h, MySubDlg2.h, etc., - not in SAPrefsSubDlg.h
ImgSource | CheeseWeasle
|
|
|
|
|
Lets say I have the following example:
+ Page 1
Page 2
If you click on the plus symbol, page 1 displays
subpages, like the following:
+ Page 1
- Subpage 1
- subpage 2
Page 2
How can I make the subpages appear when the program is
first executed, so that the user doesn't have to click
on the plus symbol to see the subpages?
Please, any response you can give me will be greatly
appreciated.
Sincerely,
Danielle (an overworked graduate student)

|
|
|
|
|
do you want *all* pages to be visible? if so, you can set the items to expanded when they are added to the tree; something like:
...
tvi.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_STATE;
tvi.item.state = TVIS_EXPANDED;
in CSAPrefsDialog::OnInitDialog.
or, if you just want to open a single node at start up:
add a member m_uStartPageID and set it 0 by default.
if (m_uStartPageID==0)
{
if (ShowPage(0))
{
m_iCurPage = 0;
}
}
else
{
for (int i=0;i<m_pages.GetSize();i++)
{
pageStruct *pPS = (pageStruct *)m_pages.GetAt(i);
ASSERT(pPS);
if (pPS)
{
ASSERT(pPS->pDlg);
if (pPS->id == m_uStartPageID)
{
ShowPage(i);
m_iCurPage = i;
break;
}
}
}
}
put that at the end of OnINitDialog, too.
then set m_uStartPageID to the page ID of the page you want to open
-c
|
|
|
|
|
We can find another similar idea here
Cheers and thanks to Chris and Sven Wiegand
Koundinya
|
|
|
|
|
yes.
and here :
http://www.codeproject.com/dialog/csettingsdlg.asp
and here :
http://www.codeproject.com/dialog/ezoptionsdlg.asp
and here :
http://www.codeguru.com/dialog/netscape_like_prefs_dialog.shtml
When history comes, it always takes you by surprise.
|
|
|
|
|
Should we call DestroyWindow() to clean up the Create() calls?
void CSAPrefsDialog::OnDestroy()
{
CDialog::OnDestroy();
// destroy windows to free resources
for (int i=0;i<m_pages.getsize();i++)
{
="" pagestruct="" *pps="(pageStruct" *)m_pages.getat(i);
="" if="" (pps)
="" pps-="">pDlg->DestroyWindow();
}
}
}
|
|
|
|
|
DestroyWindow is called on each of the Created sub-dialogs when CSAPrefsDialog's DestroyWindow is called (via CDialog::DestroyWindow). you don't need to explicitly destroy the child dialogs. override WM_DESTROY in your own sub dialog and put a breakpoint there, if you want to see it in action.
-c
I'm not the droid you're looking for.
|
|
|
|
|
Chris, I love this interface. Thanks for making the code available. I have a problem, though. I find that when I run my app and open the dialog, none of the controls inside the pages are sensitive to mouse clicks; they just sit there looking pretty but dead. The tree control works fine, and shows each separate page. This must be something pretty basic that I have done wrong, but I can't figure it out. Does this sound familiar? Anybody have any ideas?
|
|
|
|