How to put checkbox in each CMFCTabCtrl's tab header - mfc

I have a MFC application. I am using CMFCTabCtrl in a dialog.
My requirement is I have to add a checkbox in each tab page of CMFCTabCtrl as below.
Is it possible to add checkbox in each tab page of CMFCTabCtrl ?

You can't do this with creating a check box window over the current CMFCTabCtrl.
My advice would be:
Implement your own Draw3dFlat or Draw3dTab functions. This function should draw the checkbox into the tab surface.
You may overwrite AdjustTabs to resize them to the size you want.
Implement your own OnLButtonDown handler that tracks if the user clicks into your checkbox...
You have all the original source code, it should be possible to implement this in using existing code.

My question was answered in the below link.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/2b86a6df-12bb-4fe2-9f23-d9848de49f84/adding-checkbox-in-cmfctabctrls-tab-header?forum=vcgeneral#000673ca-c995-42d8-85c2-cb4781090653
The code is
BOOL CMyDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// TODO: Add extra initialization here
CRect rectDummy;
rectDummy.SetRectEmpty();
if(!m_tab.Create(CMFCTabCtrl::STYLE_3D_VS2005, rectDummy, this, 1))
{
TRACE0("Failed to create output tab window\n");
return -1; // fail to create
}
m_tab.SetResizeMode(CMFCTabCtrl::RESIZE_NO);
m_tab.SetLocation(CMFCTabCtrl::LOCATION_TOP);
CRect rc;
GetClientRect(rc);
m_tab.MoveWindow(0, 200, rc.right, 200);
const DWORD dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;
if (!m_wndOutputBuild.Create(dwStyle, rectDummy, &m_tab, 2) ||
!m_wndOutputDebug.Create(dwStyle, rectDummy, &m_tab, 3) ||
!m_wndOutputFind.Create(dwStyle, rectDummy, &m_tab, 4))
{
TRACE0("Failed to create output windows\n");
return -1; // fail to create
}
CString strTabName;
BOOL bNameValid;
// Attach list windows to tab:
m_tab.AddTab(&m_wndOutputBuild, L" First", (UINT)0);
m_tab.AddTab(&m_wndOutputDebug, L" Second", (UINT)1);
m_tab.AddTab(&m_wndOutputFind, L" Third", (UINT)2);
m_tab.init();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
} myTabCtrl.h
#pragma once
#include "afxtabctrl.h"
class myTabCtrl : public CMFCTabCtrl
{
public:
myTabCtrl();
~myTabCtrl();
void init();
DECLARE_MESSAGE_MAP()
CButton m_Check1;
CButton m_Check2;
CButton m_Check3;
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
}; myTabCtrl.cpp
#include "stdafx.h"
#include "myTabCtrl.h"
myTabCtrl::myTabCtrl()
{
}
myTabCtrl::~myTabCtrl()
{
}
void myTabCtrl::init()
{
CRect rc1, rc2, rc3;
GetTabRect(0, rc1);
GetTabRect(1, rc2);
GetTabRect(2, rc3);
m_Check1.Create(_T("Chkbox1"), WS_CHILD | WS_VISIBLE | BS_CHECKBOX, CRect(0, 0, 13, 13), this, 1234);
m_Check2.Create(_T("Chkbox2"), WS_CHILD | WS_VISIBLE | BS_CHECKBOX, CRect(0, 0, 13, 13), this, 1235);
m_Check3.Create(_T("Chkbox3"), WS_CHILD | WS_VISIBLE | BS_CHECKBOX, CRect(0, 0, 13, 13), this, 1236);
m_Check1.MoveWindow(rc1.left + 20, rc1.top + 3, 13, 13);
m_Check2.MoveWindow(rc2.left + 20, rc2.top + 3, 13, 13);
m_Check3.MoveWindow(rc3.left + 20, rc3.top + 3, 13, 13);
}
BEGIN_MESSAGE_MAP(myTabCtrl, CMFCTabCtrl)
END_MESSAGE_MAP()
LRESULT myTabCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
switch (message)
{
case WM_COMMAND:
if (wParam == 1234)
{
BOOL checked = m_Check1.GetCheck();
m_Check1.SetCheck(!checked);
}
else if (wParam == 1235)
{
BOOL checked = m_Check2.GetCheck();
m_Check2.SetCheck(!checked);
}
else if (wParam == 1236)
{
BOOL checked = m_Check3.GetCheck();
m_Check3.SetCheck(!checked);
}
break;
}
return CMFCTabCtrl::WindowProc(message, wParam, lParam);
}

