I have a Panel control and I need to draw a few lines and circles on it. Why does the panel stays untouched?
Graphics ^ graphics = panel->CreateGraphics();
Pen^ penCurrent = gcnew Pen(Color::Red);
Point p1(10,10);
Point p2(20,20);
graphics->DrawLine(penCurrent,p1,p2);
//panel->Invalidate(); //tried this to refresh too
Graphics ^ graphics = panel->CreateGraphics();
Pen^ penCurrent = gcnew Pen(Color::Red);
Point p1(10,10);
Point p2(20,20);
graphics->DrawLine(penCurrent,p1,p2);
delete graphics;
Next full example is work and draw line
#include "windows.h"
#using <mscorlib.dll>
#using <System.dll>
#using <System.Windows.Forms.dll>
#using <System.Drawing.dll>
using namespace System::Windows::Forms;
using namespace System;
using namespace System::Drawing;
ref class MyForm : public Form
{
public:
MyForm()
{
Text = "Hello, Windows Forms!";
auto button = gcnew Button();
button->Text = "Click Me!";
button->Click += gcnew EventHandler(this, &MyForm::button_click);
this->Controls->Add(button);
}
void button_click(Object^ sender, EventArgs^ e)
{
auto g = this->CreateGraphics();
g->DrawLine(Pens::Black, Point(10, 10), Point(50, 50));
delete g;
}
};
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
Application::Run(gcnew MyForm);
}
Related
I am attempting to create a "dark mode" for my Windows C++ app partially for fun, partially to try and fully comprehend the message passing in MFC, but I'm running into some really odd issues that I can't find explained anywhere.
I've spent the better part of today attempting to figure this out and will try my best to cite the many sources I've looked at and attempted to implement.
I believe I've successfully written message handlers for both WM_CTLCOLOR and WM_ERASEBKGND based on example code from this answer, but they don't seem to have any effect on my dialogs. I've cut the code down here, but am hoping that I've provided enough to expose my issue. If that still isn't enough, I can (reluctantly) share the entire repo.
SoftwareDlg.h
#ifndef _SOFTWAREDLG_H_INCLUDED_
#define _SOFTWAREDLG_H_INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class SoftwareDlg : public CDialog
{
// Construction
public:
SoftwareDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(SoftwareDlg)
enum { IDD = IDD_SOFTWARE_DIALOG };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(SoftwareDlg)
public:
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
BOOL PreTranslateMessage(MSG* pMsg);
CFont m_font;
CRichEditCtrl m_richEditCtrl;
// Generated message map functions
//{{AFX_MSG(SoftwareDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnDestroy();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
/////////////////////////////////////////////////////////////////////////////
#endif
/////////////////////////////////////////////////////////////////////////////
SoftwareDlg.cpp
#include "stdafx.h"
#include <Windows.h>
#include "AboutDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//Windows Dialog inherited function overrides
/////////////////////////////////////////////////////////////////////////////
// SoftwareDlg dialog
/////////////////////////////////////////////////////////////////////////////
SoftwareDlg::SoftwareDlg(CWnd* pParent /*=NULL*/)
: CDialog(SoftwareDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(SoftwareDlg)
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void SoftwareDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(SoftwareDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(SoftwareDlg, CDialog)
//{{AFX_MSG_MAP(SoftwareDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_TIMER()
ON_WM_DESTROY()
//}}AFX_MSG_MAP
ON_WM_ERASEBKGND()
ON_WM_CTLCOLOR()
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// SoftwareDlg message handlers
/////////////////////////////////////////////////////////////////////////////
BOOL SoftwareDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
CWnd* pPlaceholder = GetDlgItem(IDC_PLACEHOLDER);
if (pPlaceholder)
{
CRect rect;
pPlaceholder->GetClientRect(&rect);
if (!m_richEditCtrl.Create(WS_VISIBLE | ES_READONLY | ES_MULTILINE | ES_AUTOHSCROLL | WS_HSCROLL | ES_AUTOVSCROLL | WS_VSCROLL, rect, this, 0))
return FALSE;
m_font.CreateFont(-11, 0, 0, 0, FW_REGULAR, 0, 0, 0, BALTIC_CHARSET, 0, 0, 0, 0, "Courier New");
m_richEditCtrl.SetFont(&m_font);
}
m_nTimerID = SetTimer(0x1234, 1000, NULL); //Used by OnTimer function to refresh dialog box & OSD
return TRUE; // return TRUE unless you set the focus to a control
}
void SoftwareDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
/////////////////////////////////////////////////////////////////////////////
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
/////////////////////////////////////////////////////////////////////////////
void SoftwareDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
HCURSOR SoftwareDlg::OnQueryDragIcon()
{
return (HCURSOR)m_hIcon;
}
void SoftwareDlg::OnTimer(UINT nIDEvent)
{
CDialog::OnTimer(nIDEvent);
}
void SoftwareDlg::OnDestroy()
{
if (m_nTimerID)
KillTimer(m_nTimerID);
m_nTimerID = NULL;
MSG msg;
while (PeekMessage(&msg, m_hWnd, WM_TIMER, WM_TIMER, PM_REMOVE));
CDialog::OnDestroy();
}
BOOL SoftwareDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN)
{
switch (pMsg->wParam)
{
case ' ':
Sleep(1000);
}
}
return CDialog::PreTranslateMessage(pMsg);
}
BOOL SoftwareDlg::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
GetClientRect(&rect);
CBrush myBrush(RGB(255, 0, 0)); // dialog background color
CBrush* pOld = pDC->SelectObject(&myBrush);
BOOL bRes = pDC->PatBlt(0, 0, rect.Width(), rect.Height(), PATCOPY);
pDC->SelectObject(pOld); // restore old brush
return bRes; // CDialog::OnEraseBkgnd(pDC);
}
HBRUSH SoftwareDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
// Are we painting the IDC_MYSTATIC control? We can use
m_brush.CreateSolidBrush(RGB(136, 217, 242));
//if (pWnd->GetDlgCtrlID() == IDD_SOFTWARE_DIALOG)
// Set the text color to red
pDC->SetTextColor(RGB(255, 0, 0));
// Set the background mode for text to transparent so background will show thru.
pDC->SetBkMode(TRANSPARENT);
// Return handle to our CBrush object
hbr = m_brush;
return hbr;
}
HBRUSH SoftwareDlg::CtlColor(CDC* pDC, UINT nCtlColor)
{
HBRUSH myBrush = CreateSolidBrush(RGB(136, 217, 242));
return myBrush;
}
Resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Software.rc
//
#define IDM_ABOUTBOX 0x0010
#define IDD_ABOUTBOX 100
#define IDS_ABOUTBOX 101
#define IDD_SOFTWARE_DIALOG 102
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 141
#define _APS_NEXT_COMMAND_VALUE 32792
#define _APS_NEXT_CONTROL_VALUE 1026
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
Another question, posted by the same user ~6 months earlier, was answered with somewhat similar code, but using the type of framework that contains a "WinMain" function(sorry, I can't differentiate the 2+ types yet). My program does not contain a WinMain function so I wasn't able to use the sample code directly... but another difference in this answer was that David was told to catch a WM_CTLCOLORDLG message type instead the WM_CTLCOLOR message type. I tried to catch this new message type, but IntelliSense told me it was undefined and that particular message property was completely absent from the resource view of the dialog box:
I've also attempted defining "WM_CTLCOLORDLG" myself as described on the Microsoft Docs page, but continued to get error messages when I tried handling it through "ON_MESSAGE".
My code was not an original project, but was taken from an open source sample provided with RTSS. As such, it doesn't use the standard(?) "pch.h", but "stdafx.h"(which is older I guess?). I'm not certain if that's relevant, but I feel like it may be.
I think this issue may also be causing me a lot of other growing pains as well, so any help is GREATLY appreciated.
Main problem with OP's code is that the brush is re-created every time in OnCtlColor and will keep leaking GDI handles (the debug build of MFC raises an ASSERT about this). Complete step-by-step fix below.
Declare the color and brush as members of the dialog.
class SoftwareDlg : public CDialog
{
//...
protected:
COLORREF m_color;
CBrush m_brush;
//...
Initialize the color and brush in OnInitDialog.
BOOL SoftwareDlg::OnInitDialog()
{
m_color = RGB(136, 217, 242);
m_brush.CreateSolidBrush(m_color);
CDialog::OnInitDialog();
//...
Return the brush from OnCtlColor.
HBRUSH SoftwareDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
//...
return m_brush;
}
Use the color in OnEraseBkgnd to repaint any visible area.
afx_msg BOOL SoftwareDlg::OnEraseBkgnd(CDC* pDC)
{
CRect rc;
pDC->GetClipBox(&rc);
pDC->FillSolidRect(rc, m_color);
return TRUE;
}
Set the background color to the rich edit control in OnInitDialog explicitly, since rich edit controls do not use the WM_CTLCOLOR*** messages.
BOOL SoftwareDlg::OnInitDialog()
{
//...
if (pPlaceholder)
{
//...
if (!m_richEditCtrl.Create(WS_VISIBLE | ES_READONLY | ES_MULTILINE | ES_AUTOHSCROLL | WS_HSCROLL | ES_AUTOVSCROLL | WS_VSCROLL, rect, this, 0))
return FALSE;
m_richEditCtrl.SetBackgroundColor(FALSE, m_color);
//...
Note: if using the CDialogEx::SetBackgroundColor approach proposed in the other answer, the OnCtlColor and OnEraseBkgnd parts are covered by the CDialogEx implementation. The last step is still necessary because the WM_CTLCOLOR mechanism only covers the basic controls (static, edit, button etc) and the dialog itself. Controls other than those (rich edit control, list-view control etc) need to be handled each separately.
Simply use the CDialogEx class it supports CDialogEx::SetBackgroundColor and it does all the stuff for static and button controls.
I've tried using a few methods but can't seem to pass along the label to the new thread or have the secondary thread be able to access the label and refresh the form on the form thread. I'm trying to have it multi-threaded so the interface doesn't lock up when running commands to remote devices. Any help in having a way to update the label and refresh the form from a secondary thread would be appreciated! Here is my MyForm.h file and MyForm.cpp file:
#include <iostream>
#include <conio.h>
#include <windows.h>
namespace StudioControl2 {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Threading;
using namespace System::Threading::Tasks;
using namespace std;
bool GUIEvent = false;
/// <summary>
/// Summary for MyForm
/// </summary>
public ref class MyForm : public System::Windows::Forms::Form
{
public:
MyForm (void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~MyForm()
{
if (components)
{
delete components;
}
}
private: System::Windows::Forms::Button^ WindowTVVmixSelect;
private: System::Windows::Forms::Label^ StatusOutput;
private: System::ComponentModel::IContainer^ components;
protected:
private:
/// <summary>
/// Required designer variable.
/// </summary>
#pragma region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
System::ComponentModel::ComponentResourceManager^ resources = (gcnew System::ComponentModel::ComponentResourceManager(MyForm::typeid));
this->WindowTVVmixSelect = (gcnew System::Windows::Forms::Button());
this->StatusOutput = (gcnew System::Windows::Forms::Label());
(cli::safe_cast<System::ComponentModel::ISupportInitialize^>(this->pictureBox1))->BeginInit();
this->SuspendLayout();
//
// WindowTVVmixSelect
//
this->WindowTVVmixSelect->Anchor = System::Windows::Forms::AnchorStyles::None;
this->WindowTVVmixSelect->Location = System::Drawing::Point(31, 400);
this->WindowTVVmixSelect->Margin = System::Windows::Forms::Padding(5);
this->WindowTVVmixSelect->Name = L"WindowTVVmixSelect";
this->WindowTVVmixSelect->Size = System::Drawing::Size(120, 30);
this->WindowTVVmixSelect->TabIndex = 10;
this->WindowTVVmixSelect->Text = L"Vmix";
this->WindowTVVmixSelect->UseVisualStyleBackColor = true;
this->WindowTVVmixSelect->Click += gcnew System::EventHandler(this, &MyForm::WindowTVVmixSelect_Click);
//
// StatusOutput
//
this->StatusOutput->Anchor = System::Windows::Forms::AnchorStyles::None;
this->StatusOutput->BorderStyle = System::Windows::Forms::BorderStyle::Fixed3D;
this->StatusOutput->ForeColor = System::Drawing::Color::Red;
this->StatusOutput->Location = System::Drawing::Point(232, 612);
this->StatusOutput->Margin = System::Windows::Forms::Padding(5);
this->StatusOutput->Name = L"StatusOutput";
this->StatusOutput->Size = System::Drawing::Size(120, 30);
this->StatusOutput->TabIndex = 20;
this->StatusOutput->TextAlign = System::Drawing::ContentAlignment::MiddleCenter;
//
// MyForm
//
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(584, 661);
this->Controls->Add(this->WindowTVVmixSelect);
this->MinimumSize = System::Drawing::Size(600, 700);
this->Name = L"MyForm";
this->Text = L"Studio Control";
(cli::safe_cast<System::ComponentModel::ISupportInitialize^>(this->pictureBox1))->EndInit();
this->ResumeLayout(false);
this->PerformLayout();
}
#pragma endregion
private: System::Void WindowTVVmixSelect_Click(System::Object^ sender, System::EventArgs^ e) {
if (GUIEvent == false) {
GUIEvent = true;
Console::WriteLine("Window TV Vmix Select");
WindowHDMIStatus -> Text = "Vmix";
StatusOutput->Text = "Please Wait";
MyForm::Refresh();
//Creation of new thread.
ThreadWindowTVVmixSelect^ o1 = gcnew ThreadWindowTVVmixSelect();
Thread^ t1 = gcnew Thread(gcnew ThreadStart(o1, &ThreadWindowTVVmixSelect::ThreadEntryPoint));
t1->Name = "t1";
t1->Start();
}
}
ref class ThreadWindowTVVmixSelect
{
public:
void ThreadEntryPoint()
{
Sleep(2000);
Console::WriteLine("Terminating Thread Window TV Vmix Select");
//Trying to update and refresh label in MyForm.
GUIEvent = false;
}
};
};
}
#include "MyForm.h"
using namespace System;
using namespace System::Windows::Forms;
[STAThreadAttribute]
int main(array<String^>^ args) {
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
StudioControl2::MyForm form;
Application::Run(%form);
return 0;
}
As shown here MS Docs Forms Invoker
You need to create so called invoker that invokes the commands you give him in the thread that created him, so it's delegate.
Edit:
I didn't realize it's cpp, syntax is a bit different but the main idea is the same
Define and ise delegates MS Doc
I figured out how to make a Thread-Safe call from the same site I mentioned (https://learn.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-make-thread-safe-calls-to-windows-forms-controls). There's a small symbol at the top right of the page (</>) that changes the code examples to one of three options, C#, VB, or C++.
Here's the code I used for setting up a new thread, and running a thread safe invoke on the form label on the UI thread from the new thread:
private:
Thread^ Thread1;
private: System::Void WindowTVVmixSelect_Click(System::Object^ sender, System::EventArgs^ e) {
if (GUIEvent == false) {
GUIEvent = true;
Console::WriteLine("Window TV Vmix Select");
StatusOutput->Text = "Please Wait";
MyForm::Refresh();
//Creation of new thread.
this->Thread1 =
gcnew Thread(gcnew ThreadStart(this, &MyForm::ThreadWindowTVVmixSelect));
this->Thread1->Start();
}
}
private:
void ThreadWindowTVVmixSelect()
{
Sleep(3000);
//SetTextWindowHDMIStatus("Vmix");
SetTextStatusOutput("");
GUIEvent = false;
}
delegate void StringArgReturningVoidDelegate(String^ text);
//Sets the status label in the form
private:
void SetTextStatusOutput(String^ text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this->StatusOutput->InvokeRequired)
{
StringArgReturningVoidDelegate^ d =
gcnew StringArgReturningVoidDelegate(this, &MyForm::SetTextStatusOutput);
this->Invoke(d, gcnew array<Object^> { text });
}
else
{
this->StatusOutput->Text = text;
}
}
Hopefully this will help anyone else looking to update a C++ CLR form from another thread.
CURRENT UI
NEW UI
I want to change the background color of a button in MFC application. I have created my user interface(UI) in MFC .I have added every controls from the toolbox.But the problem is that i want to change the background and foreground properties of a button and window.How it is possible?
please help me to change the properties of controls in MFC.In windows application we can directly change the properties in the property window.
But in the case of MFC application that is not possible.
please help me..i have not enough experience in MFC application development.....
Thanks in advance......................
code from dialer.h
class CButtonDialer : public CButton
{
// Construction
public:
CButtonDialer();
// Attributes
public:
CButton m_button;
// CButton IDC_KEY_1;
CBrush m_brush;
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CButtonDialer)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
// Implementation
public:
virtual ~CButtonDialer();
// Generated message map functions
protected:
//{{AFX_MSG(CButtonDialer)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
CFont m_FontLetters;
CMapStringToString m_map;
HTHEME m_hTheme;
void OpenTheme() { m_hTheme = OpenThemeData(m_hWnd, L"Button"); }
void CloseTheme() {
if (m_hTheme) { CloseThemeData(m_hTheme); m_hTheme = NULL; }
}
DECLARE_MESSAGE_MAP()
virtual void PreSubclassWindow();
afx_msg LRESULT OnThemeChanged();
afx_msg void OnMouseMove(UINT,CPoint);
afx_msg void OnSize(UINT type, int w, int h);
};
code from dialer.cpp file
#include "stdafx.h"
#include "ButtonDialer.h"
#include "Strsafe.h"
#include "const.h"
/////////////////////////////////////////////////////////////////////////////
// CButtonDialer
CButtonDialer::CButtonDialer()
{
//255,255,255
m_brush.CreateSolidBrush(
(173, 41, 41));
m_map.SetAt(_T("1"),_T(""));
m_map.SetAt(_T("2"),_T("ABC"));
m_map.SetAt(_T("3"),_T("DEF"));
m_map.SetAt(_T("4"),_T("GHI"));
m_map.SetAt(_T("5"),_T("JKL"));
m_map.SetAt(_T("6"),_T("MNO"));
m_map.SetAt(_T("7"),_T("PQRS"));
m_map.SetAt(_T("8"),_T("TUV"));
m_map.SetAt(_T("9"),_T("WXYZ"));
m_map.SetAt(_T("0"),_T(""));
m_map.SetAt(_T("*"),_T(""));
m_map.SetAt(_T("#"),_T(""));
}
CButtonDialer::~CButtonDialer()
{
CloseTheme();
}
BEGIN_MESSAGE_MAP(CButtonDialer, CButton)
ON_WM_THEMECHANGED()
ON_WM_MOUSEMOVE()
ON_WM_SIZE()
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CButtonDialer message handlers
void CButtonDialer::PreSubclassWindow()
{
OpenTheme();
HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
LOGFONT lf;
GetObject(hFont, sizeof(LOGFONT), &lf);
lf.lfHeight = 14;
StringCchCopy(lf.lfFaceName,LF_FACESIZE,_T("Microsoft Sans Serif"));
m_FontLetters.CreateFontIndirect(&lf);
DWORD dwStyle = ::GetClassLong(m_hWnd, GCL_STYLE);
dwStyle &= ~CS_DBLCLKS;
::SetClassLong(m_hWnd, GCL_STYLE, dwStyle);
}
LRESULT CButtonDialer::OnThemeChanged()
{
CloseTheme();
OpenTheme();
return 0L;
}
void CButtonDialer::OnSize(UINT type, int w, int h)
{
CButton::OnSize(type, w, h);
}
void CButtonDialer::OnMouseMove(UINT nFlags,CPoint point)
{
CRect rect;
GetClientRect(&rect);
if (rect.PtInRect(point)) {
if (GetCapture() != this) {
SetCapture();
Invalidate();
}
}
else {
ReleaseCapture();
Invalidate();
}
CButton::OnMouseMove(nFlags, point);
}
void CButtonDialer::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC dc;
dc.Attach(lpDrawItemStruct->hDC); //Get device context object
CRect rt;
rt = lpDrawItemStruct->rcItem; //Get button rect
dc.FillSolidRect(rt,dc.GetBkColor());
dc.SetBkMode(TRANSPARENT);
CRect rtl = rt;
UINT state = lpDrawItemStruct->itemState; //Get state of the button
if (!m_hTheme) {
UINT uStyle = DFCS_BUTTONPUSH;
if ( (state & ODS_SELECTED) ) {
uStyle |= DFCS_PUSHED;
rtl.left+=1;
rtl.top+=1;
}
dc.DrawFrameControl(rt, DFC_BUTTON, uStyle);
} else {
UINT uStyleTheme = RBS_NORMAL;
if ( (state & ODS_SELECTED) ) {
uStyleTheme = PBS_PRESSED;
} else if (GetCapture()==this) {
uStyleTheme = PBS_HOT;
}
DrawThemeBackground(m_hTheme, dc.m_hDC,
BP_PUSHBUTTON, uStyleTheme,
rt, NULL);
}
CString strTemp;
GetWindowText(strTemp); // Get the caption which have been set
rtl.top += 4;
CString letters;
COLORREF crOldColor;
if (m_map.Lookup(strTemp,letters)) {
rtl.left+=15;
dc.DrawText(strTemp,rtl,DT_LEFT|DT_TOP|DT_SINGLELINE); // Draw out the caption
HFONT hOldFont = (HFONT)SelectObject(dc.m_hDC, m_FontLetters);
// Do your text drawing
rtl.left += 13;
rtl.top += 4;
rtl.right -=4;
crOldColor = dc.SetTextColor(RGB(148, 167, 70));
dc.DrawText(letters,rtl,DT_LEFT | DT_TOP | DT_SINGLELINE);
dc.SetTextColor(crOldColor);
// Always select the old font back into the DC
SelectObject(dc.m_hDC, hOldFont);
} else {
//127,127,127
crOldColor = dc.SetTextColor(RGB(148, 167, 70));
dc.DrawText(strTemp,rtl,DT_CENTER|DT_TOP|DT_SINGLELINE); // Draw out the caption
dc.SetTextColor(crOldColor);
}
if ( (state & ODS_FOCUS ) ) // If the button is focused
{
int iChange = 3;
rt.top += iChange;
rt.left += iChange;
rt.right -= iChange;
rt.bottom -= iChange;
dc.DrawFocusRect(rt);
}
dc.Detach();
}
BOOL CButtonDialer::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
GetClientRect(&rect);
//255,255,255
CBrush myBrush(RGB(173, 41, 41)); // dialog background color
CBrush *pOld = pDC->SelectObject(&myBrush);
BOOL bRes = pDC->PatBlt(0, 0, rect.Width(), rect.Height(), PATCOPY);
pDC->SelectObject(pOld); // restore old brush
return bRes; // CDialog::OnEraseBkgnd(pDC);
}
You need to provide a message handler for the WM_ERASEBKGND message and paint the background yourself.
Put a normal button on the Resource Editor.
On the .h file of the form where you use it, declare a CMFCButton variable like m_btnRead.
In the DoDataExchange method of your form append a line
DDX_Control(pDX, IDC_BUTTON_READ, m_btnRead);
On the method where you initialize your form (OnInitDialog, Create, etc.) append a line
m_btnRead.SetFaceColor(RGB(0, 255, 255));
and now you are done!
I am new to VC++ and its been a few times now, and this is the third program that does not give output even after it is build succesfully.
#include <AFXWIN.H>
#include <math.h>
#define PI 3.1415926
#define SEGMENTS 500
class CMyApp : public CWinApp {
public:
virtual BOOL InitInstance();
};
class CMainWindow : public CFrameWnd
{
public:
CMainWindow();
protected:
afx_msg void OnPaint();
afx_msg void OnLButtonDown(UINT, CPoint);
DECLARE_MESSAGE_MAP();
};
CMyApp myAPP;
BOOL CMyApp::InitInstance() {
m_pMainWnd = new CMainWindow;
m_pMainWnd->ShowWindow(SW_MAXIMIZE);
m_pMainWnd->UpdateWindow();
return TRUE;
}
BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)
ON_WM_PAINT ()
END_MESSAGE_MAP ()
CMainWindow::CMainWindow() {
Create(NULL,"The Hello Application",WS_OVERLAPPEDWINDOW);
}
void CMainWindow::OnPaint() {
CRect rect;
int nWidth = rect.Width();
int nHeight = rect.Height();
CPaintDC dc (this);
CPoint aPoint[SEGMENTS];
for (int i =0; i < SEGMENTS; i++){
aPoint[i].x = ((i*nWidth)/SEGMENTS );
aPoint[i].y= (int)((nHeight/2)* (1-(sin((2*PI*i)/SEGMENTS))));
}
dc.Polyline(aPoint, SEGMENTS);
UpdateData(false);
}
The above program should give Sine curve as the output, except that I get a blank window. And I don't know why does it happen. If it helps, I am using VC++ 6.0
The problem is probably that the rectangle you use to get the width and height is not initialized. You have to get the rectangle from somewhere, see e.g. CWnd::GetClientRect.
I'm currently developing a custom control that derives from CStatic MFC class (Smart Device C++ project).
I have created the control class using VC++ MFC class wizard, selecting CStatic class as its base class. I have used Class View to add OnSize event handler for my control class (I have selected WM_SIZE message from messages list), and new OnSize method has been created by Visual Studio along with ON_WM_SIZE() statement between BEGIN_MESSAGE_MAP(...) and END_MESSAGE_MAP().
The problem is that my control does not receive WM_SIZE thus OnSize method is never called - I used MoveWindow to change size of my control - its size changes as I have seen on dialog window but WM_SIZE message is never being sent. When I send WM_SIZE through SendMessage or PostMessage function - the control OnSize method is called normally. What do I wrong? I've read MSDN docs about CStatic control and there is no information that WM_SIZE message is never sent to a static control window.
Sorry for my bad English.
For a Windows dialog based project I've tested what you describe. I receive WM_SIZE messages in the custom control after a call of MoveWindow. Can you post a few pieces of your source code, especially for the dialog class where you use your custom Static control for your test?
Update after you posted your code
Did you run this in a debugger? I'm wondering why you don't get immediately an exception when the dialog is opened because CThreatSelection::OnSize is fired as one of the first events, even before the window handle threatGrid.m_hWnd of your control exists at all. So calling threatGrid.MoveWindow in your OnSize dialog event should cause an exception when the dialog opens.
I'm not sure what you are trying to achieve but it looks that you want to resize your custom Static according to the dialog size as soon as the dialog opens:
For this a possible alternative could be: Remove CThreatSelection::OnSize and place in CThreatSelection::OnInitDialog instead:
CThreatSelection::OnInitDialog()
{
CDialog::OnInitDialog();
// ... perhaps other Init-Stuff...
CRect rect;
GetClientRect(&rect);
threatGrid.MoveWindow(0,0, rect.Width(), rect.Height(), FALSE);
return TRUE;
}
Here you can call threatGrid.MoveWindow because the Window Handle threatGrid.m_hWnd is already created in OnInitDialog.
Below is a header of my CDialog based window generated by MFC wizard
#pragma once
#include "threatgrid.h"
#define COLUMN_COUNT 4
// CThreatSelection dialog
class CThreatSelection : public CDialog
{
DECLARE_DYNAMIC(CThreatSelection)
public:
CThreatSelection(CWnd* pParent = NULL); // standard constructor
virtual ~CThreatSelection();
// Dialog Data
enum { IDD = IDD_THSELECT };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
public:
virtual BOOL OnInitDialog();
private:
public:
// My custom cotrol field
CThreatGrid threatGrid;
afx_msg void OnSize(UINT nType, int cx, int cy);
};
Here is te body:
// ThreatSelection.cpp : implementation file
//
#include "stdafx.h"
#include "SpeedNotifyNative.h"
#include "ThreatSelection.h"
// CThreatSelection dialog
IMPLEMENT_DYNAMIC(CThreatSelection, CDialog)
CThreatSelection::CThreatSelection(CWnd* pParent /*=NULL*/)
: CDialog(CThreatSelection::IDD, pParent)
, threatGrid(theApp.imaging, 3)
{
}
CThreatSelection::~CThreatSelection()
{
}
void CThreatSelection::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_THGRID, threatGrid);
}
BEGIN_MESSAGE_MAP(CThreatSelection, CDialog)
ON_WM_SIZE()
END_MESSAGE_MAP()
// CThreatSelection message handlers
BOOL CThreatSelection::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CThreatSelection::OnSize(UINT nType, int cx, int cy)
{
threatGrid.MoveWindow(0,0, cx, cy, FALSE);
//threatGrid.SizeChanged(cx,cy); I use it normally because no WM_SIZE is sent to threatGrid
CDialog::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
}
...And my custom control header:
#pragma once
#include "atltypes.h"
#include "GridIcon.h"
// CThreatGrid
class ImagingSystem;
class CThreatGrid : public CStatic
{
DECLARE_DYNAMIC(CThreatGrid)
public:
CThreatGrid(ImagingSystem* imaging, int cols);
virtual ~CThreatGrid();
protected:
DECLARE_MESSAGE_MAP()
private:
// Obiekt podsystemu obrazowania
ImagingSystem* imaging;
// Ilość kolumn w siatce
int columns;
// Spacing elementów
int spacing;
public:
// Informuje kontrolkę o zmianie rozmiaru - dotychczas nie udało mi się znaleźć rozwiązania dlaczego WM_SIZE nie ejst wysyłane
void SizeChanged(int cx, int cy);
private:
// Aktualny rozmiar - śledzony niezależnie aby uniknąć niepotrzebnych przeładowań obrazków
CSize currSize;
// Lista ikon
std::vector icons;
public:
afx_msg void OnSize(UINT nType, int cx, int cy);
};
...and my custom control body:
// ThreatGrid.cpp : implementation file
//
#include "stdafx.h"
#include "SpeedNotifyNative.h"
#include "ThreatGrid.h"
// CThreatGrid
IMPLEMENT_DYNAMIC(CThreatGrid, CStatic)
CThreatGrid::CThreatGrid(ImagingSystem* imaging, int cols)
: imaging(imaging)
, columns(cols)
{
}
CThreatGrid::~CThreatGrid()
{
}
BEGIN_MESSAGE_MAP(CThreatGrid, CStatic)
ON_WM_SIZE()
END_MESSAGE_MAP()
// Informuje kontrolkę o zmianie rozmiaru - dotychczas nie udało mi się znaleźć rozwiązania dlaczego WM_SIZE nie ejst wysyłane
void CThreatGrid::SizeChanged(int cx, int cy)
{
CSize nSize(cx,cy);
if(nSize != currSize)
{
currSize = nSize;
int wspc = (int)(0.015 * cx);
int hspc = (int)(0.015 * cy);
spacing = (wspc 0 )
{
int rows = (icons.size() + columns - 1) / columns;
int width = (currSize.cx - spacing * (2 + columns - 1)) / columns;
int height = (currSize.cy - spacing * (2 + rows - 1)) / rows;
CSize size;
if ( width Calculate(i / columns, i % columns, abspoint, size, spacing);
}
}
}
}
void CThreatGrid::OnSize(UINT nType, int cx, int cy)
{
CStatic::OnSize(nType, cx, cy);
// NEVER CALLED BY SYSTEM
}