Remove tabs bar from CTabCtrl when there is only one page - mfc

i have created a CTabCtrlinside a CDockablePane, and i have added only one page, then there is no need to show the tabs bar.
how can i remove the tab bar when there is only one page ?
Thanks in advance :)

You can hide the tab and use CTabCtrl::AdjustRect to reposition the child pages. For example:
void CMyDialog::show_tab_bar(bool show)
{
tab.ShowWindow(show ? SW_SHOW : SW_HIDE);
CRect r;
tab.GetWindowRect(&r);
ScreenToClient(&r);
tab.AdjustRect(FALSE, &r);
page1.SetWindowPos(0, r.left, r.top, r.Width(), r.Height(), SWP_HIDEWINDOW);
page2.SetWindowPos(0, r.left, r.top, r.Width(), r.Height(), SWP_HIDEWINDOW);
...
page1.ShowWindow(SW_SHOW);
}
Alternatively you can use CTabCtrl::DeleteAllItems if you want the tab borders to be visible always.
void CMyDialog::show_tab_bar(bool show)
{
tab.DeleteAllItems();
if (show)
{
tab.InsertItem(0, L"Page 1");
tab.InsertItem(1, L"Page 2");
...
}
CRect r;
tab.GetWindowRect(&r);
ScreenToClient(&r);
tab.AdjustRect(FALSE, &r);
page1.SetWindowPos(0, r.left, r.top, r.Width(), r.Height(), SWP_HIDEWINDOW);
page2.SetWindowPos(0, r.left, r.top, r.Width(), r.Height(), SWP_HIDEWINDOW);
...
page1.ShowWindow(SW_SHOW);
}

Related

Capturing a specific window using BitBlt return the black or transparent border which represent the classic gui layer

I tried to capture a screenshot of specific window using BitBlt and save it to clipboard, but it returns the screenshot with the content inside window border only while the window border itself is remain transparent or blacked out with many weird behaviors.
The expected result should be the full window border with the full content:
This is the actual result:
This is what I tried:
Comment the SetLayeredWindowAttributes function before performing BitBlt but the result is the entire black screenshot.
Tried to set the delay after UpdateWindow function but the weird border remains the same.
Disabling some coded option but it didn't help...
Use PrintWindow but the result is the classic gui border, which is not the intended goal (and many article indicate about the problem with this function).
I don't have any idea why this happened nor able to find out due to lack of information of this command when searching Internet.
Is there anything wrong with my code?
void QuickScreenshot()
{
HWND windowHandle(::FindWindowW(0, L"Internet Download Manager 6.41"));
ANIMATIONINFO AnimationInfo{};
SystemParametersInfoW(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, NULL);
auto DefaultAnimationInfo(AnimationInfo);
AnimationInfo.iMinAnimate = 0;
DefaultAnimationInfo.cbSize = sizeof(ANIMATIONINFO);
SystemParametersInfoW(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, WM_SETTINGCHANGE);
auto originalExstyle(GetWindowLongW(windowHandle, GWL_EXSTYLE));
SetWindowLongW(windowHandle, GWL_EXSTYLE, WS_EX_LAYERED);
COLORREF windowColor;
BYTE windowAlpha, customAlpha(1);
DWORD flag;
WINDOWPLACEMENT windowState{};
windowState.length = sizeof(WINDOWPLACEMENT);
GetLayeredWindowAttributes(windowHandle, &windowColor, &windowAlpha, &flag);
SetLayeredWindowAttributes(windowHandle, windowColor, customAlpha, flag);
GetWindowPlacement(windowHandle, &windowState);
if (windowState.showCmd == SW_SHOWMINIMIZED)
{
if ((windowState.flags & WPF_RESTORETOMAXIMIZED) == WPF_RESTORETOMAXIMIZED)
{
ShowWindow(windowHandle, SW_MAXIMIZE);
}
else
{
ShowWindow(windowHandle, SW_SHOWNORMAL);
}
}
else
{
ShowWindow(windowHandle, windowState.showCmd);
}
RECT windowRectangleCoordinates;
GetWindowRect(windowHandle, &windowRectangleCoordinates);
InvalidateRect(windowHandle, &windowRectangleCoordinates, TRUE);
UpdateWindow(windowHandle);
Sleep(100);
HDC ScreenContentHandle(GetWindowDC(windowHandle));
HDC DestinationContentHandle(CreateCompatibleDC(ScreenContentHandle));
auto cx(windowRectangleCoordinates.right - windowRectangleCoordinates.left);
auto cy(windowRectangleCoordinates.bottom - windowRectangleCoordinates.top);
HBITMAP BitmapHandle(CreateCompatibleBitmap(ScreenContentHandle, cx, cy));
HGDIOBJ oldObject(SelectObject(DestinationContentHandle, BitmapHandle));
//PrintWindow(windowHandle, ScreenContentHandle, NULL);
BitBlt
(
DestinationContentHandle,
0, 0, cx, cy,
ScreenContentHandle,
0, 0,
SRCCOPY | CAPTUREBLT
);
SaveToClipboard(BitmapHandle);
SelectObject(DestinationContentHandle, oldObject);
DeleteDC(DestinationContentHandle));
ReleaseDC(NULL, ScreenContentHandle));
DeleteObject(BitmapHandle));
ShowWindow(windowHandle, SW_MINIMIZE);
SetLayeredWindowAttributes(windowHandle, windowColor, windowAlpha, flag);
SetWindowLongW(windowHandle, GWL_EXSTYLE, originalExstyle);
SystemParametersInfoW(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &DefaultAnimationInfo, WM_SETTINGCHANGE);
}

