How to modify the tool rect of a CToolTipCtrl? - c++

This question is related to this one.
In a CDockablePane derived class I have a CTreeCtrl member for which I add a ToolTip in OnCreate():
int CMyPane::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDockablePane::OnCreate(lpCreateStruct) == -1)
return -1;
const DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
TVS_CHECKBOXES | TVS_DISABLEDRAGDROP | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT |
TVS_INFOTIP | TVS_NOHSCROLL | TVS_SHOWSELALWAYS;
if(!m_tree.Create(dwStyle, m_treeRect, this, TREECTRL_ID) ) { return -1; }
m_pToolTip->AddTool(&m_tree, LPSTR_TEXTCALLBACK, &m_treeRect, TREECTRL_ID);
m_tree.SetToolTips(m_pToolTip);
return 0;
}
I have to call AddTool() with all of the optional parameters because the default values won't work with CDockablePane.
m_treeRect is a CRect member set to (0, 0, 10000, 10000) in the CTor. This is really ugly.
I would like to adjust the tool's rectangle whenever m_tree's size changes.
So I tried some stuff in CMyPane::OnSize() but none of it worked:
Calling m_pToolTip->GetToolInfo() then modify the CToolInfo's rect member, then calling SetToolInfo()
Calling m_pToolTip->SetToolRect()
How is it meant to be done?

I know no other way to do this other than calling DelTool then AddTool again in your OnSize handler:
void CMyPane::OnSize(UINT nType, int cx, int cy)
{
CDockablePane::OnSize(nType, cx, cy);
if (m_pToolTip != NULL)
{
m_pToolTip->DelTool(&m_tree, TREECTRL_ID);
CRect treeRect;
m_tree.GetClientRect(treeRect);
m_pToolTip->AddTool(&m_tree, LPSTR_TEXTCALLBACK, &treeRect, TREECTRL_ID);
}
}

int CMyPane::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDockablePane::OnCreate(lpCreateStruct) == -1)
return -1;
const DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
TVS_CHECKBOXES | TVS_DISABLEDRAGDROP | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT |
TVS_INFOTIP | TVS_NOHSCROLL | TVS_SHOWSELALWAYS;
if(!m_tree.Create(dwStyle, m_treeRect, this, TREECTRL_ID) ) { return -1; }
m_pToolTip->AddTool(&m_tree, LPSTR_TEXTCALLBACK, &m_treeRect, TREECTRL_ID);
m_tree.SetToolTips(m_pToolTip);
return 0;
}

Related

Problem with tooltip for two different docked panes of CMFCToolBar

I made two groups of toolbar:
`
if (!m_wndToolBar1.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | CBRS_TOOLTIPS | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar1.LoadToolBar(IDR_MAINFRAME_256)) return -1;
m_wndToolBar1.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_wndToolBar1);
`
I make it in a DockPane and another one:
`
if (!m_wndToolBar2.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar2.LoadToolBar(IDR_MAINFRAME_256_3D)) return -1;
m_wndToolBar2.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_wndToolBar2);
Put tehe MESSAGE MAP:
ON_NOTIFY_EX(TTN_NEEDTEXT, 0, &CTunnelMainFrame::OnNeedText)
And the function:
BOOL CTunnelMainFrame::OnNeedText(UINT id, NMHDR* pNMHDR, LRESULT* pResult)
{
UINT_PTR nId = pNMHDR->idFrom - 1;
CMFCToolBarButton* pBtnToolBar = m_wndToolBar1.GetButton(nId);
if (pBtnToolBar)
{
TCHAR szBuff[64];
::LoadString(AfxGetResourceHandle(), pBtnToolBar->m_nID, szBuff, sizeof(szBuff) / sizeof(TCHAR));
pTTT->lpszText = szBuff;
pTTT->hinst = AfxGetResourceHandle();
}
return TRUE;
}
`
So, I expect that the tooltip will appear only on m_wndToolBar1's dock pane, but in fact it also appear on m_wndToolBar2's dock pane. But with STRINGTABLE ID (string message) that belongs to m_wndToolBar1. My question is how to disable tooltip on m_wndToolBar2's dock pane? or to make other OnNeedText funtion that only wokrs on m_wndToolBar2's dock pane?
Thanks~
1)
BOOL CMainFrame::OnNeedText(UINT id, NMHDR* pNMHDR, LRESULT* pResult)
{
CPoint point;
GetCursorPos(&point);
CRect rcToolbar1;
m_wndToolBar.GetWindowRect(&rcToolbar1);
if(rcToolbar1.PtInRect(point) == FALSE)
return TRUE;
UINT_PTR nId = pNMHDR->idFrom - 1;
NMTTDISPINFO* pTTT = (NMTTDISPINFO*)pNMHDR;
CMFCToolBarButton *pBtn1 = m_wndToolBar.GetButton(nId);
if (pBtn1)
{
TCHAR szBuff[64];
LoadString(AfxGetResourceHandle(), pBtn1->m_nID, szBuff, sizeof(szBuff) / sizeof(TCHAR));
//_stprintf(szBuff, L"Controle ID:%d", pBtn1->m_nID);
pTTT->lpszText = szBuff;
pTTT->hinst = AfxGetResourceHandle();
}
return TRUE;
}
2)don't using TTN_NEEDTEXT, using the prompt instead, Resource View->Toolbar, set the m_wndToolBar1's prompt with text and set the m_wndToolBar2's prompt with empty text