Related

c++ winapi - best practice for switching between 2 different sets of buttons/control layouts in the same window on button press

I'm a hobbyist programmer coming back to C++ after many years away from programming and new to winapi so sorry for the "basic" GUI question. I'm trying to find the best practice for implementing the following, very common, behaviour.
From a users perspective this is the behaviour I want to create. I have 1 window with some buttons in it. The user clicks on 1 of the buttons and the window contents appears to change to show different buttons/text fields etc. The user interacts with these controls then finally clicks a "back" button and they are returned to the first screen.
This behaviour is so common I thought it would be easy to find examples and best practices for implementing it but clearly I'm not asking the right questions in google. Not sure if the right way forward is a new window, a child window and how to set up winproc to capture the events in these 2 options, i.e. a winproc for each window or child or 1 massive winproc for everything. Hence the best practice question.
Can anyone help, either be explaining the best way to set this up with the WINAPI or by pointing me to some material online. I've spent days looking, plenty on creating 1 windows with controls. Very happy to follow tutorials and experiment to learn more.
Thanks jwezorek I got very close to your updated code last night but still couldn't get the child events to work. Finally cracked it using your updated code and putting the page switch buttons in the same pane as the other buttons so all clicks were handled on a pane basis in the child winproc. Thank you all for your help. Code below in case it's of interest/use to anyone else.
#include <windows.h>
#define PANE1_ID 101
#define BUTTON11_ID 102
#define BUTTON12_ID 103
#define BUTTON_TO_PAGE_1 104
#define PANE2_ID 201
#define BUTTON21_ID 202
#define BUTTON22_ID 203
#define BUTTON_TO_PAGE_2 204
LRESULT CALLBACK parentWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK childWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
HINSTANCE g_hinst;
static HWND g_pane1;
static HWND g_pane2;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
g_hinst = hInstance;
MSG msg = { 0 };
// Parent window definition
WNDCLASS parentWindow = { 0 };
parentWindow.lpfnWndProc = parentWndProc;
parentWindow.hInstance = hInstance;
parentWindow.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
parentWindow.lpszClassName = L"MainWindow";
if (!RegisterClass(&parentWindow))
return 1;
// Child window definition
WNDCLASS childWindow = { 0 };
childWindow.lpfnWndProc = childWndProc;
childWindow.hInstance = hInstance;
childWindow.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
childWindow.lpszClassName = L"Pane";
if (!RegisterClass(&childWindow))
return 1;
// Create main window
if (!CreateWindow(parentWindow.lpszClassName, L"grouped buttons", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 640, 480, 0, 0, hInstance, NULL))
return 2;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK parentWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
// create pane 2 with button then hide the pane and the button to switch to pane 1
g_pane2 = CreateWindow(L"Pane", L"", WS_CHILD | WS_VISIBLE, 20, 20, 250, 200, hWnd, (HMENU)PANE2_ID, g_hinst, 0);
CreateWindow(L"BUTTON", L"Button 2.1", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 50, 10, 180, 35, g_pane2, (HMENU)BUTTON21_ID, g_hinst, 0);
CreateWindow(L"BUTTON", L"Button 2.2", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 50, 40, 180, 35, g_pane2, (HMENU)BUTTON22_ID, g_hinst, 0);
CreateWindow(L"BUTTON", L"Back to Page 1", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 50, 130, 180, 35, g_pane2, (HMENU)BUTTON_TO_PAGE_1, g_hinst, 0);
ShowWindow(g_pane2, SW_HIDE);
UpdateWindow(g_pane2);
// create pane 1 with buttons and show it and the button to switch to pane 2
g_pane1 = CreateWindow(L"Pane", L"", WS_CHILD | WS_VISIBLE, 20, 20, 250, 200, hWnd, (HMENU)PANE1_ID, g_hinst, 0);
CreateWindow(L"BUTTON", L"Button 1.1", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 10, 10, 180, 35, g_pane1, (HMENU)BUTTON11_ID, g_hinst, 0);
CreateWindow(L"BUTTON", L"Button 1.2", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 10, 40, 180, 35, g_pane1, (HMENU)BUTTON12_ID, g_hinst, 0);
CreateWindow(L"BUTTON", L"Go to page 2", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 10, 130, 180, 35, g_pane1, (HMENU)BUTTON_TO_PAGE_2, g_hinst, 0);
ShowWindow(g_pane1, SW_SHOW);
UpdateWindow(g_pane1);
break;
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK childWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_COMMAND) {
switch (wParam) {
case BUTTON_TO_PAGE_2:
{
// MessageBox(hWnd, L"You pressed go to page 2", L"Button Pressed", MB_OK);
ShowWindow(g_pane1, SW_HIDE);
ShowWindow(g_pane2, SW_SHOW);
}
break;
case BUTTON11_ID:
MessageBox(NULL, L"Button 1.1", L"Page 1 Button", 0);
break;
case BUTTON12_ID:
MessageBox(NULL, L"Button 1.2", L"Page 1 Button", 0);
break;
case BUTTON_TO_PAGE_1:
{
// MessageBox(hWnd, L"You pressed go to page 1", L"Button Pressed", MB_OK);
ShowWindow(g_pane2, SW_HIDE);
ShowWindow(g_pane1, SW_SHOW);
}
break;
case BUTTON21_ID:
MessageBox(NULL, L"Button 2.1", L"Page 2 Button", 0);
break;
case BUTTON22_ID:
MessageBox(NULL, L"Button 2.2", L"Page 2 Button", 0);
break;
}
return 0;
}
else {
return DefWindowProc(hWnd, message, wParam, lParam);
}
}

