IPreviewHandler SetWindow does not specify a size - c++

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 );

Related

C++ MFC Refresh Window

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();
}

ellipse as checked icon in a menu

I'm creating a context menu for a window and I'd like to have in a submenu filled ellipses, each in a different colour, instead of texts - this submenu is responsible for choosing a colour. I don't know how to do it... Does anybody know any concrete example? I've read on MSDN pages about owner-drawn menu items, but there were no example concerning this specific task - so, I don't know how to do it. Later I tried to change checked icon for my menu item - but it turned out my Dev-C++ (under Windows 7) knows neither SetDCBrushColor nor DC_BRUSH, and I still don't know how to change checked icon without loading an image from a file. Then I added at the beginning of my program the following lines:
#define _WIN32_IE 0x0600
#define WINVER 0x0700
#define _WIN32_WINNT 0x0700
Then the compiler doesn't protest, however, the icon is always black, when I'm trying the following code and whatever colour I'm choosing:
HWND hwnd = GetDesktopWindow();
HDC hdc = GetDC( hwnd );
HDC hdcMem = CreateCompatibleDC( hdc );
SIZE size = { GetSystemMetrics( SM_CXMENUCHECK ), GetSystemMetrics( SM_CYMENUCHECK ) };
HBITMAP bitmap = CreateCompatibleBitmap( hdcMem, size.cx, size.cy );
HBITMAP bitmapOld = (HBITMAP) SelectObject( hdcMem, bitmap );
PatBlt( hdcMem, 0, 0, size.cx, size.cy, WHITENESS );
HBRUSH brushOld = (HBRUSH) SelectObject( hdcMem, GetStockObject( NULL_BRUSH ) );
Ellipse( hdcMem, 0, 0, size.cx, size.cy);
SetDCBrushColor( hdcMem, RGB(0,0,255) );
SelectObject( hdcMem, GetStockObject( DC_BRUSH ) );
Ellipse( hdcMem, 2, 2, size.cx-2, size.cy-2 );
SelectObject( hdcMem, brushOld );
SelectObject( hdcMem, bitmapOld );
DeleteDC( hdcMem );
ReleaseDC( hwnd, hdc );
SetMenuItemBitmaps( mnu_t, (30*M_MENU_T+25), MF_BYCOMMAND, bitmap, bitmap);// mnu_t and M_MENU_T are my variables
Can anyone help me?
The problem is here:
HBITMAP bitmap = CreateCompatibleBitmap( hdcMem, size.cx, size.cy );
This is a perfectly natural and rational statement to write, but it doesn't do what most people expect it to do. It's a common mistake and it can take forever to figure out that the source of the problem is here. I know this from making this very mistake more than once myself.
CreateCompatibleBitmap does not create a bitmap that's compatible with the specified device context (DC). Well, it does--sort of--but it's actually more nuanced that: It creates a new bitmap that's compatible with the bitmap that's selected into the specified DC.
When creating a memory DC with CreateCompatibleDC, the new DC gets a default bitmap that is 1 pixel wide by 1 pixel high and with a color depth of 1 bit. This is not intuitive at all, since you asked for the DC to be compatible with the screen DC, and the screen (almost certainly) has more than 1 bit of color depth.
So when you call CreateCompatibleBitmap you get a new bitmap of the specified size that uses 1 bit per pixel. You can draw to it, and, if the stars align, you'll see a crude outline of what you drew. But if the stars aren't aligned, you'll end up with all the pixels being a single color.
When you blit a 1-bit per pixel bitmap to another DC, the current text foreground and background colors are used. Since the foreground text color is often black, you end up with a black rectangle and virtually no clue as to where you went wrong.
The solution is to specify the screen or window DC instead of the memory DC in the call the CreateCompatibleBitmap. This will create a new bitmap that has the same color depth as the bitmap used by the screen, which is far more useful.

window with transparent client area

