I am using Visual Studio 2010 with MFC and I am trying to make a rectangle that is red when a device is disconnected and green when it is. I have made the rectangle with the following code:
CRect lConnectStatus;
GetDlgItem( IDC_CONNECT_STATUS ) -> GetClientRect( &lConnectStatus );
GetDlgItem( IDC_CONNECT_STATUS ) -> ClientToScreen( &lConnectStatus );
ScreenToClient( &lConnectStatus );
mConnected.Create( GetSafeHwnd(), 10000 );
mConnected.SetPosition( lConnectStatus.left, lConnectStatus.top, lConnectStatus.Width(), lConnectStatus.Height() );
if( mDevice.IsConnected() ){
mConnected.SetBackgroundColor(0, 255, 0);
}
else{mConnected.SetBackgroundColor(0, 0, 255);}
I inserted this snippet into the OnInitDlg method and the rectangle does appear, but it doesn't change to green when the device gets connected. Is there anyway I can refresh the window so that the code is executed again and the colour changes to green?
What type of control is IDC_CONNECT_STATUS? If it is a static control you can eliminate all this code and handle WM_CTLCOLOR_STATIC in the parent dialog. Your message handler for that message will control the color of the static control. To refresh the static control call Invalidate on that control. That will cause it to call your WM_CTLCOLOR_STATIC message handler.
Solved It, As I am new to C++ I didn't know that putting the code snippet into the OnInitDlg() method wouldn't work. So I put the code into the OnPaint()method and used the functions Invalidate() and UpdateWindow() to force the window to refresh when the device was connected/disconnected. Thanks for your help.
Edit Thanks to Barmak for suggesting not to create the control in the OnPaint() method. I have updated the code below.
program::OnInitDlg(){
CRect lConnectStatus;
GetDlgItem( IDC_CONNECT_STATUS ) -> GetClientRect( &lConnectStatus );
GetDlgItem( IDC_CONNECT_STATUS ) -> ClientToScreen( &lConnectStatus );
ScreenToClient( &lConnectStatus );
mConnected.Create( GetSafeHwnd(), 10000 );
mConnected.SetPosition( lConnectStatus.left, lConnectStatus.top, lConnectStatus.Width(), lConnectStatus.Height() );
}
program::OnPaint(){
if( mDevice.IsConnected() ){
mConnected.SetBackgroundColor(0, 255, 0);
}
else{mConnected.SetBackgroundColor(0, 0, 255);}
}
program::Connect(){
Invalidate();
UpdateWindow();
}
program::disconnect(){
Invalidate();
UpdateWindow();
}
Related
I want to add a preview on my window. A rectangle is passed into the function in which the preview will be drawn, but for some reason the preview is drawn in the entire window and not in the specified rectangle.
RECT rectPreview;
rectPreview.top=10;
rectPreview.left=10;
rectPreview.right=100;
rectPreview.bottom=100;
IPreviewHandler *pIPreviewHandler(NULL) ;
CoCreateInstance( cls, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IPreviewHandler, (LPVOID*)&pIPreviewHandler );
//some code
pIPreviewHandler->SetWindow( hWnd , &rectPreview );
pIPreviewHandler->SetRect( &rectPreview );
pIPreviewHandler->DoPreview( );
How to set the drawing rectangle so that the preview is only in it?
just need to call SetRect after DoPreview
pIPreviewHandler->DoPreview();
pIPreviewHandler->SetRect( &rectPreview );
I have a CPropertySheet that I am using to show three CPropertyPages. I removed the default "Apply" and "Help" buttons. My problem comes that now that they are removed, I have a large gap where they were once located. Is there a way to remove this gap? Thanks!
Here is a picture of the gap I speak of:
Before the buttons were removed, they were located to the right side of the gap. Please note that the "Change Options" page was created in Visual Studio's designer and the page ends right under the Print button. The main Admin Options CPropertySheet was created entirely from code.
Here is the code to initialize the CPropertySheet and pages (and the removal of the "Help" and "Apply" buttons:
BEGIN_MESSAGE_MAP(CSLIMOptCplusplusApp, CWinApp)
//ON_COMMAND(ID_HELP, &CWinApp::OnHelp) Commented out to remove the "Help" button
END_MESSAGE_MAP()
BOOL OptCplusplusApp::InitInstance()
{
CWinApp::InitInstance();
SQLHENV m_1;
EnvGetHandle(m_1);
Login lgn; //Creates a Login dialog for the user to enter credentials.
lgn.DoModal();
CImageSheet* imagedlg = new CImageSheet( "SLIM Admin Options" );
CImageDisplay* pageImageDisplay = new CImageDisplay;
CImageDimensions* pageImageDimensions = new CImageDimensions;
ListOption* pageListOption = new ListOption;
ASSERT( imagedlg );
ASSERT( pageImageDisplay );
ASSERT( pageImageDimensions );
ASSERT( pageListOption );
imagedlg->AddPage( pageListOption);
imagedlg->AddPage( pageImageDisplay );
imagedlg->AddPage( pageImageDimensions );
imagedlg->m_psh.dwFlags |= PSH_NOAPPLYNOW; //Removes the default Apply button
imagedlg->Create();
imagedlg->ShowWindow( SW_SHOW );
m_pMainWnd = imagedlg;
I will edit if any further details are needed. Thanks.
To achieve this kind of a look with a property sheet....
You need to handle OnitDialog within the sheet and re-size it. For example, using a combination of CPropertySheet::GetPage and CWnd::MoveWindow will accomplish what you want.
BOOL MyPropSheet::OnInitDialog()
{
BOOL bResult = CPropertySheet::OnInitDialog();
// TODO: Add your specialized code here
CPropertyPage* pg1 = GetPage(0);
CRect rect(0, 0, 0, 0);
pg1->GetWindowRect(&rect);
CRect thisRect(0, 0, 0, 0);
GetWindowRect(&thisRect);
thisRect.bottom = rect.bottom + 16;
MoveWindow(&thisRect);
return bResult;
}
I have a tab control in my Win32 application. The control is multi-row capable. When I resize the window such that the tab control is reduced in width, multiple rows show up. The problem is that when I click on one of the lower rows the tabs in the upper rows are blocked by the current tab's window( the tab control doesn't properly resize the content window of the current tab so that the upper rows are visible ). How do I account for this problem?
Here is code for my resize function:
RECT cr;
GetClientRect( pHdr->hWndTab, &cr );
TabCtrl_AdjustRect( pHdr->hWndTab, FALSE, &cr );
OffsetRect( &cr, cxMargin - cr.left, cyMargin - cr.top );
SetWindowPos( pHdr->hWndDisplay, 0, cr.left, cr.top, cr.right, cr.bottom, SWP_SHOWWINDOW );
This code comes from Microsoft website...
pHdr->hWndTab is the window handle for the tab control
pHdr->hWndDisplay is the window handle for the content window of the current tab
EDIT: Actually, after clicking the lower tabs, the upper tabs move to the top of control...however, they are still blocked by the content window...
I fixed the problem by adjusting the display rectangle after offsetting:
typedef struct tag_dlghdr
{
HWND hWndTab;
HWND hWndDisplay;
RECT rcDisplay;
DLGTEMPLATE *apRes[ MAX_PAGES ];
DLGPROC MsgProc[ MAX_PAGES ];
}DLGHDR
Resize( HWND hWndDlg )
{
DLGHDR *pHdr = ( DLGHDR * )GetWindowLong( hWndDlg, GWL_USERDATA );
DWORD dwDlgBase = GetDialogBaseUnits();
int cxMargin = LOWORD( dwDlgBase ) / 4;
int cyMargin = HIWORD( dwDlgBase ) / 8;
m_niCurTabSel = TabCtrl_GetCurSel( pHdr->hWndTab );
RECT cr;
GetClientRect( pHdr->hWndTab, &cr );
TabCtrl_AdjustRect( pHdr->hWndTab, FALSE, &cr );
OffsetRect( &cr, cxMargin - cr.left, cyMargin - cr.top );
CopyRect( &pHdr->rcDisplay, &cr );
TabCtrl_AdjustRect( pHdr->hWndTab, FALSE, &pHdr->rcDisplay );
SetWindowPos( pHdr->hWndDisplay, 0, pHdr->rcDisplay.left, pHdr->rcDisplay.top, pHdr->rcDisplay.right, pHdr->rcDisplay.bottom, SWP_SHOWWINDOW );
}
I have written Following code which will apply color to all static text in one window, but
I want to apply two different colors in one window like ID:1234 where ID is another color and 1234 will be different color in one window. How can I do this? here is what i have done:
case WM_CTLCOLORSTATIC:
SetBkColor( hdc, COLORREF( :: GetSysColor( COLOR_3DFACE) ) );
//sets bckcolor of static text same as window color
if ( ( HWND ) lParam == GetDlgItem( hWnd, IDC_PID) )
{
SetTextColor( ( HDC ) wParam, RGB( 250, 50, 200));
return ( BOOL ) CreateSolidBrush ( GetSysColor( COLOR_3DFACE) );
}
break;
I'm not sure I understand your problem. Your code looks pretty much ok. One point worth noting is that you are responsible for cleaning up resources that you allocate. With the code above you are leaking the HBRUSH object created through a call to CreateSolidBrush. Since you don't need a custom brush you should rather be using GetSysColorBrush.
As a matter of taste I would filter on the control ID rather than its window handle using GetDlgCtrlID. Incorporating the changes your code should look like this:
case WM_CTLCOLORSTATIC:
switch ( GetDlgCtrlID( (HWND)lParam ) )
{
case IDC_PID:
//sets bckcolor of static text same as window color
SetBkColor( (HDC)wParam, COLORREF( GetSysColor( COLOR_3DFACE ) ) );
SetTextColor( (HDC)wParam, RGB( 250, 50, 200) );
return (INT_PTR)GetSysColorBrush( COLOR_3DFACE );
default:
// Message wasn't handled -> pass it on to the default handler
return 0;
}
I have a Windows Template Library CListViewCtrl in report mode (so there is a header with 2 columns) with owner data set. This control displays search results. If no results are returned I want to display a message in the listbox area that indicates that there were no results. Is there an easy way to do this? Do you know of any existing controls/sample code (I couldn't find anything).
Otherwise, if I subclass the control to provide this functionality what would be a good approach?
I ended up subclassing the control and handling OnPaint like this:
class MsgListViewCtrl : public CWindowImpl< MsgListViewCtrl, WTL::CListViewCtrl >
{
std::wstring m_message;
public:
MsgListViewCtrl(void) {}
BEGIN_MSG_MAP(MsgListViewCtrl)
MSG_WM_PAINT( OnPaint )
END_MSG_MAP()
void Attach( HWND hwnd )
{
SubclassWindow( hwnd );
}
void SetStatusMessage( const std::wstring& msg )
{
m_message = msg;
}
void OnPaint( HDC hDc )
{
SetMsgHandled( FALSE );
if( GetItemCount() == 0 )
{
if( !m_message.empty() )
{
CRect cRect, hdrRect;
GetClientRect( &cRect );
this->GetHeader().GetClientRect( &hdrRect );
cRect.top += hdrRect.Height() + 5;
PAINTSTRUCT ps;
SIZE size;
WTL::CDCHandle handle = this->BeginPaint( &ps );
handle.SelectFont( this->GetFont() );
handle.GetTextExtent( m_message.c_str(), (int)m_message.length(), &size );
cRect.bottom = cRect.top + size.cy;
handle.DrawText( m_message.c_str(), -1, &cRect, DT_CENTER | DT_SINGLELINE | DT_VCENTER );
this->EndPaint( &ps );
SetMsgHandled( TRUE );
}
}
}
};
After the search runs, if there are no results, I call SetStatusMessage and the message is displayed centered under the header. That's what I wanted. I'm kind of a newbie at subclassing controls so I'm not sure if this is the best solution.
If you're on Vista or later, handle the LVN_GETEMPTYMARKUP notification. For pre-Vista, you'll need to paint the message yourself.
Another idea is to have another control, with the same size and position as the list control, but hidden. Could be an edit control, static text, browser control, or what have you.
Then when you don't have any search results, you put the message in this control, and un-hide it. When the user does another search that returns results, you hide this control and show the results in the list view normally.