Maybe the reason I can't find how to do this is because it isn't allowed. My brain is now confused and I can't solve this on my own. Here it is, simplified:
The problem is, change colours of dialogs in runtime.
#define NEW_COLOR 0x00C4FFFF
// the base class
class MyDialog : public CDialog
{
//...
COLORREF m_clrBkgnd;
virtual void RefreshColor();
}
void MyDialog::RefreshColor()
{
m_clrBkgnd = NEW_COLOR;
Invalidate();
RedrawWindow();
}
// the derived class
class CTest : public MyDialog
{
// no m_clrBkgnd
// no RefreshColor
}
// in main
CTest * m_pTestsDlg;
// here we decide to change the colours of all dialogs...
if (m_pTestsDlg != NULL)
{
m_pTestsDlg->RefreshColor();
}
It runs into RefreshColor nicely and changes the value of m_clrBkgnd, but the dialog does not change colour.
The point is, I have an awful lot of dialogs, and I want to do RefreshColor without changing the dialog code in any way. I have a feeling it must be possible to do this just by changing the base class. In my sample I just change the background colour, obviously there are buttons and stuff, but if I can get this to work I can extrapolate...
On the other hand it might just be plain impossible, and that's why I can't find the answer.
Some dialogs are very complicated and may have to have their own implementation after all.
EDIT
Here is where m_clrBkgnd is used:
HBRUSH MyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
switch (nCtlColor)
{
case CTLCOLOR_STATIC:
{
pDC->SetBkMode(OPAQUE);
pDC->SetTextColor(0,0,0);
pDC->SetBkColor(m_clrBkgnd);// to set the background color
return (HBRUSH) hbr;
break;
}
case CTLCOLOR_BTN:
{
pDC->SetBkMode(TRANSPARENT);
return HBRUSH(m_brushHollow);
break;
}
default:
return (HBRUSH) hbr;
}
}
Related
Tools : Visual Studio 2019, MFC, cpp
I'm looking for how to change the background color for the CFileDialog dialog box. I found this link ==> Q115087: HOWTO: Change the Background Color of a Common Dialog.
I have extracted this code and insert it all into my project then two files mydlg.h and mydlg.cpp. I replace the CFileDialog object with mydlg.
This the code included:
Header file ==> mydlg.h
//
#include <dlgs.h>
#define BACKGROUNG_COLOR RGB(0, 0, 255)
//////////////////////////////////////////////////////////////////////
// CMyDlg dialog
class CMyDlg : public CFileDialog
{
// Construction
public:
CMyDlg(CWnd* pParent = NULL); // standard constructor
// Add a CBrush pointer to store the new background brush
CBrush m_pBkBrush;
// Dialog Data
//{{AFX_DATA(CMyDlg)
enum { IDD = FILEOPENORD };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Implementation
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Generated message map functions
//{{AFX_MSG(CMyDlg)
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
Code file CMyDlg.cpp
CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/): CFileDialog(TRUE, NULL, NULL, OFN_HIDEREADONLY)
{
//{{AFX_DATA_INIT(CMyDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
void CMyDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMyDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CMyDlg, CFileDialog)
//{{AFX_MSG_MAP(CMyDlg)
ON_WM_CTLCOLOR()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////
// CMyDlg message handlers
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
m_pBkBrush.CreateSolidBrush(BACKGROUNG_COLOR);
switch (nCtlColor) { // ==> breakpoint here
case CTLCOLOR_STATIC:
{
// Set the static text to white on blue.
pDC->SetBkColor(BACKGROUNG_COLOR); return (m_pBkBrush);
}
case CTLCOLOR_DLG: return (m_pBkBrush);
default: return CFileDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}
How i call it
CMyDlg FileOpenDialog(TRUE,NULL,local_File,OFN_FILEMUSTEXIST |
OFN_HIDEREADONLY|OFN_PATHMUSTEXIST,
OpenFilter, // filter
AfxGetMainWnd()); // the parent window
CString local_string= Current_Dir();
FileOpenDialog.m_ofn.lpstrInitialDir = local_string;
status = Mess.LoadString(IDS_STRING191);
FileOpenDialog.m_ofn.lpstrTitle = Mess;
if (FileOpenDialog.DoModal() == IDOK)
{
pszSource = FileOpenDialog.m_ofn.lpstrFile;
return true;
}
return false;
Compilation OK
Observation the background color does not change
When i put a stop point on the switch in the function OnCtlColor we do not pass there.
Have you an idea, can you help me?
Thank you
Have you read this article How To Change the Background Color of a Common Dialog Q117778 - does not work where it says:
Changing the background colour of a standard File dialog seems to be possible but requires more steps than in case of a simple dialog.
If it is absolutely crucial to change the colour and no simpler solutions, then consider this summary:
Derive a class from CFileDialog.
In the constructor, get the value of m_ofn.lpfnHook and store to a variable. Write to m_ofn.lpfnHook an address of a new hook procedure. The new hook procedure will call the old one.
In the new hook procedure, intercept the WM_INITDIALOG message and do this: get the parent HWND and get the GWL_WNDPROC value (the old window procedure) of the parent and store it in a variable. Replace this procedure with a new window procedure. The new window procedure will call the old one.
In the new window procedure, intercept the WM_CTLCOLORDLG message and proceed as explained in documentation and above posts.
The linked conversation thread is dated 2009 which is more recent that your linked tutorial.
Guys, can someone give me a brief run through of how to change the background colour of a CEdit control at runtime? I want to be able to change the background to red if the field is zero length and the normal white otherwise.
You cannot do it with a plain CEdit, you need to override a few bits.
Implement your own ON_WM_CTLCOLOR_REFLECT handler, then return your coloured CBrush in the handler:
(roughly, you'll need to put the usual resource management in there, rememebr to delete your brush in the destructor)
class CColorEdit : public CEdit
{
....
CBrush m_brBkgnd;
afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor)
{
m_brBkgnd.DeleteObject();
m_brBkgnd.CreateSolidBrush(nCtlColor);
}
}
This can also be done without deriving from CEdit:
Add ON_WM_CTLCOLOR() to your dialog's BEGIN_MESSAGE_MAP() code block.
Add OnCltColor() to your dialog class:
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
Implement OnCtlColor() like so:
HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
if ((CTLCOLOR_EDIT == nCtlColor) &&
(IDC_MY_EDIT == pWnd->GetDlgCtrlID()))
{
return m_brMyEditBk; //Create this brush in OnInitDialog() and destroy in destructor
}
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}
I have a CStatic picture control on a CDialog that I use to draw content:
CMyDrawingControl.h
CMyDrawingControl : CStatic
{
//Constructor, Destructor, other items
//End Constructor, Destructor, other items
public:
void DrawStuff(CDC *dc);
protected:
afx_msg void OnPaint();
afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
}
CMyDrawingControl.cpp
CMyDrawingControl::CMyDrawingControl
{
}
BEGIN_MESSAGE_MAP(CMyDrawingControl, CStatic)
//{{AFX_MSG_MAP(CMyDrawingControl)
ON_WM_VSCROLL()
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CMyDrawingControl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
//determine delta
ScrollWindow(0, -delta);
Invalidate();
UpdateWindow();
}
void CMyDrawingControl::OnPaint()
{
CPaint dc(this);
DrawStuff(&dc);
}
void CMyDrawingControl::DrawStuff(CDC *dc)
{
dc->SetMapMode(MM_LOMETRIC);
//draw on dc
//text, lines, shapes, etc
}
However the content is usually bigger than the control so I need to be able to scroll the content. CScrollView automatically handles by drawing to the view in OnDraw, but I can't seem to get it to work in OnPaint(). The control either will draw blank or has a lot of repeated content when scrolling.
I'm basically trying to duplicate the exact behavior of CScrollView on a CDialog; I've seen some posts that come close to this, but I don't want to implement a CDocument and a CView.
I think it is much simpler to use a read only edit control.
Beside scrolling this also makes it possible that the user can select and copy parts of the text.
I am experimenting with painting the background of a window in c++ using the MFC library. It is mandated that i use this framework because I am working on an MFC application. I have tried several different methods but cannot get it to work. So i recently opened a blank project and just want to figure out how to paint the background but it is not working. Any help would be great. Here is my code...
class CExerciseApp : public CWinApp
{
//a pointer to our window class object
Basic_Window *bwnd;
BOOL InitInstance()
{
bwnd = new Basic_Window();
m_pMainWnd = bwnd;
bwnd->ShowWindow(1);
HWND hWnd = GetActiveWindow();
CRect drawing_area;
GetClientRect(hWnd, &drawing_area);
CBrush newBrush;
newBrush.CreateSolidBrush(RGB(255,255,255));
CDC* dc = bwnd->GetDC();
dc->FillRect(&drawing_area, &newBrush);
bwnd->RedrawWindow();
return TRUE;
}
};
From my own post https://stackoverflow.com/a/22875542/383779 , I can guarantee I had made that work. I used that approach for implementing themes/skins on a commercial application.
You need to add a OnCtlColor method to your Basic_Window class.
In your .h file, add to the Basic_Window class:
const CBrush m_BackgroundBrush;
and
afx_msg HBRUSH OnCtlColor( CDC* pDC, CWnd* pWnd, UINT nCtlColor);
In .cpp file the constructor will initialize the new variable
Basic_Window::Basic_Window()
: m_BackgroundBrush(RGB(255,255,255))
{
//...
}
and implement
HBRUSH Basic_Window::OnCtlColor( CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
if(some_exception)
return __super::OnCtlColor( pDC, pWnd, nCtlColor);
return (HBRUSH) m_BackgroundBrush.GetSafeHandle();
}
some_exception here means a situation where you will want the default behavior, instead of your own painting. Maybe it is a certain type of control, and for that exists the nCtlColor parameter.
Do not forget to add ON_WM_CTLCOLOR() to your message map.
I have asked two questions earlier about this and for each post there was some solutions i tried them, but the problem still exist.
My first question was : why a windowless Activex does not return the Handle. the suggestion was "change the creation setting an make windowless activate off, i have tried it but still m_hWnd property has returned zero as GetSafeHwnd() method has did.
the second one was the same question this one focused on COleControl class and it's ancestor CWnd. the solution was as this "Create invisible window somewhere in your control initialization code. Handle the messages sent to this window, and call controls methods directly". so i did that but the created class still returns zero handle.
here is my new invisible class source:
// moWind.cpp : implementation file
//
#include "stdafx.h"
#include "PINActive.h"
#include "moWind.h"
#include "include\xfspin.h"
#include <math.h>
// moWind
IMPLEMENT_DYNAMIC(moWind, CWnd)
moWind::moWind(){}
moWind::~moWind(){}
//=============================================================
LRESULT moWind::OnExecuteEvent (WPARAM wParam, LPARAM lParam)
{
WFSRESULT *pResult = (WFSRESULT *)lParam;
CString EK=_T("");
CString str;
int reskey=0;
if (pResult->u.dwEventID=WFS_EXEE_PIN_KEY)
{
LPWFSPINKEY pressedkey;
pressedkey=(LPWFSPINKEY)pResult->lpBuffer;
reskey = log10((double)pressedkey->ulDigit) / log10((double)2);
EK.Format("%d",reskey);
xfsOnKeyEvent->OnKeyRecieved(reskey);
}
else
{
str.Format("ExecuteEvent: ID = %d\r\n", pResult->u.dwEventID);
}
MessageBox("a Execute message Recieved");
return 0;
}
BEGIN_MESSAGE_MAP(moWind, CWnd)
ON_MESSAGE(WFS_EXECUTE_EVENT,OnExecuteEvent)
END_MESSAGE_MAP()
and this is .h file of the class:
// moWind.h
class IXFSEvents
{
protected:
IXFSEvents(){};
virtual ~IXFSEvents(){};
public:
virtual void OnKeyRecieved(int key)=0;
};
class moWind : public CWnd
{
DECLARE_DYNAMIC(moWind)
public:
moWind();
virtual ~moWind();
void Register(IXFSEvents* obj)
{
xfsOnKeyEvent= obj;
}
protected:
IXFSEvents* xfsOnKeyEvent;
LRESULT OnExecuteEvent (WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
};
and at the end here this the way I've used this class in my Activex:
in the myActivex.h file:
include "moWind.h"
class CmyActivexCtrl : public COleControl, public IXFSEvents
{
...
Class definition
...
protected:
moWind tmpWind;
.
.
};
finally in the creation method of myActivex i have initialized the component callback method an wanted to get it's Handle as this:
CmyActivexCtrl::CmyActivexCtrl()
{
InitializeIIDs(&IID_DmyActivex, &IID_DmyActivexEvents);
tmpWind.Register(this);
myOtherComponent.WindowsHandle=tmpWind.GetSafeHwnd(); //here my Cwnd derived class returns zero
//my other component gets the handle and call an API with it to register
//the given handle and force the API to send the messages to that handle.
}
As you mentioned you need a window handle to be able to receive user messages through it, you always have an option of creating a helper window, such as message only window, see Using CreateWindowEx to Make a Message-Only Window.
For your windowless control it is okay to not have any window handle at all, so you cannot really rely on handle availability unless you own a window yourself.