I register the window class like this:
WNDCLASSEX wctt;
wctt.cbSize = sizeof(WNDCLASSEX);
wctt.style = CS_DBLCLKS;
wctt.lpfnWndProc = WndProcTooltip;
wctt.cbClsExtra = 0;
wctt.cbWndExtra = 0;
wctt.hInstance = m_hAppInstance;
wctt.hIcon = NULL;
wctt.hCursor = LoadCursor(NULL, IDC_SIZE);
wctt.hbrBackground = NULL;
wctt.lpszMenuName = NULL;
wctt.lpszClassName = _T("myWindow");
wctt.hIconSm = NULL;
RegisterClassEx(&wctt)
As you can see I use wctt.hbrBackground = NULL; so it will have no background.
The window is created like this:
::CreateWindowEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
_T("myWindow"),
NULL,
WS_VISIBLE | WS_POPUP,
50,
50,
150,
100,
NULL,
NULL,
m_hAppInstance,
NULL);
In the paint section I draw icon on the window:
PAINTSTRUCT ps;
HDC hdc;
BITMAP bitmap;
ICONINFO iconinfo;
hdc = ::BeginPaint(hWnd, &ps);
::SetBkMode(hdc,TRANSPARENT);
::GetIconInfo(localIcon, &iconinfo);
::GetObject(iconinfo.hbmColor, sizeof(bitmap), &bitmap);
::DeleteObject(iconinfo.hbmColor);
::DeleteObject(iconinfo.hbmMask);
::DrawIconEx(hdc, 0,0, localIcon, bitmap.bmWidth, bitmap.bmHeight, 0, NULL, DI_NORMAL);
The icon size is smaller than the window size and I get on the background the current view on the window below the popup.
But now when I move the window (or minimize the window below the popup) the background is not changing.
I was trying to make a timer that each time do the flowing:
RECT rcClient;
GetClientRect(hWnd, &rcClient);
InvalidateRect(hWnd,&rcClient,TRUE);
This makes the print function run again but the background of the icon is not changing.
Should I do anything in WM_ERASEBKGND?
Does Anyone have any idea how to make it work?
thanks,
guy
It's not enough to just let the background stay unpainted; you also need to get the window below yours to repaint itself when necessary.
If the windows are part of the same hierarchy, created by the same thread, it is sufficient to give your window the WS_EX_TRANSPARENT extended style. This causes the window underneath to paint itself first so the background is always up-to-date.
Otherwise you need to use SetWindowRgn so that your window actually doesn't exist outside of the borders you wish to paint.
Look at Layered Window. This feature allows creating semi-transparent windows of different shapes.
Add WS_EX_LAYERED extended attribute in your window class.
You can control the transparency of your window with these two functions:
SetLayeredWindowAttributes:
bAlpha controls the opacity of the entire window, if you pass LWA_ALPHA in dwFlags.
When bAlpha is 0, the window is completely transparent. When bAlpha is 255, the window is opaque.
crKey sets the color that would transparent.
All pixels painted by the window in this color will be transparent.
UpdateLayeredWindow gives you precise control over window transparency, you can give different parts of window different levels of transparency.
If you're trying to create a non-rectangular window, this is not sufficient. Setting "no background" simply means the background will not be drawn, and you'll see whatever happens to be in memory at that location.
To create a non-rectangular window, have a look at the SetWindowRgn function.

Drawing multiple bitmaps on one Device Context in MFC - winapi

I want to use a single CDC, inwhich to draw 3 bitmaps, positioned in the CDC, and then pass it into UpdateLayeredWindow. My problem is that I can't get the SIZE* psize parameter of the UpdateLayeredWindow function right! Can Anyone help? What do I do?
BLENDFUNCTION bBlendFnc = {
AC_SRC_OVER,
0,
255,
AC_SRC_ALPHA
};
CBitmap btCdcBuff;
CBitmap* cache;
BITMAP hbCdcBuff;
btCdcBuff.CreateCompatibleBitmap(pCdcMain, szWndSize.cx, szWndSize.cy); btCdcBuff.GetBitmap(&hbCdcBuff);
cache = pCdcMain->SelectObject(&btCdcBuff); // pCdcMain is a compatible CDC with the screen (pCdcScreen)
Blend(&btIcon); // This function just creates a compatible CDC from a CPaintDC, selects the passed in CBitmap via SelectObject and AlphaBlends it to the pCdcMain.
pCdcMain->SelectObject(cache);
UpdateLayeredWindow(pCdcScreen, NULL, new CSize(hbCdcBuff.bmWidth, hbCdcBuff.bmHeight), pCdcMain, new CPoint(0, 0), 0, &bBlendFnc, ULW_ALPHA) // This fails and returns false
When using CreateCompatibleBitmap with UpdateLayeredWindow, make sure you pass in the CDC for the screen (ie, pCdcScreen not pCdcMain), so that the Bitmap created is of the correct format. See this thread: http://social.msdn.microsoft.com/Forums/en/windowsuidevelopment/thread/1fbcf5e4-b9eb-4537-bf0b-d330aa333fea

SDL - C++ can't load more than one image

I can't load more than a png: indeed the only image to be blittered is the first to load. There's no error.
boy = IMG_Load(strcat(imagedir,"boy.png"));
SDL_Rect boyrect = {0,0,50,50};
SDL_BlitSurface( boy, &boyrect, screen, NULL );
bar = IMG_Load(strcat(imagedir,"bar.png"));
SDL_Rect barrect = {0,-SCREEN_HEIGHT+150,SCREEN_WIDTH,SCREEN_HEIGHT};
SDL_BlitSurface( bar, &barrect, screen, NULL );
The second argument is the SDL_Rect from source, and the fourth argument the zone to paste.
I think you want to paste each png in a part of the screen.
SDL_BlitSurface( boy, NULL, screen, &boyrect );
SDL_BlitSurface( bar, NULL, screen, &barrect );