Create derived control at runtime cause assertion

I am trying to create a control at run-time, but it causes assertion, and I don't know what's causing it. The control I am using is the Tree ComboBox Control from this link: https://www.codeproject.com/Articles/187762/Tree-ComboBox-Control
I added the code to register the class as follow:
CTreeComboBox::CTreeComboBox()
...
{
...
RegisterWindowClass();
}
CTreeComboBox::~CTreeComboBox()
{
m_BrushAlert.DeleteObject();
}
BOOL CTreeComboBox::RegisterWindowClass()
{
WNDCLASS wndcls;
HINSTANCE hInst = AfxGetInstanceHandle();
if (!(::GetClassInfo(hInst, _T("TreeComboBox"), &wndcls)))
{
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = NULL;
wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
wndcls.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = _T("TreeComboBox");
if (!AfxRegisterClass(&wndcls))
{
AfxThrowResourceException();
return FALSE;
}
}
return TRUE;
}
I tried to create the control at run-time using the following code in the test program:
BOOL CTestComboBoxDlg::OnInitDialog()
{
...
m_ComboBox2.CreateEx(WS_EX_CLIENTEDGE, _T("TreeComboBox"), _T(""), WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP,
CRect(0, 0, 100, 50), this, 100000, NULL);
return TRUE; // return TRUE unless you set the focus to a control
}
I also tried creating the control using a button click event thinking that I should let the GUI finish initializing, but the same error occur:
void CTestComboBoxDlg::OnBnClickedButton1()
{
m_ComboBox2.CreateEx(WS_EX_CLIENTEDGE, _T("TreeComboBox"), _T(""), WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP,
CRect(0, 0, 100, 50), this, 100000, NULL);
}
When I run the program, it stopped at the file dbgrptt.cpp at the following line:
__try
{
if (_CRT_ASSERT == nRptType && _InterlockedIncrement(&_crtAssertBusy) > 0)
{
/* use only 'safe' functions -- must not assert in here! */
_ERRCHECK(_itoa_s(nLine, szLineMessage, DBGRPT_MAX_MSG, 10));
OutputDebugStringA("Second Chance Assertion Failed: File ");
OutputDebugStringA(szFile ? szFile : "<file unknown>");
OutputDebugStringA(", Line ");
OutputDebugStringA(szLineMessage);
OutputDebugStringA("\n");
It stop here===> _CrtDbgBreak();
retval=-1;
__leave;
}
The program run fine if I create the control manually using the Visual Studio GUI editor, so I am not sure what's wrong. Can you help me figure out how to create this control at run-time?
Note: change the statement: TRACE1(_T("Item selected: %s\n"), GetItemText(hItem)); to TRACE(_T("Item selected: %s\n"), GetItemText(hItem)); in the file ComboTreeCtrlExt.cpp if you if you want to run the code and are using MFC
To answer my own question. Move the following code from the CTreeComboBox::PreSubclassWindow() to the CTreeComboBox::OnCreate()
CRect rect(0, 0, 0, 0);
DWORD dwStyle = WS_POPUP | WS_BORDER;
CWnd* pWnd = &m_Tree;
pWnd->CreateEx(0, WC_TREEVIEW, NULL, dwStyle, rect, GetParent(), 0, NULL);
m_Tree.Init(this);
GetClientRect(rect);
SetDroppedWidth(rect.Width());
SetDroppedHeight(m_nDroppedHeight);
dwStyle = CBS_DROPDOWNLIST & GetStyle();
ASSERT(CBS_DROPDOWNLIST == dwStyle);

How to change default gripper Style CToolbar?

I am using MFC c++. I using CToolBar i try to changing the default Gripper Style:
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
I want to change this:
to this:
Any help?
Finally its work.
Thanks to Barmak Shemirani.
Method 1: (docking enable)
SetWindowTheme(m_wndToolBar.m_hWnd,L"",L"")
Method 2: (docking not working)
CReBarCtrl& rbc = m_wndReBar.GetReBarCtrl();
REBARBANDINFO rbbi;
rbbi.cbSize = sizeof(rbbi);
rbbi.fMask = RBBIM_STYLE;
int nCount = rbc.GetBandCount();
for (int i = 0; i < nCount; i++)
{
rbc.GetBandInfo(i, &rbbi);
rbbi.fStyle |= RBBS_NOGRIPPER;
rbbi.fStyle &= ~RBBS_GRIPPERALWAYS;
rbc.SetBandInfo(i, &rbbi);
}

How To Add A Second Toolbar Into Mainframe?

I would like to add a second toolbar in my main frame window to sit under the existing toolbar.
Reading the following tutorials:
http://forums.codeguru.com/showthread.php?495887-Add-a-toolbar-to-an-MFC-application
http://www.codersource.net/2010/01/30/mfc-tutorial-toolbars/
MFC Toolbar on Dialog?
I have come to a similar conclusion to this unanswered thread:
https://stackoverflow.com/questions/35736580/how-to-add-a-second-toolbar-to-an-mfc-application-so-that-the-toolbar-is-added-o
This is my code:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// create a view to occupy the client area of the frame
if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
{
TRACE0("Failed to create view window\n");
return -1;
}
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
m_wndStatusBar.SetPaneInfo(EWF_PANE_INDEX, ID_SEPARATOR, SBPS_NORMAL, EWF_PANE_WIDTH);
for (int i=0;i<5; i++) {
// Change Status Bar style to make it Owner-drawn
m_wndStatusBar.GetStatusBarCtrl().SetText("", i, SBT_OWNERDRAW);
}
CToolBar myToolBar;
if (!myToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!myToolBar.LoadToolBar(IDR_MAINFRAME_B))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
return 0;
}
I have added:
CToolBar myToolBar;
if (!myToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!myToolBar.LoadToolBar(IDR_MAINFRAME_B))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
At the bottom for my second toolbar but it does not appear when the app is opened and it compiles with no errors.
In comparison to the already supplied toolbar which is called from InitInstance() by pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE , NULL, NULL);
If I call this pFrame->LoadFrame with my second toolbar in the next line the app will not load all together.
How do I need to call my second toolbar?
Have I missed something completely?
You need to add CToolBar myToolBar as a member variable of your CMainFrame class, the same way as m_wndToolBar. Otherwise, it gets destroyed if you define it as a local variable after the OnCreate exits.