"Lights off" effect of the main application window

How to make a "Lights off" effect for the main application window? I mean this:
lights on:
lights off:
UPDATE-1:
I made my own "lights-off" window implementation.
The algorithm is as follows:
Create a new hidden child window (darkened window)
Creating a screenshot of the main window
Fill the darkened window with black brush and copy onto it HDC the screenshot using AlphaBlend() function with a certain transparency value
Show the darkened window.
And it works great. But there is one drawback - when show and hide the darkened window then all child controls of the main window are painted in its color (darkened window color) for a short time:
This:
Here is description from .rc-file:
mainWindow DIALOGEX 0, 0, 309, 177
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,198,156,50,14,WS_CLIPSIBLINGS
PUSHBUTTON "Cancel",IDCANCEL,252,156,50,14,WS_CLIPSIBLINGS
CONTROL "",IDC_TAB1,"SysTabControl32",0x0,7,4,204,111,WS_CLIPSIBLINGS
PUSHBUTTON "Button1",IDC_BUTTON1,228,18,22,17,WS_CLIPSIBLINGS
PUSHBUTTON "Button2",IDC_BUTTON2,262,43,32,19,WS_CLIPSIBLINGS
EDITTEXT IDC_EDIT1,216,46,35,15,ES_AUTOHSCROLL | WS_CLIPSIBLINGS
LTEXT "Static",IDC_STATIC1,223,86,59,11,WS_CLIPSIBLINGS
LTEXT "Static",IDC_STATIC2,7,119,36,13,WS_CLIPSIBLINGS
CONTROL "Check1",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_CLIPSIBLINGS | WS_TABSTOP,45,121,56,8
CONTROL "Check2",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_CLIPSIBLINGS | WS_TABSTOP,110,119,36,13
CONTROL "Check3",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_CLIPSIBLINGS | WS_TABSTOP,127,137,44,11
PUSHBUTTON "Button3",IDC_BUTTON3,110,154,55,16,WS_CLIPSIBLINGS
EDITTEXT IDC_EDIT2,232,72,40,14,ES_AUTOHSCROLL|WS_CLIPSIBLINGS
CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP | WS_CLIPSIBLINGS,220,106,69,15
CONTROL "Radio1",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON|WS_CLIPSIBLINGS,21,136,38,10
CONTROL "",IDC_SPIN1,"msctls_updown32",UDS_ARROWKEYS|WS_CLIPSIBLINGS,100,137,11,14
PUSHBUTTON "Button4",IDC_BUTTON4,17,149,50,14,WS_CLIPSIBLINGS
CONTROL "Check4",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP | WS_CLIPSIBLINGS,203,131,35,11
END
And now question is - how to fix this?
I wrote for you the first approach mentioned by Remy Lebeau:
LightLayer.h
#pragma once
#include <Windows.h>
class LightLayer
{
public:
/**
* darkness [0-255]
* 0: light
* 255: dark
*/
LightLayer(HWND attachedWindow, int darkness = 180);
bool isValid() const;
void turnLightOn();
void turnLightOff();
void setDarkness(int darkness);
void onWindowPosChanged(LPARAM lParam);
void onShowWindow(WPARAM wParam);
private:
bool mValid;
bool mMustShow;
bool mWinPosChanged;
HWND mLayer;
HWND mAttachedWin;
WNDPROC mDefProc;
void setVisibility(bool visibility);
void updatePos();
static INT_PTR CALLBACK LightsLayerProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
};
LightLayer.cpp
#include "LightLayer.h"
LightLayer::LightLayer(HWND attachedWindow, int darkness)
{
mValid = false;
mMustShow = false;
mWinPosChanged = false;
mAttachedWin = NULL;
mLayer = CreateWindowEx(
WS_EX_LAYERED,
L"STATIC",
NULL,
WS_POPUP,
0, 0, 0, 0,
attachedWindow,
NULL, NULL, NULL);
if (mLayer)
{
mValid = true;
mAttachedWin = attachedWindow;
SetWindowLongPtr(mLayer, GWLP_USERDATA, (LONG_PTR) this);
mDefProc = (WNDPROC) SetWindowLongPtr(mLayer, GWLP_WNDPROC, (LONG_PTR) LightsLayerProc);
setDarkness(darkness);
}
}
bool LightLayer::isValid() const
{
return mValid;
}
void LightLayer::turnLightOn()
{
setVisibility(false);
}
void LightLayer::turnLightOff()
{
setVisibility(true);
}
void LightLayer::setDarkness(int darkness)
{
if(mValid)
SetLayeredWindowAttributes(mLayer, 0, darkness, LWA_ALPHA);
}
void LightLayer::setVisibility(bool visibility)
{
if (!mValid)
return;
mMustShow = visibility;
if (visibility)
updatePos();
ShowWindow(mLayer, visibility ? SW_SHOW : SW_HIDE);
SetFocus(mAttachedWin);
}
void LightLayer::updatePos()
{
if (!mValid)
return;
RECT rc;
GetClientRect(mAttachedWin, &rc);
MapWindowPoints(mAttachedWin, GetParent(mAttachedWin), (LPPOINT)&rc, 2);
SetWindowPos(mLayer, HWND_NOTOPMOST,
rc.left,
rc.top,
rc.right - rc.left,
rc.bottom - rc.top,
0);
OutputDebugStringA("\nupdatePos");
}
void LightLayer::onWindowPosChanged(LPARAM lParam)
{
if (!mValid)
return;
if (mMustShow)
{
updatePos();
mWinPosChanged = false;
}
else
mWinPosChanged = true;
}
void LightLayer::onShowWindow(WPARAM wParam)
{
setVisibility(wParam && mMustShow);
}
INT_PTR CALLBACK LightLayer::LightsLayerProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LightLayer* caller = reinterpret_cast<LightLayer*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
switch (uMsg)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
FillRect(hdc, &ps.rcPaint, GetSysColorBrush(COLOR_BACKGROUND));
EndPaint(hWnd, &ps);
}
break;
}
return caller->mDefProc(hWnd, uMsg, wParam, lParam);
}
And now add this to your dialog procedure:
LightLayer* lightLyr = nullptr;
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
lightLyr = new LightLayer(hDlg, 180);
// Check if it's valid (e.g. no errors upon window creation)
if (! lightLyr->isValid())
{
delete lightLyr;
lightLyr = nullptr;
}
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_OFF:
{
if(lightLyr)
{
lightLyr->turnLightOff();
SendDlgItemMessage(hDlg, IDC_ON, BM_SETCHECK, BST_UNCHECKED, 0);
}
break;
}
case IDC_ON:
{
if(lightLyr)
{
lightLyr->turnLightOn();
SendDlgItemMessage(hDlg, IDC_OFF, BM_SETCHECK, BST_UNCHECKED, 0);
}
break;
}
}
break;
case WM_WINDOWPOSCHANGED:
if(lightLyr)
lightLyr->onWindowPosChanged(lParam);
break;
case WM_SHOWWINDOW:
if(lightLyr)
lightLyr->onShowWindow(wParam);
break;
case WM_DESTROY:
delete lightLyr;
break;
}
return 0;
}
And here's a showcase.