Resizing a modeless property sheet

I have a class derived from CPropertysheet. It has two property pages in it. I have made the sheet modeless. But resizing using the mouse drag is not possible. How to make the propertysheet a resizable one?
For modal property sheet see links in comment section. For modeless version, create the property sheet with WS_THICKFRAME. This is enough to make the dialog resizable. For example:
propSheet->Create(this, WS_THICKFRAME |
WS_VISIBLE | WS_SYSMENU | WS_POPUP | WS_VISIBLE | WS_CAPTION);
To handle the resizing, add the following members:
class CMyPropertySheet:public CPropertySheet
{
CRect save_rc;//used in OnSize
CRect minimum_rc;//used in OnGetMinMaxInfo
BOOL OnInitDialog();
void OnSize(UINT nType, int cx, int cy);
void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI);
...
};
Overload OnInitDialog as follows:
BOOL CMyPropertySheet::OnInitDialog()
{
//override for modeless:
m_bModeless = FALSE;
m_nFlags |= WF_CONTINUEMODAL;
BOOL bResult = CPropertySheet::OnInitDialog();
m_bModeless = TRUE;
m_nFlags &= ~WF_CONTINUEMODAL;
//save rectangles for resizing
GetClientRect(&save_rc); //save the old rect for resizing
GetClientRect(&minimum_rc); //save the original rect for OnGetMinMaxInfo
return bResult;
}
The rest of it is explained in MSDN example:
void CMyPropertySheet::OnSize(UINT nType, int cx, int cy)
{
CPropertySheet::OnSize(nType, cx, cy);
if(nType == SIZE_MINIMIZED)
return;
if (!GetActivePage()) return;
if (!GetTabControl()) return;
int dx = cx - save_rc.Width();
int dy = cy - save_rc.Height();
//count how many childs are in window
int count = 0;
for(CWnd *child = GetWindow(GW_CHILD); child; child = child->GetWindow(GW_HWNDNEXT))
count++;
HDWP hDWP = ::BeginDeferWindowPos(count);
for (CWnd *child = GetWindow(GW_CHILD); child; child = child->GetWindow(GW_HWNDNEXT))
{
CRect r;
child->GetWindowRect(&r);
ScreenToClient(&r);
if (child->SendMessage(WM_GETDLGCODE) & DLGC_BUTTON)
{
r.left += dx;
r.top += dy;
::DeferWindowPos(hDWP, child->m_hWnd, 0, r.left, r.top, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
else
{
r.right += dx;
r.bottom += dy;
::DeferWindowPos(hDWP, child->m_hWnd, 0, 0, 0, r.Width(), r.Height(),
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
}
::EndDeferWindowPos(hDWP);
GetClientRect(&save_rc);
}
void CMyPropertySheet::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
lpMMI->ptMinTrackSize.x = minimum_rc.Width();
lpMMI->ptMinTrackSize.y = minimum_rc.Height();
CPropertySheet::OnGetMinMaxInfo(lpMMI);
}
Also add ON_WM_SIZE and ON_WM_GETMINMAXINFO to message map

How to auto resize the text control in mfc

I want to put the text in my IDC_TEXT in MFC. I want to auto resize that control with input text. I used my code but it does not work. Could you help me resolve it?
CFont *m_Font1 = new CFont;
CStatic * m_Label;
m_Font1->CreatePointFont(200, "Time New Roman");
m_Label = (CStatic *)GetDlgItem(IDC_TEXT);
m_Label->SetFont(m_Font1);
m_Label->SetWindowText( _T("") );
//Display text in thread
THREADSTRUCT* ts = (THREADSTRUCT*)param;
CDC* vDC_TXT;
vDC_TXT =ts->_this->GetDlgItem(IDC_TEXT)->GetDC();
ts->_this->GetDlgItem(IDC_TEXT)->SetWindowTextA(text.c_str());
//Update the length-
ts->_this->GetDlgItem(IDC_TEXT)->SetWindowPos(NULL, 0, 0, 1000, 1000, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
However, the number (1000,1000) is set by my hand. I want to auto change based on the text size. Could you have me to solve it?
Update:
If font size is the same, and only text is different, then you should be able to reuse the old font:
void ChangeSize()
{
CWnd* dlgItem = GetDlgItem(IDC_STATIC1);
if (!dlgItem)
return;
CString s;
dlgItem->GetWindowText(s);
CDC dc;
dc.CreateCompatibleDC(NULL);
dc.SelectObject(dlgItem->GetFont());
CRect r;
dlgItem->GetClientRect(&r);
if (s.Find('\n') < 0)
dc.DrawText(s, &r, DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE | DT_EDITCONTROL);
else
dc.DrawText(s, &r, DT_CALCRECT | DT_NOPREFIX | DT_EDITCONTROL);
dlgItem->SetWindowPos(0, 0, 0, r.Width(), r.Height(), SWP_NOMOVE);
}
Previous answer for when font is changing:
m_Font1 should be declared as member data and setup setup once, and created and cleaned up elsewhere. It think that's what you are doing.
Then you can draw text functions to find text size, and resize the control as follows
void ChangeSize()
{
CWnd* dlgItem = GetDlgItem(IDC_STATIC1);
if (!dlgItem)
return;
CString s;
dlgItem->GetWindowText(s);
CDC dc;
dc.CreateCompatibleDC(NULL);
//or just use CClientDC dc(this) if device context is available
dc.SelectObject(m_font);
CRect r;
dlgItem->GetClientRect(&r);
if (s.Find('\n') < 0)
{
//change width/height for single line text
dc.DrawText(s, &r, DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE | DT_EDITCONTROL);
}
else
{
//change height for multiple-line text
dc.DrawText(s, &r, DT_CALCRECT | DT_NOPREFIX | DT_EDITCONTROL);
}
dlgItem->SetWindowPos(0, 0, 0, r.Width(), r.Height(), SWP_NOMOVE);
dlgItem->SetFont(m_font, 1);
}

Wrong CListCtrl items drawing

I have my CListCtrlEx derived from CListCtrl. This list have style LVS_REPORT, LVS_OWNERDRAWFIXED and LVS_EX_GRIDLINES. I have added possibility to change font for this list. This works fine, but there is one bad thing - if I change font and before that I have not been scrolling list, then all list items redraws right, but if I have done scrolling before font changing, then list items redraws a little bit upper or lower than list grid horizontal lines, i. e. items text becomes overlapped by grid lines.
Here is how I changing list font:
LRESULT CListCtrlEx::OnSetFont(WPARAM wParam, LPARAM)
{
LRESULT res = Default();
CRect rc;
GetWindowRect(&rc);
WINDOWPOS wp;
wp.hwnd = m_hWnd;
wp.cx = rc.Width();
wp.cy = rc.Height();
wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;
SendMessage(WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp);
return res;
}
void CListCtrlEx::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
HDC hDC = ::GetDC(NULL);
CFont* pFont = GetFont();
HFONT hFontOld = (HFONT)SelectObject(hDC, pFont->GetSafeHandle());
CRect rect;
DrawText(hDC, _T(" "), 1, rect, DT_SINGLELINE | DT_CALCRECT);
lpMeasureItemStruct->itemHeight = rect.bottom - rect.top;
SelectObject(hDC, hFontOld);
::ReleaseDC(NULL, hDC);
}
UPD:
three people have clicked button UP and nobody knows what it can be? :(
UPD 1:
here's the class code
http://pastebin.com/UdXYEpF7 .h
http://pastebin.com/2HYe5AEd .cpp
I tried your code, it looks like ListView is exchanging messages with scroller, the header is also being resized, it's not really worth investigating. It's fine if you just set position to zero, you can save the old position and put it back.
void CListCtrlEx::SetupFont(int nSize, const CString& strName)
{
int saveIndex = GetTopIndex();
EnsureVisible(0, 0);
if (m_pFont.get()) m_pFont.get()->DeleteObject();
VERIFY(m_pFont.get()->CreatePointFont(nSize, strName));
SetFont(m_pFont.get());
//This scrolls to bottom, it ensures saveIndex will end up on top
//once the next EnsureVisible is called
if (GetItemCount())
EnsureVisible(GetItemCount() - 1, 1);
EnsureVisible(saveIndex, 1);
}

Can't change position of button

In a C++ app I create a button using CreateWindowEx and later try to change its position using SetWindowPos, but the button doesn't appear where I want it.
What's interesting is that when I resize the window (with the mouse, not programatically), I can see for a split second a blank silhouette the same size of the button where the button is supposed to appear. This must be because I also call SetWindowPos in response to window resizing events. However the actual button stays at the same location. I'd post a screenshot but for some reason the silhouette never shows up in screenshots.
This is the code that changes the X position (the code that changes the Y position is almost identical):
HRESULT Control::put_Left(float left)
{
RECT windowRect;
::GetWindowRect(m_hWnd, &windowRect);
if (m_isTopLevel)
{
BOOL bResult = ::SetWindowPos(
m_hWnd,
nullptr,
static_cast<int>(DesktopDpi::GetInstance().DipsToPixelsX(left)),
windowRect.top,
0,
0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOREPOSITION
);
if (!bResult)
return HRESULT_FROM_WIN32(::GetLastError());
}
else
{
// NOTE: for a button this is the code that will execute, because a
// button is not a top-level window
HWND hWndParent = ::GetParent(m_hWnd);
if (hWndParent == nullptr)
return HRESULT_FROM_WIN32(::GetLastError());
POINT parentPos = {0, 0};
if (!::ClientToScreen(hWndParent, &parentPos))
return E_FAIL;
BOOL bResult = ::SetWindowPos(
m_hWnd,
nullptr,
static_cast<int>(DesktopDpi::GetInstance().DipsToPixelsX(left)),
windowRect.top - parentPos.y,
0,
0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOREPOSITION
);
if (!bResult)
return HRESULT_FROM_WIN32(::GetLastError());
}
return S_OK;
}
Are you sure the parent of the button isn't moving it back to the old position when it handles WM_SIZE? It sure sounds like it from your description.