Event when a particular Slider is changed - visual-c++

I am writing a C++ MFC Dialog based Application and my program has lots of sliders. I want the program to call a function depending on which Slider is being changed by the user. I tried using GetPos() but not much success so far. Any easier way of doing this?
Message Map:
BEGIN_MESSAGE_MAP(CSerialPortDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
//ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedButton1)
ON_BN_CLICKED(IDC_READ_COMM, OnBnClickedReadComm)
ON_WM_CLOSE()
ON_BN_CLICKED(IDC_WRITE, OnBnClickedWrite)
//ON_CBN_SELCHANGE(IDC_SENSORS, OnCbnSelchangeSensors)
//ON_CBN_SELCHANGE(IDC_SENSOR_LIST, OnCbnSelchangeSensorList)
ON_BN_CLICKED(IDC_GO, OnGo)
ON_WM_TIMER()
ON_BN_CLICKED(IDC_KILL_TIMER, OnBnClickedKillTimer)
ON_BN_CLICKED(IDC_READ_TIMER, OnBnClickedReadTimer)
ON_BN_CLICKED(IDC_WRITE_COMM, OnBnClickedWriteComm)
ON_BN_CLICKED(IDC_TERMINATE, OnBnClickedTerminate)
ON_BN_CLICKED(IDC_RUN, OnBnClickedRun)
ON_CONTROL(NM_CLICK,IDC_BOOM_SLIDER, Write_Boom)
ON_CONTROL(NM_CLICK,IDC_PITCH_SLIDER, Write_Pitch)
END_MESSAGE_MAP()
...

Slider controls send WM_HSCROLL or WM_VSCROLL notifications when they are scrolled, horizontally or vertically. Catch them in your dialog and there you can call your desired function, depending on who sent the notification.
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
//...
ON_WM_HSCROLL()
//...
END_MESSAGE_MAP()
//////////////////////////
// nSBCode: The operation performed on the slider
// nPos: New position of the slider
// pScrollBar: The scrollbar (slider ctrl in this case) that sent the notification
void CMyDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
CSliderCtrl* pSlider = reinterpret_cast<CSliderCtrl*>(pScrollBar);
// Check which slider sent the notification
if (pSlider == &c_Slider1)
{
}
else if (pSlider == &c_Slider2)
{
}
// Check what happened
switch(nSBCode)
{
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
case TB_THUMBPOSITION:
case TB_TOP:
case TB_BOTTOM:
case TB_THUMBTRACK:
case TB_ENDTRACK:
default:
break;
}
//...
}
`

BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
//...
ON_WM_HSCROLL()
//...
END_MESSAGE_MAP()
void CMyDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
CSliderCtrl *ACSliderCtrl = (CSliderCtrl *)pScrollBar;
int nID = ACSliderCtrl->GetDlgCtrlID();
int NewPos = ((CSliderCtrl *)pScrollBar)->GetPos();
CWnd *ACWnd = GetDlgItem(nID);
switch (nID)
{
default:
break;
case IDC_SLIDER1:
m_edit1.Format( "%d", NewPos );
UpdateData(FALSE);
break;
}
CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}

I figured it out, I think. What you call a slider is commonly called a "Scrollbar". You're probably looking for the WM_VSCROLL message. As noted there, "lParam: If the message is sent by a scroll bar, this parameter is the handle to the scroll bar control."
See also CWnd::OnVScroll

You do have different ON_CONTROL macro's for the different controls? Because it's then just a matter of specifying different methods as the third argument to ON_CONTROL

Related

SubclassDlgItem() debug assertion failed

I have created a dailog box with custom control. I am using ultimate grid in my application. (https://www.codeproject.com/Articles/20183/The-Ultimate-Grid-Home-Page).
I am having an error (Debug Assertion Failed) when I run my project.
BOOL CCustomControlDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 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)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
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
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
// Add "About..." menu item to system menu.
m_grid.AttachGrid(this, IDC_CUSTOM1);// ERROR LINE
return TRUE; // return TRUE unless you set the focus to a control
}
//Attach grid implementation
BOOL CUGCtrl::AttachGrid(CWnd * wnd,UINT ID){
if( SubclassDlgItem(IDC_CUSTOM1,wnd)) // ERROR LINE
{
long style = GetWindowLong(m_hWnd,GWL_STYLE);
style = style|WS_CLIPCHILDREN|WS_TABSTOP;
SetWindowLong(m_hWnd,GWL_STYLE,style);
// if the parent window is specified
if(wnd!= NULL)
{
LOGFONT logFont;
CFont *pTempFont = wnd->GetFont();
pTempFont->GetLogFont( &logFont );
// ceate a font object based on the font information retrieved from
// parent window. This font will be used as grid's default font.
int nIndex = AddFont( logFont.lfHeight, logFont.lfWidth, logFont.lfEscapement,
logFont.lfOrientation, logFont.lfWeight, logFont.lfItalic,
logFont.lfUnderline, logFont.lfStrikeOut, logFont.lfCharSet,
logFont.lfOutPrecision, logFont.lfClipPrecision,
logFont.lfQuality, logFont.lfPitchAndFamily, logFont.lfFaceName );
SetDefFont( nIndex );
// create a font that will be used for the heading cells. This object
// is almost identical to the grid's default font, except its weight
// was increased by 200.
nIndex = AddFont( logFont.lfHeight, logFont.lfWidth, logFont.lfEscapement,
logFont.lfOrientation, logFont.lfWeight + 200, logFont.lfItalic,
logFont.lfUnderline, logFont.lfStrikeOut, logFont.lfCharSet,
logFont.lfOutPrecision, logFont.lfClipPrecision,
logFont.lfQuality, logFont.lfPitchAndFamily, logFont.lfFaceName );
CUGCell cell;
GetHeadingDefault( &cell );
cell.SetFont( GetFont( nIndex ) );
SetHeadingDefault( &cell );
}
CreateChildWindows();
// When WS_EX_RTLREADING style was specified for the place holder
// window, then set the grid to be in RTL layout mode.
style = GetWindowLong( m_hWnd, GWL_EXSTYLE );
if ( style&WS_EX_RTLREADING )
SetGridLayout( 1 );
OnSetup();
OnSheetSetup(0);
// Allow drawing after the grid is initialized
m_GI->m_paintMode = TRUE;
// Adjust the grid's components to fit current setup
AdjustComponentSizes();
return TRUE;
}
return FALSE;
}
Anyone having any idea how to fix this??
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
void CCustomControlDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CCustomControlDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
DDX_Control(pDX, IDC_CUSTOM1, m_drawpad);
//}}AFX_DATA_MAP
}
The issue is, that you are attaching two different C++ objects to the same control (IDC_CUSTOM1). The entry in DoDataExchange() implicitly performs the subclassing by calling DDX_Control(pDX, IDC_CUSTOM1, m_drawpad);, while the code in OnInitDialog() is more explicit (m_grid.AttachGrid(this, IDC_CUSTOM1);), but essentially does the same thing.
To fix this, you have a number of options, depending on what you are after:
Remove the DDX_Control() call in DoDataExchange() if you don't need the m_drawpad object attached to IDC_CUSTOM1.
Remove the m_grid.AttachGrid() call inside OnInitDialog(), if you don't need the m_grid object attached to IDC_CUSTOM1.
Add an additional control placeholder to your dialog resource and use that for either of those objects, in case you need both.

Starting Doc/View application hidden

Using Visual studio 2010 and MFC Doc/View Applications I want my SDI application to start up completely hidden, and after sometime or with receiving some message from tray icon it shows the mainframe, view and so on. I change the line m_pMainWnd->ShowWindow(SW_NORMAL); to m_pMainWnd->ShowWindow(SW_HIDE); in BOOL CMyApp::InitInstance() but the main frame just flickers after executing the application and then goes hiiden what should I do inorder to avoid this problem and keep the showing capability of main frame when ever I want.
Here is the solution for SDI/MDI app: The new MFC (with VC2010) overrides the m_nCmdShow value with a setting stored in the system registry. To change this behaviour, simply override the LoadWindowPlacement virtual function in the application class.
BOOL CAdVisuoApp::LoadWindowPlacement(CRect& rectNormalPosition, int& nFflags, int& nShowCmd)
{
BOOL b = CWinAppEx::LoadWindowPlacement(rectNormalPosition, nFflags, nShowCmd);
nShowCmd = SW_HIDE;
return b;
}
Normally if you have VC2005 or earlier the following will do:
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
m_nCmdShow = SW_HIDE;
// Dispatch commands specified on the command line. Will return FALSE if
// app was launched with /RegServer, /Register, /Unregserver or /Unregister.
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The one and only window has been initialized, so show and update it
m_pMainWnd->ShowWindow( m_nCmdShow);
m_pMainWnd->UpdateWindow();
Note that m_nCmdShow should be set to SW_HIDE before ProcessShallCommand for the flicker not to occur.
It looks like there might be a bug in VC2010 though. Since I have done this before it intrigued me and tried a fresh VC2010 project but it was not working. I noticed the problem was deep in the following MFC function.
BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
CWnd* pParentWnd, CCreateContext* pContext)
{
// only do this once
ASSERT_VALID_IDR(nIDResource);
ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);
m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOURCE)
CString strFullString;
if (strFullString.LoadString(nIDResource))
AfxExtractSubString(m_strTitle, strFullString, 0); // first sub-string
VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
// attempt to create the window
LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);
CString strTitle = m_strTitle;
if (!Create(lpszClass, strTitle, dwDefaultStyle, rectDefault,
pParentWnd, ATL_MAKEINTRESOURCE(nIDResource), 0L, pContext))
{
return FALSE; // will self destruct on failure normally
}
// save the default menu handle
ASSERT(m_hWnd != NULL);
m_hMenuDefault = m_dwMenuBarState == AFX_MBS_VISIBLE ? ::GetMenu(m_hWnd) : m_hMenu;
// load accelerator resource
LoadAccelTable(ATL_MAKEINTRESOURCE(nIDResource));
if (pContext == NULL) // send initial update
SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
return TRUE;
}
m_nCmdShow is still SW_HIDE when this function executes but it changes to SW_SHOWNORMAL when if (!Create(lpszClass... line executes. I don't know why this happens in VC2010 project only, sounds like a bug to me.
My sample project was SDI.
This comes from a dialog based application but you should be able to convert it to a Doc/View app as well. You need to handle the OnWindowPosChanging event. The key line is the the one inside the if statement. This allows my application to start completely hidden from view.
void CIPViewerDlg::OnWindowPosChanging( WINDOWPOS FAR* lpWindowPosition )
{
if( !m_bVisible )
{
lpWindowPosition->flags &= ~SWP_SHOWWINDOW;
}
CDialog::OnWindowPosChanging( lpWindowPosition );
}
Make sure that you are correctly turning off the WS_VISIBLE bit in CMainFrame::PreCreateWindow(CREATESTRUCT& cs). Something like this should worK:
cs.style &= ~WS_VISIBLE;
We had simply been negating the bit instead of turning it off, and we got away with it in VS 6.0 because this function was called only once. It is called twice in newer versions of Visual Studio, so in the second call we were flipping it right back on again. :-O
I tried all for Visual Studio 2010 and finished up with:
class CMainFrame : public CFrameWndEx
{
// ...
// Attributes
public:
BOOL m_bForceHidden;
// ...
// Overrides
public:
virtual void ActivateFrame(int nCmdShow = -1);
//...
};
CMainFrame::CMainFrame() : m_bForceHidden(TRUE)
{
// ...
}
void CMainFrame::ActivateFrame(int nCmdShow)
{
if(m_bForceHidden)
{
nCmdShow = SW_HIDE;
m_bForceHidden = FALSE;
}
CFrameWndEx::ActivateFrame(nCmdShow);
}
Other tricks did not work for me.
Found solution at:
http://forums.codeguru.com/showthread.php?478882-RESOLVED-Can-a-Doc-view-be-hidden-at-startup
I found in VS2017 (using BCGControlBar Pro which is what MFC Feature Pack was based on) that you have to handle things in two places:
BOOL CMainFrame::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext)
{
if (!__super::LoadFrame(nIDResource, dwDefaultStyle, pParentWnd, pContext))
{
return FALSE;
}
// undo what __super::LoadFrame() does where it will set it to SW_NORMAL if not SW_MAXIMIZED
AfxGetApp()->m_nCmdShow = SW_HIDE;
}
BOOL CTheApp::LoadWindowPlacement(CRect& rectNormalPosition, int& nFflags, int& nShowCmd)
{
BOOL b = __super::LoadWindowPlacement(rectNormalPosition, nFflags, nShowCmd);
nShowCmd = SW_HIDE;
return b;
}

MFC App with main window as modeless dialog

I am developing an MFC application and exporting it into dll. The application has only one window, and I want that window modeless. Inside InitInstance(), if I want it to be modal, I only need to do this:
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CUIWelcomeDlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
return false;
It works just fine as a modal. This is the code for the modeless one:
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CUIWelcomeDlg * dlg;
dlg=new CUIWelcomeDlg();
m_pMainWnd=dlg;
if(dlg!=NULL) {
dlg->Create(IDD_UIWELCOME_DIALOG,NULL);
dlg->ShowWindow(SW_SHOW);
}
return true;
I tried to debug it. It is fine until it reaches return true; After that, the dialog window freezes and is not responding. Does anyone know how to fix this?
Try to remove the following line:
m_pMainWnd = dlg;
(if dlg is a pointer here, you should call it pdlg).
You need to implement your own endless loop. Of course you don't want to stop the UI thread to be responsive so you need to capture and dispatch message inside this loop. Try adding this after ShowWindow:
MSG msg;
// Handle dialog messages
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if(!IsDialogMessage(&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

Getting edit box text from a modal MFC dialog after it is closed

From a modal MFC dialog, I want to extract text from an edit box after the dialog is closed. I attempted this:
CPreparationDlg Dlg;
CString m_str;
m_pMainWnd = &Dlg;
Dlg.DoModal();
CWnd *pMyDialog=AfxGetMainWnd();
CWnd *pWnd=pMyDialog->GetDlgItem(IDC_EDIT1);
pWnd->SetWindowText("huha max");
return TRUE;
It does not work.
The dialog and its controls is not created until you call DoModal() and as already pointed, is destroyed already by the time DoModal() returns. Because of that you cannot call GetDlgItem() neither before, nor after DoModal(). The solution to pass or retrieve data to a control, is to use a variable in the class. You can set it when you create the class instance, before the call to DoModal(). In OnInitDialog() you put in the control the value of the variable. Then, when the window is destroyed, you get the value from the control and put it into the variable. Then you read the variable from the calling context.
Something like this (notice I typed it directly in the browser, so there might be errors):
class CMyDialog : CDialog
{
CString m_value;
public:
CString GetValue() const {return m_value;}
void SetValue(const CString& value) {m_value = value;}
virtual BOOL OnInitDialog();
virtual BOOL DestroyWindow( );
}
BOOL CMyDialog::OnInitDialog()
{
CDialog::OnInitDialog();
SetDlgItemText(IDC_EDIT1, m_value);
return TRUE;
}
BOOL CMyDialog::DestroyWindow()
{
GetDlgItemText(IDC_EDIT1, m_value);
return CDialog::DestroyWindow();
}
Then you can use it like this:
CMyDialog dlg;
dlg.SetValue("stackoverflow");
dlg.DoModal();
CString response = dlg.GetValue();
Open your dialog resource, right-click on the textbox and choose "Add variable", pick value-type and CString
In the dialog-class: before closing, call UpdateData(TRUE)
Outside the dialog:
CPreparationDlg dlg(AfxGetMainWnd());
dlg.m_myVariableName = "my Value";
dlg.DoModal();
// the new value is still in dlg.m_myVariableName
DoModal() destroys the dialog box before it returns and so the value is no longer available.
It's hard to tell why you are setting m_pMainWnd to your dialog. To be honest, I'm not really sure what you are trying to do there. That's bound to cause problems as now AfxGetMainWnd() is broken.
Either way, you can't get the dialog box's control values after the dialog has been destroyed.
I often use
D_SOHINH dsohinh = new D_SOHINH();
dsohinh.vd_kichthuoc=v_kichthuocDOC;
dsohinh.vd_sohinh=v_soluongDOC;
if(dsohinh.DoModal()==IDOK)
{
v_soluongDOC=dsohinh.vd_sohinh;
v_kichthuocDOC=dsohinh.vd_kichthuoc;
}
SetModifiedFlag(true);
UpdateAllViews(NULL);
With dsohinh is Dialog form that you want to get data to mainform .
After get data then call SetModifiedFlag(true) to set view data updated.
call UpdateAllViews(NULL) to Set data to mainform
This solution may seem long, meaning that so much code has been written for this seemingly small task.
But when we have a list or tree inside the child window where all the items are created in the child window
and the items have to be moved to the parent window,
then it makes sense.
This source code can easily create a window and transfer information from the window before closing to the parents.
//copy the two functions in your code
//1- bool peek_and_pump(void)
// template<class T,class THISCLASS>
//2- void TshowWindow(int id,T *&pVar,THISCLASS *ths)
//and make two member variable
// bool do_exit;
// bool do_cancel;
//in child dialog class.
//set true value in do_exit in child dialog for exit
CchildDialog *dlg;
template<class T,class THISCLASS>
void TshowWindow(int id,T *&pVar,THISCLASS *ths)
{
T *p=pVar;
if(!p)
p= new T;
if(p->m_hWnd)
{
p->SetForegroundWindow();
}
else
{
delete p;
p= new T;
if(!(p->m_hWnd && IsWindow(p->m_hWnd)))
{
p->Create(id,ths);
if(IsWindow(p->m_hWnd))
p->ShowWindow(TRUE);
}
}
pVar=p;
}
bool peek_and_pump(void)
{
MSG msg;
#if defined(_AFX) || defined(_AFXDLL)
while(::PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))
{
if(!AfxGetApp()->PumpMessage())
{
::PostQuitMessage(0);
return false;
}
}
long lIdle = 0;
while(AfxGetApp()->OnIdle(lIdle++))
;
#else
if(::PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
#endif
return true;
}
void CparentPage::OnBnClick1()
{
if(dlg)
{
dlg->DestroyWindow();
}
TshowWindow<CchildDialog,CparentPage>(IDD_DIALOG_child,dlg,this);
dlg->GetDlgItem(IDC_EDIT_1)->SetWindowText("");
dlg->m_temp_window.EnableWindow(FALSE);//enable or disable controls.
dlg->UpdateData(false);//for to be done enable of disable or else.
dlg->do_exit=false;
dlg->do_cancel=false;
while(dlg->do_exit==false)
{
peek_and_pump();//wait for dlg->do_exit set true
}
if( dlg->do_cancel==false )
{
CString str1;
dlg->GetDlgItem(IDC_EDIT_1)->GetWindowText(str1);
//or other member variale of CchildDialog
//after finish all work with dlg then destroy its.
}
dlg->DestroyWindow();
}
void CchildDialog::OnBnClickedOk()
{
UpdateData();
OnOK();
do_exit=true;
do_cancel=false;
}
void CchildDialog::OnBnClickedCancel()
{
OnCancel();
do_exit=true;
do_cancel=true;
}

Get pressed keys in J2ME with GameCanvas

I would like to get whether (for example) the 3 key is pressed (KEY_NUM3).
I have tried getKeyStates but it only detects the game action keys.
How could I get the states of non-game action keys?
(I have overridden the keyPressed and keyReleased functions of Canvas and storing the key states in an array (I'm using a Vector for storing but I think could store them in an array too, if that's the problem), but this does not seem to be very nice)
in your keypressed use the keyCode passed in like so
protected void keyPressed(int keyCode)
{
//try catch getGameAction as can legally throw an exception
int gameAction = getGameAction(keyCode);
switch(gameAction)
{
case UP:
break;
case DOWN:
break;
case LEFT:
break;
}
switch(keyCode)
{
case KEY_NUM1:
break;
case KEY_NUM2:
break;
case KEY_NUM3;
break;
}
}
I suppose that can be
something like the code below
int key=getKeyStates();
// i mean keyStates();
if((key&down_pressed)!=0)
{
//do movements
}
but can be
if((key & Canvas.key_num3)!=0)
{
//do something
}
//you can set the super() to true in the constructor

Resources