Is there a way I can run 3 CreateWindow functions at once?

I working on my new program about asking the user if he agree to the terms.
My program is creating a black window with a checkbox, when the user check the checkbox,
an button called "RUN" created.
My problem is that I can't change the color of the static text next to the checkbox, I must create first the checkbox and then create and change the static text.
Let me explain, my WM_CREATE is using three CreateWindow functions, one is the checkbox and after it comes the "RUN" button, and the last one is the static text, next to the checkbox.
Now, when I create first the button, the button work well and I can check it and uncheck it, but the static text is not working well.
For the static text I removed his background and change his color with WM_CTLCOLORSTATIC, but the background is not removed and the color too.
Now, when I create first the text, the text is working well and the color and the background are changed, and the button isn't working, I can't check it or uncheck it.
Please try to debug my program, it is hard to explain.
You need to try to switch between the two functions in the WM_CREATE, try to create first text and then you can see that the checkbox is not working well.
My whole program:
#include <windows.h>
#include <iostream>
#include <thread>
using namespace std;
// Text
#define IDC_STATIC 1
// Buttons
#define IDC_BUTTON 2
HWND agree, button1, text;
LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM param, LPARAM lparam);
int WINAPI WinMain(HINSTANCE currentInstance, HINSTANCE previousInstance, PSTR cmdLine, INT cmdCount)
{
// Register the window class
const char* CLASS_NAME = "myWin32WindowClass";
WNDCLASS wc{};
wc.hInstance = currentInstance;
wc.lpszClassName = CLASS_NAME;
wc.hIcon = 0;
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = CreateSolidBrush(RGB(20, 20, 20));
wc.lpfnWndProc = WindowProcessMessages;
RegisterClass(&wc);
HWND main = CreateWindow(CLASS_NAME, "WastedBit 1.6.2",
WS_VISIBLE, // Window style
CW_USEDEFAULT, CW_USEDEFAULT, // Window initial position
950, 750, // Window size
nullptr, nullptr, nullptr, nullptr);
// TopMost
SetWindowPos(main, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
// Window loop
MSG msg{};
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_CREATE: {
button1 = CreateWindow("button", 0, WS_VISIBLE | WS_CHILD | BS_CHECKBOX, 20, 490, 15, 15, hwnd, (HMENU)1, ((LPCREATESTRUCT)lparam)->hInstance, NULL);
agree = CreateWindow("button", "RUN", WS_CHILD, 750, 525, 150, 150, hwnd, 0, 0, 0);
text = CreateWindow("static", "By checking this button, you agree to the terms above", WS_CHILD | WS_VISIBLE, 30, 490, 150, 150, hwnd, (HMENU)IDC_STATIC, 0, 0);
}
break;
case WM_COMMAND: {
BOOL checked = IsDlgButtonChecked(hwnd, 1);
if (checked) {
CheckDlgButton(hwnd, 1, BST_UNCHECKED);
ShowWindow(agree, SW_HIDE);
}
else {
CheckDlgButton(hwnd, 1, BST_CHECKED);
ShowWindow(agree, SW_SHOW);
}
}
break;
case WM_DESTROY: {
PostQuitMessage(0);
}
break;
case WM_CTLCOLORSTATIC: {
if ((HWND)lparam == GetDlgItem(hwnd, IDC_STATIC))
{
SetBkMode((HDC)wparam, TRANSPARENT);
SetTextColor((HDC)wparam, RGB(400, 0, 0));
return (BOOL)GetStockObject(NULL_BRUSH);
}
break;
}
break;
default:
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}
I have tried to use it with valueless functions, but still the same.
Your problem is that you have same child-window identifiers.
Change:
button1 = CreateWindow("button", 0, WS_VISIBLE | WS_CHILD | BS_CHECKBOX, 20, 490, 15, 15, hwnd, (HMENU)1, ((LPCREATESTRUCT)lparam)->hInstance, NULL);
to something:
#define ID_BUTTON_2 101
button1 = CreateWindow("button", 0, WS_VISIBLE | WS_CHILD | BS_CHECKBOX, 20, 490, 15, 15, hwnd, (HMENU)ID_BUTTON_2, ((LPCREATESTRUCT)lparam)->hInstance, NULL);
When you receive WM_COMMAND, you should check WM_COMMAND source.
You created 3 controls, so, they can send you WM_COMMAND.
WM_COMMAND source can be known from control id ( parameter HMENU of CreateWindow ).
Here is quick fix.
case WM_COMMAND:
if( wparam == 1 ) {
BOOL checked = IsDlgButtonChecked(hwnd, 1);
if (checked) {
CheckDlgButton(hwnd, 1, BST_UNCHECKED);
ShowWindow(agree, SW_HIDE);
}
else {
CheckDlgButton(hwnd, 1, BST_CHECKED);
ShowWindow(agree, SW_SHOW);
}
}
}
break;

