I am developing MFC based SDI application using CFormView class in VC++. My problem is that I need to load image when the dialog initially appears. How to place image in an SDI application..I know for dialog based applications it can be done using OnInitDialog application.But for SDI application there is no such function. I tried placing the image using OnInitialUpdate() and OnPaint() function. But it failed..What should I do to place the image to dialog when it first appears? Please Help
Thanks in advance
Code as I placed in OnInitialUpdate()
void CECUSimulatorView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
GetParentFrame()->RecalcLayout();
ResizeParentToFit();
hBitmap = LoadImage(0,_T("F:/ECUSimulator/ECUSimulator_New/res/LedOff.bmp"), IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
ImageLoading();
}
Code for the function ImageLoading()
void CECUSimulatorView::OnInitialUpdate()
{
HDC hDC, hDCToDisplay = NULL;
hDC = CreateCompatibleDC(hDCToDisplay);
SelectObject(hDC,hBitmap);
hDCToDisplay = ::GetDC(m_picture.m_hWnd);
m_picture.GetWindowRect(&picRect);
BitBlt(hDCToDisplay,0 , 0, (picRect.right - picRect.left), (picRect.bottom -picRect.top), hDC, 0 ,0 ,SRCCOPY);
DeleteDC(hDC);
DeleteDC(hDCToDisplay);
}
Here
HANDLE hBitmap;
CStatic m_picture; //Picture Control
CRect picRect; //Picture Control Rect
I removed the code from OnInitialUpdate() and placed it in OnPaint() function as follows:
void CECUSimulatorView::OnPaint()
{
CPaintDC dc(this); // device context for painting
hBitmap = LoadImage(0,_T("F:/ECUSimulator/ECUSimulator_New/res/LedOff.bmp"), IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
ImageLoading();
}
Calling LoadImage() in OnInitialUpdate() is ok, the actual painting needs to be done in one of the two following ways:
a) in CECUSimulatorView::OnDraw() -- easier, but may introduce flickering
b) override the OnPaint() function of the m_picture control using ClassWizard and draw the picture there
[the comments in the previous answer was getting very extended, hence a new answer]
a) derive a new class (say CMyPicture) based on CStatic, change m_picture to this new class
b) in CMyPicture, create a handler for WM_PAINT, this will normally be called CMyPicture::OnPaint()
c) change your ImageLoading() function to take a CDC *pDC as parameter and use this DC to render the image
d)
void CMyStatic::OnPaint(void)
{ CPaintDC dc(this);
ImageLoading(&dc); // or even move the painting logic here
}
NOTE: you can load the image in OnInitialUpdate(), no need to load it each time you are painting
An example (for a dialog, but the painting logic should not be affected) in this SO Answer.
I found the answer for my problem.
I used CBitmap class as follows:
CBitmap m_bBitmap1;
In OnInitialUpdate() I wrote as follows :
m_bBitmap1.LoadBitmapW(IDB_BITMAP1);
In OnPaint() I wrote as follows:
m_picture.SetBitmap(m_bBitmap1);
Wherever(In which all functions)need to load image just call the above line of code in corresponding functions..
Related
I have found a GDI leak in our huge application software.
Below is a simple program to test this problem.
The Idea is that the main dialog box opens another dialog box(dialog box A).
If the dialog box A include a bitmap function for a CStatic control,
it will create GDI leak.
Even when I use "DeleteObject(bitmap)".
Have I done some thing wrong ?
Do you have any thoughts?
Thanks.
// Resource File
...
DIALOG_BOXA DIALOGEX 0, 0, 219, 142
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_BORDER
EXSTYLE WS_EX_STATICEDGE
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,46,121,50,14
PUSHBUTTON "Cancel",IDCANCEL,119,121,50,14
CONTROL 131,RED_LIGHT0,"Static",SS_BITMAP,7,17,80,37
PUSHBUTTON "",RED_LIGHT1,7,60,80,37,BS_BITMAP | NOT WS_TABSTOP
END
// head file
DialogBoxA: public CDialog
{
...
CStatic m_static;
CButton m_button ;
...
}
/////////////////////////////////////////////////////////
void DialogBoxA::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, RED_LIGHT0, m_static);
DDX_Control(pDX, RED_LIGHT1, m_button);
}
BOOL DialogBoxA::OnInitDialog()
{
CDialog::OnInitDialog();
HBITMAP bitmap ;
// This will create GDI leak !!!
bitmap = LoadBitmap ( AfxGetApp()->m_hInstance,BEACON_BIG_RED_ON) ;
m_static.SetBitmap (bitmap );
DeleteObject(bitmap);
// This is OK !!!
bitmap = LoadBitmap ( AfxGetApp()->m_hInstance,BEACON_BIG_RED_ON) ;
m_button.SetBitmap (bitmap );
DeleteObject(bitmap);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
Here is the exlanantion and solution for the GDI leak in static control:
http://blogs.msdn.com/b/oldnewthing/archive/2014/02/19/10501282.aspx
It's complicated. First, let's take a closer look at your code
bitmap = LoadBitmap ( AfxGetApp()->m_hInstance,BEACON_BIG_RED_ON) ;
m_static.SetBitmap (bitmap );
DeleteObject(bitmap);
You should not delete the bitmap that you just told the static control to use. It's still using it! It's going to continue using it until you set the bitmap to something else.
So instead of trying to delete the bitmap during dialog initialization, you should wait until the dialog is being destroyed. At that point, you have to get tell the static control to stop using the bitmap, and only then can you delete the bitmap object.
Second, static controls sometimes make a copy of your bitmap. Whether it makes a copy depends on a bunch of things, including whether the bitmap has a non-zero alpha channel. It becomes your problem to destroy this copy as well. (This may be why your one of your cases works and the other doesn't.)
You basically have to keep track of the bitmap you think you set until it's time to clean up. Then you have to compare what's actually in the static control to the one you thought you gave it. If they're different, then you destroy both (your bitmap and the static controls copy). If they're the same, then the static control didn't make a copy, and you have to destroy just the one you made (once!).
I'm making a plug-in for a program and when faced with the options on how to create a window inside the program with the same style as the program window i opted for using the MFC classes:CDC, CRect, CPen,etc and then using DrawFrameControl i was able to design a simplified version of what i want.
The question now is: i created a close,minimize,etc buttons. But how will i add events to what i have drawn?
I searched online and haven't found a solution, that why i'm asking you guys
Thank you
Here is the code for what i've drawn so far:
CDC dc;
dc.Attach(hdc);
CButton but;
CBrush green(COLOR_GREEN);
CBrush white(COLOR_WHITE);
CRect rect=GetRadarArea();
CRect rect2=GetChatArea();
CPoint ptdown,ptup;
rect.bottom=rect2.top;
rect.TopLeft().x=rect.BottomRight().x-180;
//AddScreenObject (1,"Cenas",rect,true,"nice") ;
//but.Create("Undo",BS_PUSHBUTTON,rect,hdc,MYBUTTONID);
dc.FillRect(&rect,&green);
CRect rect3; //Closebutton
rect3.TopLeft().x=rect.BottomRight().x-10;
rect3.TopLeft().y=rect.TopLeft().y;
rect3.BottomRight().x=rect.BottomRight().x;
rect3.BottomRight().y=rect.TopLeft().y+10;
dc.DrawFrameControl(&rect3,DFC_CAPTION,DFCS_CAPTIONCLOSE);
CRect rect4; //Minimize button
rect4.top=rect3.top;
rect4.bottom=rect3.bottom;
rect4.TopLeft().x=rect3.TopLeft().x-10;
rect4.BottomRight().x=rect3.BottomRight().x-10;
dc.DrawFrameControl(&rect4,DFC_CAPTION,DFCS_CAPTIONMIN);
CRect rect5;
rect5.top=rect3.top;
rect5.bottom=rect3.bottom;
rect5.TopLeft().x=rect.TopLeft().x;
rect5.BottomRight().x=rect3.BottomRight().x;
dc.SetTextColor(COLOR_WHITE);
dc.DrawText("FL Changes List",rect5,DT_CENTER);
CPen pen1 ( 0, 0.2, COLOR_WHITE) ;
dc.SelectObject(&pen1);
dc.MoveTo(rect.TopLeft().x,rect5.BottomRight().y);
dc.LineTo(rect.BottomRight().x,rect5.BottomRight().y);
Add message handlers for WM_LBUTTONDOWN and WM_LBUTTONUP. When you get a click compare the click location to the pseudo-button location(s) to determine if a button was hit.
I'm a little new to using MFC and VC++ as such, but I'm doing this as part of a Course and i Have to stick to VC++.
http://www.cprogramming.com/tutorial/game_programming/same_game_part1.html
This is the tutorial I have been following to make a simple samegame. However when i try to display score, the score is getting displayed Underneath or outside my application window, even though I've displayed score before calling updateWindow(). I've tried various methods but I am kinda lost here.
Here is the code I'm using to Display the score:
void CSameGameView::updateScore()
{
CSameGameDoc* pDoc = GetDocument();
CRect rcClient, rcWindow;
GetClientRect(&rcClient);
GetParentFrame()->GetWindowRect(&rcWindow);
int nHeightDiff = rcWindow.Height() - rcClient.Height();
rcScore.top=rcWindow.top + pDoc->GetHeight() * pDoc->GetRows() + nHeightDiff;
rcScore.left=rcWindow.left + 50;
rcScore.right=rcWindow.left + pDoc->GetWidth() - 50;
rcScore.bottom=rcScore.top + 20;
CString str;
double points = Score::getScore();
str.Format(_T("Score: %0.2f"), points);
HDC hDC=CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL);
COLORREF clr = pDoc->GetBoardSpace(-1, -1); //this return background colour
pDC->FillSolidRect(&rcScore, clr);
DrawText(hDC, (LPCTSTR) str, -1, (LPRECT) &rcScore, DT_CENTER);
}
Thank you for any help and I'm sorry if the question doesn't make sense or in ambiguous.
There are several problems with your code:
1. The hDC you are creating is going to have coordinates relative to the desktop window. To paint text in your window, use CClientDC like this: CClientDC dc(this); (see http://msdn.microsoft.com/en-US/library/s8kx4w44%28v=vs.80%29.aspx)
2. The code you have will leak a DC every time the function is called. The method in #1 will fix that.
3. Your paint code should be done in the CView::OnDraw. There you get a DC passed to you and you don't have to worry about creating one with CClientDC. Set the variables you want to draw (e.g. your points or score), store them as class members and draw them in CView::OnDraw.
Don't do the drawing in your updateScore method.
Make sense? Hang in there!
I am trying to make a paint application in MFC using visul basic c++ 6.0 i have already created a window using Create function and also have created a toolbar with a tool line but i am stuck on how to code for the line because the function i know goes like d.lineTo(x,y) and d.Moveto(x2,y2) but it comes under the line function how do i use OnLButtonDown to Trap the co-ordiantes or is there any other way i can draw a line ..? any help will be useful
have a look at the MFC Scribble tutorial :
http://msdn.microsoft.com/en-us/library/aa716527%28v=vs.60%29.aspx)
It will get you started on how to handling mouse click and mouse move and drawing.
M.
Ok, you're going to have to override several member functions to do this. I've outlined an approach below. My example below deals with a single line-drawing operation (from mouse down, to mouse up). An exercise for you, is to make it so that once you've done one, you can then do another at a different place. It's easy, btw!
CWnd::OnLButtonDown(UINT _flags, CPoint _pt);
CWnd::OnLButtonUp(UINT _flags, CPoint _pt);
CWnd::OnMouseMove(UINT _flags, CPoint _pt);
CWnd::OnPaint()
Apologies if some of these function signatures are wrong! Add some members to your window class:
// at the top of your file
#include <vector>
// in your class
typedef std::vector<POINT> PointVector;
PointVector m_Points;
CYourWnd::OnLButtonDown(UINT _flags, CPoint _pt);
{
// NOTE: For more than one set of drawing, this will be different!
m_Points.clear();
m_Points.push_back(POINT(_pt.x, _pt.y));
}
CYourWnd::OnMouseMove(UINT _flags, CPoint _pt);
{
if(_flags & MK_LBUTTON)
{
const POINT& last(m_Points.back());
if(_pt.x != last.x || _pt.y != last.y)
{
m_Points.push_back(POINT(_pt.x, _pt.y));
Invalidate();
}
}
}
CYourWnd::OnPaint()
{
CPaintDC dc(this);
CRect rcClient; GetClientRect(&rc);
FillSolidRect(&rcClient, RGB(255, 255, 255));
if(m_Points.size())
{
dc.MoveTo(m_Points[0].x, m_Points[0].y);
for(PointsVector::size_type p(1);
p < m_Points.size();
++p)
dc.LineTo(m_Points[p].x, m_Points[p].y);
}
}
Obviously, this is crude and gives you a single drawing operation. Once you click the left button down again, it erases what you've done. So, once you have this working:
Make it so you can draw an unlimited amount of lines. You could accomplish this in several ways such as an additional container (to store vectors), or even drawing-operation classes that you can store in a single vector and then execute.
This solution may well flicker. How might you stop this? Perhaps OnEraseBkgnd holds the clue...
How about more colours?
All signs point towards creating some drawing-classes that encapsulate this for you, but I hope this has got you started.
Myself shweta dodiya.I am facing problem with nokia N97 related to change orientation for my game application.
I am using J2me technology.I want to pause my application when i open my slider.
Thanks in advance
I don't know what code are you using, or are you using Canvas to draw the game on screen, or some other API that does that for you...
If you have something like this GameScreen extends Canvas and you use GameScreen object to draw and display the game, you need to add an override to sizeChanged method to it and check the new width (w) and the new height (h) of the GameScreen, and do the things you want in regards to that:
public void sizeChanged(int w, int h)
{
if(h > w) //NORMAL
{
drawGame();
if(paused) resumeGame();
}
else //LANDSCAPE
{
pauseGame();
drawPauseScreen();
}
}
This is a simple pseudo code, I hope you are getting the point. If statement is checking the relation between new width and the new height. If the phone is in landscape mode, H is less then W...