Well I want a pretty simple thing, but a bit of confused.
void CAppDlg::OnPaint()
{
CPaintDC dc(this);
CDC pdc;
pdc.CreateCompatibleDC(&dc);
CBitmap *oldBmp = pdc.SelectObject(&m_BmpImg[0]);
dc.BitBlt(0, 0, m_SizBmpImg[0].cx, m_SizBmpImg[0].cy, &pdc, 0, 0, SRCCOPY);
dc.SelectObject(&oldBmp);
}
In the above code snippet I would like to put last 3 lines to a separate function. Now I cannot pass CPaintDC as a function parameter, I need to convert it to CDC or CMemDC. And also how do I pass this pdc (CDC pdc) or shall I create a new one inside my function.
A sample with bit of explanation would be off a great help.
This should work.
void CAppDlg::OnPaint()
{
CPaintDC dc(this);
CDC pdc;
pdc.CreateCompatibleDC(&dc);
YourSeparateFUnction(dc, pdc);
}
void CAppDlg::YourSeparateFUnction(CPaintDC & dc, CDC & pdc)
{
CBitmap *oldBmp = pdc.SelectObject(&m_BmpImg[0]);
dc.BitBlt(0, 0, m_SizBmpImg[0].cx, m_SizBmpImg[0].cy, &pdc, 0, 0, SRCCOPY);
dc.SelectObject(&oldBmp);
}
Related
As mention from microsft doc. WM_NCPAINT is use to paint non-client area. it means like title bar. https://learn.microsoft.com/en-us/windows/win32/gdi/wm-ncpaint. But i get unexpected result. it paint client area too. and the weird one. title bar is gone. when launch. after ALT+TAB. the title bar appears with windows 7 style in windows 10.
class CMainFrame::CFrameWnd
{
public:
CMainFrame()
{
Create(
NULL,
"Hello World!",
WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU,
CRect(CPoint(100, 100), CSize(640, 360));
}
protected:
afx_msg void OnNcPaint();
DECLARE_MESSAGE_MAP()
}
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_NCPAINT()
END_MESSAGE_MAP()
void CMainFrame::OnNcPaint()
{
PAINTSTRUCT ps;
CBrush brush;
brush.CreateSolidBrush(RGB(0, 0, 255));
CDC *pDC = BeginPaint(&ps);
pDC->FillRect(&ps.rcPaint, &brush);
EndPaint(&ps);
}
class CApplication : public CWinApp {
BOOL InitInstance() {
CMainFrame* mainWnd = new CMainFrame();
m_pMainWnd = mainWnd;
mainWnd->ShowWindow(SW_NORMAL);
mainWnd->UpdateWindow();
return TRUE;
}
};
In InitInstance, you must call the base class CWinApp::InitInstance() in the first line.
Create your main frame window using
CreateEx(0, AfxRegisterWndClass(0), "Hello World!",
WS_VISIBLE | WS_OVERLAPPEDWINDOW, 100, 100, 640, 360, NULL, 0);
Add PreCreateWindow to control the edges and other properties
int CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
auto res = CFrameWnd::PreCreateWindow(cs);
cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
return res;
}
Use the appropriate paint classes, CPaintDC dc(this), CWindowDC, for overriding OnPaint or OnNcPaint (avoid overriding OnNcPaint), use CClientDC dc(this) for other client area paints. Avoid calling WinAPI functions directly, for example avoid calling BeginPaint. You can also use Visual Studio to create a sample dialog based application, it will be easier to get started with that.
I need to add custom menu items as needed. I found OnInitMenuPopup (WM_INITMENUPOPUP) does what I need but I can't get an icon to show next to the text on the menu? I've tried a 16x16 png graphic using m_MyGraphic as a CPngImage, I've tried attaching it to a CBitmap, I've tried saving the graphic as a .bmp and loading as CBitmap. I've tried not setting the graphic on the load, but then trying to do it with SetMenuItemBitmaps(), I've tried a 13x13 graphic, I've tried a 15x15 graphic (which matches GetMenuCheckMarkDimensions()). Never does a graphic show next to the menu item? What am I doing wrong or missing?
TIA!
void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
// add items
if (pPopupMenu && pPopupMenu->GetMenuItemCount() > 0 && pPopupMenu->GetMenuItemID(0) == ID_MY_EXPECTED_ID) {
// loop though and add menu items
for (UINT i=0; i<theApp.m_MyList.GetCount(); i++) {
CString s;
s.Format(_T("%i: %s"), i, theApp.m_MyList[i].String);
MENUITEMINFO mii={};
mii.cbSize=sizeof(mii);
mii.fMask=MIIM_ID|MIIM_STRING|MIIM_BITMAP;
mii.wID=ID_MY_RANGE_0+i;
mii.dwTypeData=s.GetBuffer();
mii.hbmpItem=(HBITMAP)m_MyBitmap.GetSafeHandle();
pPopupMenu->InsertMenuItem(i+1, &mii, TRUE);
// not working above so tried using this as well but it doesn't work either:
//pPopupMenu->SetMenuItemBitmaps(i+1, MF_BYPOSITION, &m_MyBitmap, &m_MyBitmap);
}
}
CFrameWndEx::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
}
I found a work around. First add CMFCToolBarMenuButton::m_bAlwaysCallOwnerDraw=TRUE; somewhere on initialization.
Then handle drawing it:
BOOL CMainFrame::OnDrawMenuImage(CDC* pDC, const CMFCToolBarMenuButton* pMenuButton, const CRect& rectImage)
{
BOOL result=FALSE;
if (pMenuButton->m_nID>=ID_MY_RANGE_0 && pMenuButton->m_nID<=ID_MY_RANGE_N) {
// size to use on menu
CSize sizemenuimage = CMFCToolBar::GetMenuImageSize();
// get size of our bitmap
BITMAP bitmap;
m_MyBitmap.GetBitmap(&bitmap);
// create dc to attach bitmap to
CDC dcmem;
if (dcmem.CreateCompatibleDC(pDC)) {
// attach bitmap to dc
CBitmap * poldbitmap=dcmem.SelectObject(&m_MyBitmap);
if (poldbitmap) {
// Draw bitmap
result=pDC->StretchBlt(rectImage.left+(rectImage.Width()-sizemenuimage.cx)/2,
rectImage.top+(rectImage.Height()-sizemenuimage.cy)/2,
sizemenuimage.cx, sizemenuimage.cy,
&dcmem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);
// Select original object
dcmem.SelectObject(poldbitmap);
}
dcmem.DeleteDC();
}
}
return result;
}
Another possible solution (if you already have the bitmaps for toolbar) is:
void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
CMDIFrameWnd::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
// TODO: Add your message handler code here
HICON hIcon = AfxGetApp()->LoadIcon(IDR_TESTMETYPE);
pPopupMenu->SetMenuItemBitmaps(ID_FILE_NEW, MF_BYCOMMAND, ConvertIconToBitmap(hIcon), NULL);
...
...
}
where SetMenuItemBitmaps is defined as:
CBitmap* CMainFrame::ConvertIconToBitmap(HICON hIcon)
{
CDC dc;
CBitmap bmp;
CClientDC ClientDC(this);
dc.CreateCompatibleDC(&ClientDC);
bmp.CreateCompatibleBitmap(&ClientDC, 13, 13);
CBitmap* pOldBmp = (CBitmap*)dc.SelectObject(&bmp);
::DrawIconEx(dc.GetSafeHdc(), 0, 0, hIcon, 13, 13, 0, (HBRUSH)RGB(255, 255, 255), DI_NORMAL);
dc.SelectObject(pOldBmp);
dc.DeleteDC();
HBITMAP hBitmap = (HBITMAP)::CopyImage((HANDLE)((HBITMAP)bmp),
IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE);
return CBitmap::FromHandle(hBitmap);
}
suppose that I have COpenGLControl class downloaded here from codeguru assuming that the first event handler runned when creating the OpenGL window is OnCreate, I have tried to catch up the errors of this class. here's the code used to create the window in my dialog's .h and .cpp files:
MyOpenGLTestDlg.h
COpenGLControl m_oglWindow;
MyOpenGLTestDlg.cpp
CRect rect;
// Get size and position of the picture control
GetDlgItem(ID_OPENGL)->GetWindowRect(rect);
// Convert screen coordinates to client coordinates
ScreenToClient(rect);
up to know I think the function OnCreate has been invoked. In fact, I think the line of code COpenGLControl m_oglWindow; causes this function to be invoked! but I'm not sure so it will be appreciated if you guide me alittle about this?
anyway, I have not made a lot of change to the class:
OpenGLControl.h
#pragma once
#include "afxwin.h"
#include "WinBase.h"
#include <gl/gl.h>
#include <gl/glu.h>
class COpenGLControl : public CWnd
{
public:
/******************/
/* Public Members */
/******************/
UINT_PTR m_unpTimer;
// View information variables
float m_fLastX;
float m_fLastY;
float m_fPosX;
float m_fPosY;
float m_fZoom;
float m_fRotX;
float m_fRotY;
bool m_bIsMaximized;
private:
/*******************/
/* Private Members */
/*******************/
// Window information
CWnd *hWnd; //window handle
HDC hdc; //device context handle
HGLRC hrc; //handle to GL Rendering Context
int m_nPixelFormat;
CRect m_rect;
CRect m_oldWindow;
CRect m_originalRect;
public:
COpenGLControl(void);
virtual ~COpenGLControl(void);
void oglCreate(CRect rect, CWnd *parent);
void oglInitialize(void);
void oglDrawScene(void);
// Added message classes:
afx_msg void OnPaint();
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnDraw(CDC *pDC);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
DECLARE_MESSAGE_MAP()
};
OpenGLControl.cpp
int COpenGLControl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1) return -1;
oglInitialize();
return 0;
}
void COpenGLControl::oglInitialize(void)
{
// Initial Setup:
//
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
32, // bit depth
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
24, // z-buffer depth
8,0,PFD_MAIN_PLANE, 0, 0, 0, 0,
};
// Get device context only once.
hdc = GetDC()->m_hDC;
// Pixel format.
m_nPixelFormat = ChoosePixelFormat(hdc, &pfd);
SetPixelFormat(hdc, m_nPixelFormat, &pfd);
// Create the OpenGL Rendering Context.
hrc = wglCreateContext(hdc);
GLenum error13 = glGetError();
wglMakeCurrent(hdc, hrc);
// Basic Setup:
//
// Set color to use when clearing the background.
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepth(1.0f);
// Turn on backface culling
glFrontFace(GL_CCW);
glCullFace(GL_BACK);
// Turn on depth testing
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
// Send draw request
OnDraw(NULL);
}
As you see I have written the code GLenum error13 = glGetError(); right after hrc = wglCreateContext(hdc); to catch any probable error that it throws and yes the value for error13 is 1282 which means INVALID_OPERATION so I think the handle for OpenGL rendering context is not created properly!
besides if you check the values for hdc and hrc, you encounter these:
hdc -> unused = ??? (Error: expression can not be evaluated)
hrc -> unused = 0
Could you help me find out why it is the case? and what's the problem?
The results are quite undefined if you call GL functions (like glGetError() itself) without having a current GL context.
wglCreateContext() is part of the Win33 API (and not the GL API) and will signal errors by returning a NULL pointer. You can call the Windows API function GetLastError() if you want details in that case, like with most other Windows API functions.
Do not call an OpenGL API function before you have a "current context" for the calling thread in Win32. The operations will be undefined.
To correct this issue, simply move the call to wglMakeCurrent (...) one line up so that it comes before the call to glGetError (...).
Note that you have to do this for every thread, and in Win32 only one thread is allowed to access an OpenGL context at any given time. If you ever want to do multi-threaded rendering in Win32, you will have to either acquire/release the context and do synchronization between threads or use a bunch of contexts that "share lists" (wglShareLists (...)).
Like derhass mentioned, if you want information about an error generated by the WGL API, use GetLastError (...). WGL is part of the window system, which is built on top of the Win32 API, so it will communicate its errors to you through the traditional Win32 channels.
By the way, try not to print GL error values in decimal form. They are always enumerated in gl.h as hexadecimal constants, so it would be easier to find the appropriate enumerant if you did this:
printf ("OpenGL Error: 0x%X\n", err);
The same goes for all enumerated constants in OpenGL. If you do not have a function that will map them to a human-readable string, you should use the hexadecimal value to look them up.
hi
There is a function in C++ Visual studio CDC::ExtFloodFill(int x, int y, COLORREF crColor,UINT nFillType);
my question is that what we suppose to write in place of
int x , int y, COLORREF crColor, UINT nFillType
Like if I have a Object Which I want to Color How to do it
enter code here
#include "afxwin.h"
class fr : public CFrameWnd
{
public:
CPoint st;
CPoint en;
fr()
{
Create(0,"First Frame");
}
//////////////////////
void OnLButtonDown(UINT fl,CPoint p )
{
st.x=p.x;
st.y=p.y;
}
//////////////////////
void OnLButtonUp(UINT fl,CPoint r)
{
en.x=r.x;
en.y=r.y;
CClientDC d(this);
d.Ellipse(st.x,st.y,en.x,en.y);
}
void OnRButtonDown(UINT fl,CPoint q)
{
CClientDC e(this);
e.ExtFloodFill(............);
}
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(fr,CFrameWnd)
ON_WM_LBUTTONDOWN()
ON_WM_RBUTTONDOWN()
END_MESSAGE_MAP()
class app : public CWinApp
{
public:
int InitInstance()
{
fr*sal;
sal=new fr;
m_pMainWnd=sal;
sal->ShowWindow(1);
return true;
}
};
app a;
For your example, ExtFloodFill (or any other version of FloodFill) isn't really the right choice.
Instead, you normally want to set the current brush to the color/pattern you want, then draw your object (and it'll automatically be filled with the current brush). Let's say, for example, that you want to draw a red ellipse:
CMyView::OnDraw(CDC *pDC) {
CBrush red_brush;
red_brush.CreateSolidBrush(RGB(255, 0, 0));
pDC->SelectObject(red_brush);
pDC->Ellipse(0, 0, 100, 50);
}
Edit: Okay, if you really insist it has to be a flood-fill, and you're doing it in response to a button click, you'd probably do something like this:
void CYourView::OnRButtonDown(UINT nFlags, CPoint point)
{
CClientDC dc(this);
CBrush blue_brush;
blue_brush.CreateSolidBrush(RGB(0, 0, 255));
dc.SelectObject(blue_brush);
dc.ExtFloodFill(point.x, point.y, RGB(0, 0,0), FLOODFILLBORDER);
CView::OnRButtonDown(nFlags, point);
}
how to set background image in a dialog box in vc++6.0
For MFC you overload OnEraseBackground
class CMyDialog: public CDialog
{
protected:
CMyDialog::CWizardDialog(int nID);
BOOL OnEraseBkgnd(CDC* pDC);
CBitmap m_background;
};
BOOL CMyDialog::OnEraseBkgnd(CDC* pDC)
{
CDialog::OnEraseBkgnd(pDC);
if(!m_background.m_hObject)
return true;
CRect rect;
GetClientRect(&rect);
CDC dc;
dc.CreateCompatibleDC(pDC);
CBitmap* pOldBitmap = dc.SelectObject(&m_background);
BITMAP bmap;
m_background.GetBitmap(&bmap);
// stretch
pDC->StretchBlt(0, 0, rect.Width(),rect.Height(), &dc,0, 0,bmap.bmWidth,bmap.bmHeight, SRCCOPY);
// don't stretch
//pDC->StretchBlt(0, 0, rect.Width(),rect.Height(), &dc,0, 0,rect.Width(),rect.Height(), SRCCOPY);
dc.SelectObject(pOldBitmap);
return true;
}
Use the function SetBackgroundImage() in your OnInitDialog().
Example:
this->SetBackgroundImage(IDB_BITMAP1, BACKGR_TOPLEFT, TRUE);
For more details, see https://msdn.microsoft.com/en-us/library/bb983866.aspx.