Is there a way I can hide a button when checkbox is unchecked?

I working to make a program that the user must agree to continue with the program.
The user must check the checkbox to continue, if the user check the checkbox, the "RUN" button displayed, and if he unchecked the checkbox, the button is hidden.
I have two problems with my program, when the user unchecked the checkbox, the "RUN" button does not disappeared, and the second problem is that when the user click on the "RUN" button, my program thinks that the user clicked on the checkbox and check or unchecked the checkbox.
This is my whole program, I would be very happy if you helped me.
If you want you can debug this program and see my problems.
#include <windows.h>
#include <iostream>
#include "resource.h"
using namespace std;
LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM param, LPARAM lparam);
const char *title = "Check Box";
HWND agree, button;
int WINAPI WinMain(HINSTANCE currentInstance, HINSTANCE previousInstance, PSTR cmdLine, INT cmdCount)
{
// Register the window class
const char* CLASS_NAME = "myWin32WindowClass";
WNDCLASS wc{};
wc.hInstance = currentInstance;
wc.lpszClassName = CLASS_NAME;
wc.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1));
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = CreateSolidBrush(RGB(20, 20, 20));
wc.lpfnWndProc = WindowProcessMessages;
RegisterClass(&wc);
HWND main = CreateWindow(CLASS_NAME, "WastedBit 1.6.2",
WS_OVERLAPPED | WS_VISIBLE | WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU, // Window style
CW_USEDEFAULT, CW_USEDEFAULT, // Window initial position
950, 750, // Window size
nullptr, nullptr, nullptr, nullptr);
// TopMost
SetWindowPos(main, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
// Window loop
MSG msg{};
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_CREATE: {
button = CreateWindow("button", 0,
WS_VISIBLE | WS_CHILD | BS_CHECKBOX,
20, 490, 15, 15,
hwnd, (HMENU)1, ((LPCREATESTRUCT)lparam)->hInstance, NULL);
CheckDlgButton(hwnd, 1, BST_UNCHECKED);
}
break;
case WM_COMMAND: {
BOOL checked = IsDlgButtonChecked(hwnd, 1);
if (checked) {
CheckDlgButton(hwnd, 1, BST_UNCHECKED);
}
else if (CheckDlgButton(hwnd, 1, BST_CHECKED) == TRUE) {
CheckDlgButton(hwnd, 1, BST_CHECKED);
agree = CreateWindow("button", "RUN", WS_VISIBLE | WS_CHILD, 750, 525, 150, 150, hwnd, (HMENU)button, 0, 0);
}
else if (CheckDlgButton(hwnd, 1, BST_UNCHECKED) == TRUE) {
ShowWindow(agree, SW_HIDE);
}
}
break;
case WM_DESTROY: {
PostQuitMessage(0);
}
break;
default:
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}
My program works great with #duDE's help.
I put the button and the checkbox in WM_CREATE, I make the button to be invisible when created, but when the user check the checkbox, the button is created.
I wouldn't consider it a problem, but once the "RUN" button is pressed, the button disappears and the checkbox return to be unchecked.
LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_CREATE: {
button = CreateWindow("button", 0,
WS_VISIBLE | WS_CHILD | BS_CHECKBOX,
20, 490, 15, 15,
hwnd, (HMENU)1, ((LPCREATESTRUCT)lparam)->hInstance, NULL);
agree = CreateWindow("button", "RUN", WS_CHILD, 750, 525, 150, 150, hwnd, 0, 0, 0);
}
break;
case WM_COMMAND: {
BOOL checked = IsDlgButtonChecked(hwnd, 1);
if (checked) {
CheckDlgButton(hwnd, 1, BST_UNCHECKED);
ShowWindow(agree, SW_HIDE);
}
else {
CheckDlgButton(hwnd, 1, BST_CHECKED);
ShowWindow(agree, SW_SHOW);
}
}
break;
case WM_DESTROY: {
PostQuitMessage(0);
}
break;
default:
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}
I would create both objects (the check box AND the button) in WM_CREATE, you will get the handleButton back.
And the hiding should happens in WM_COMMAND then like this:
BOOL checked = IsDlgButtonChecked(hwnd, 1);
if (checked)
ShowWindow(handleButton, SW_HIDE);
else
ShowWindow(handleButton, SW_SHOW);

