I've a DGRect::draw(HWND hwnd) which simply draws a Blank HBITMAP on hwnd window Handle.
I works fine If I call it from main() . It even works correctly If called from DGRDPServer::DGRDPServer() constructor which is QTcpServer Derived. It also works well from DGRDPServer::listen(qint64 port). The hwnd is passed in DGRDPServer constructor. The Problem appears when I call it from DGRDPServer::incomingConnection(int socketDescriptor) I've qDebug()ed value of hwnd and its Okay. Whats Causing the draw for failing. ??
Here goes my code for DGRect::draw(HWND hwnd)
QByteArray ba;
HDC hdc = GetWindowDC(hwnd);
HBITMAP scrn = CreateCompatibleBitmap(hdc,/*width*/200,/*height*/200);
SetBitmapBits(scrn, /*size()*/200*200*4, ba.data());
BITMAP bm;
PAINTSTRUCT ps;
HDC whdc = BeginPaint(hwnd, &ps);
HDC hdcMem = CreateCompatibleDC(whdc);
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, scrn);
GetObject(scrn, sizeof(bm), &bm);
BitBlt(whdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, hbmOld);
DeleteDC(hdcMem);
EndPaint(hwnd, &ps);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
Update
Seems like hwnd can be painted from main thread only. However UpdateWindow Call works from a different thread. and looks like functions like DGRDPServer::incomingConnection(int socketDescriptor) are called from a different thread. So What can be done to paint hwnd from a different thread ?
My guess is that the problem here is your use of BeginPaint: as per docs: An application should not call BeginPaint except in response to a WM_PAINT message
Outside of that, you may be able to use plain GetDC/ReleaseDC instead of BeginPaint/EndPaint pair.
The 'windows way' of doing this sort of thing, however, is to just use the worker thread to update the internal data appropriately, and then use InvalidateRect or similar to tell Windows that the window needs to be updated, and Windows will send a WM_PAINT later. UpdateWindow is essentially a more immediate version of this: it sends WM_PAINT to the window right there and then (which causes the actual painting to take place on that hwnd's thread).
Related
I'm creating a message window to receive timer messages in a separate queue from the main Excel Application window. I can then subclass that window without a torrent of irrelevant stuff going through my (slow) VBA message loop.
As I understand it, I can use the hWndParent parameter along with the WM_CHILD style to make a window that is a child of the main window handle. According to the DestroyWindow docs:
If the specified window is a parent or owner window, DestroyWindow
automatically destroys the associated child or owned windows when it
destroys the parent or owner window.
So I imagine that supplying Application.hWnd as the parent would mean that when I close Excel, all the associated windows are removed too.
But Message-Only Windows need HWND_MESSAGE as the parent, so I'm not sure when/if they'll be cleared up?
FWIW, here's the code I'm using to generate/find the window (my program may lose its state so I can't rely on storing the handle in a variable)
Public Function getMessageWindow(ByVal windowName As String) As hWnd
Const className As String = "Static"
Dim result As hWnd
result = ApiFindWindow(className, windowName)
If result.value.address = 0 Then 'not found
Const HWND_MESSAGE As Long = (-3&)
result = APiCreateWindowEx(0, className, windowName, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, 0)
End If
getMessageWindow = result
End Function
The documentation for Fl_Tree in FLTK 1.3.4 says:
The callback() is invoked depending on the value of when()
FL_WHEN_RELEASE -- callback invoked when left mouse button is released on an item
FL_WHEN_CHANGED -- callback invoked when left mouse changes selection state
but I can't get the callback called if the mouse is released and I can't see a difference between both. Any ideas?
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Tree.H>
static void cb_(Fl_Tree*, void*)
{
printf ("callback\n");
}
int main()
{
Fl_Double_Window* w = new Fl_Double_Window(325, 325);
Fl_Tree* o = new Fl_Tree(25, 25, 255, 245);
o->callback((Fl_Callback*)cb_);
o->when(FL_WHEN_RELEASE);
o->add("foo/bar");
o->add("foo/baz");
o->end();
w->show();
return Fl::run();
}
this snippets outputs "callback" on every change, even if FL_WHEN_RELEASE is set.
If you have downloaded, the distribution, have a look at test/input.cxx and test/tree.cxx. Both have tests for the different when selections.
WHEN_CHANGED only makes sense on edit boxes, browsers and tables - you can verify the data as it is typed in. This does not happen with WHEN_RELEASE. For all other widgets, there is virtually no difference.
Edit
In order for release to fire every time, there are one of three options
Modify the source FL_Tree.cxx. Look for FL_Tree::select. Change alreadySelected to false.
If you look at the source, in the same routine, further down, it says
#if FLTK_ABI_VERSION >= 10301
If the library is built with FLTK_ABI_VERSION set to 10301, it will call the reselect but there is also a whole load of other stuff it will do when this #define is set since it affects all widgets
Comment out the #if FLTK_ABI_VERISON and corresponding #endif in FL_Tree::select.
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 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..
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!