C++ why setWindowText doesn't display any text?

I have code as below, and my question is why in the cell A[0][0] setWindowText put nothing?
if(LOWORD( wParam ) == 104){
int td;
int td_width=80;
int tr = 0;
int tr_height=20;
for (tr=0;tr<2;tr++) {
for (td=0;td<10;td++) {
HWND A[tr][td];
A[tr][td] = CreateWindowEx( 0, "EDIT", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL,
td*td_width, tr*tr_height+50, td_width+1, tr_height+1, hwnd, NULL, hInstance, NULL );
}
SetWindowText(A[0][0], "MK" );
}
}
You're defining A[tr][td] inside the inner most loop. This restricts its scope to just that loop. In other words, on each iteration, you're creating a brand new array and assigning just one of its elements.
It's a little surprising that this even compiles. I guess you have another A array defined somewhere else, and that's the one you're referencing in the SetWindowText call.
As Peter said, you are declaring your array in the wrong spot. But more than that, you are also declaring the array as fixed-length but using run-time values to specify its bounds. That will not work, and should not even compile. A fixed-length array's bounds must be known at compile-time, not at run-time.
Try this instead:
if (LOWORD(wParam) == 104)
{
const int td_width = 80;
const int tr_height = 20;
HWND A[2][10];
for (int tr = 0; tr < 2; ++tr)
{
for (int td = 0; td < 10; ++td)
{
A[tr][td] = CreateWindowEx( 0, TEXT("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL, td*td_width, tr*tr_height+50, td_width+1, tr_height+1, hwnd, NULL, hInstance, NULL );
}
}
SetWindowText(A[0][0], TEXT("MK") );
}