How to place a toolbar inside an edit control?

My original goal was to place an X button inside an edit control (it later turned out that this edit control by itself must be a part of the combo box.) I've been suggested to use this article as a guidance.
To make it look a little bit "prettier" I decided to use a toolbar for that X button instead. So I came up with the following code. Here's how the control is initialized inside the ComboBox:
//Initialization
#define EDIT_X_TOOLBAR_BTN_W 10
#define EDIT_X_TOOLBAR_BTN_H 11
//Find edit control handle using GetComboBoxInfo() API
COMBOBOXINFO cbi2 = {0};
cbi2.cbSize = sizeof(cbi2);
GetComboBoxInfo(hComboWnd, &cbi2);
HWND hEditCtrl = cbi2.hwndItem;
HINSTANCE hInst = ::GetModuleHandle(NULL);
//Create toolbar as a child of the edit control
hWndToolbar = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
WS_CHILD | WS_VISIBLE |
CCS_NODIVIDER | CCS_NOPARENTALIGN |
CCS_NORESIZE | CCS_NOMOVEY | TBSTYLE_FLAT | TBSTYLE_TRANSPARENT,
0, 0, 0, 0,
hEditCtrl,
(HMENU)ID_CMD_EDIT_X_TOOLBAR, hInst, 0);
::SendMessage(hWndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
::SendMessage(hWndToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(EDIT_X_TOOLBAR_BTN_W, EDIT_X_TOOLBAR_BTN_H));
::SendMessage(hWndToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(EDIT_X_TOOLBAR_BTN_W, EDIT_X_TOOLBAR_BTN_H));
//Load bitmap
TBADDBITMAP tbab = {0};
tbab.hInst = hInst;
tbab.nID = IDB_BITMAP_TOOLBAR_X;
VERIFY(::SendMessage(hWndToolbar, TB_ADDBITMAP, 1, (LPARAM)&tbab) != -1);
TBBUTTON tbbs[1] = {0};
tbbs[0].iBitmap = 0;
tbbs[0].idCommand = CMD_EDIT_X_TOOLBAR_CLOSE;
tbbs[0].fsState = TBSTATE_ENABLED;
tbbs[0].fsStyle = TBSTYLE_BUTTON;
tbbs[0].iString = -1;
VERIFY(::SendMessage(hWndToolbar, TB_ADDBUTTONS, SIZEOF(tbbs), (LPARAM)tbbs));
//Subclass edit control
oldProc = (WNDPROC)::SetWindowLong(hEditCtrl, GWL_WNDPROC, (LONG)wndProcEditCtrl);
//And redraw the edit control
::SetWindowPos(hEditCtrl, NULL, 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
And this is the subclassed window proc for the edit control:
CRect rcToolbar;
LRESULT CALLBACK wndProcEditCtrl(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_NCCALCSIZE:
{
if(wParam)
{
//First let edit box process it
::CallWindowProc(oldProc, hWnd, msg, wParam, lParam);
RECT* pRc = (RECT*)lParam;
//Define toolbar size & move it
int nTB_w = pRc->bottom - pRc->top;
int nTB_h = nTB_w;
//Adjust the edit's client area
pRc->right -= nTB_w;
//Set toolbar rect
rcToolbar.SetRect(pRc->right, pRc->top, pRc->right + nTB_w, pRc->top + nTB_h);
//And move the toolbar
::MoveWindow(hWndToolbar, pRc->right, pRc->top, nTB_w, nTB_h, TRUE);
return 0;
}
}
break;
case WM_NCHITTEST:
{
POINT pnt;
pnt.x = GET_X_LPARAM(lParam);
pnt.y = GET_Y_LPARAM(lParam);
if(::ScreenToClient(hWnd, &pnt))
{
if(rcToolbar.PtInRect(pnt))
{
return HTBORDER;
}
}
}
break;
}
return ::CallWindowProc(oldProc, hWnd, msg, wParam, lParam);
}
The issue is that I can see that the toolbar is created (via Spy++) but it remains inactive and I don't see my button (all I get is a gray rectangle on the right):
To make sure that I can create the toolbar itself, if I change its parent window from the edit control (i.e. hEditCtrl) to the main dialog window, it is displayed (in a wrong place) and responds to clicks just fine. So my conclusion is that I must be blocking some messages to it in my subclass. The question is which ones?
Any idea what am I missing here?