How to create a MFC CSliderCtrl? - c++

I created a new MFC project with MS VS 2010 using their wizard (I chose single document if it matters). Then, I created a dialog box and from the toolbox I dragged a new slider. Using VS's wizard (right click on dialog-->add class) I created a class for my dialog called MyDialog. Next, I used VS's wizard to add a variable to to slider.
So now, in my MyDialog class I have a CSliderCtrl and I can't get it to work.
I tried to use SetRange() and\or SetPos() in OnInitDialog() but they crash to program and throws an exception.
If I create a new CSliderCtrl in OnInitDialog() and set it's range with SetRange() like so, it does works.
BOOL MyDialog::OnInitDialog()
{
CSliderCtrl *TrackBar = new CSliderCtrl;
TrackBar->Create(WS_CHILD | WS_VISIBLE,CRect(20, 20, 60, 280),this, IDC_SLIDER1);
int min,max;
TrackBar->GetRange(min,max);
TrackBar->SetPos(10);
return TRUE;
}
But this doesn't work:
BOOL MyDialog::OnInitDialog()
{
m_mySlider.SetRange(1,100); //sending true\false doesn't matter
return TRUE;
}
Can anyone help me please?

From the code you shown, you missed this important line,
CDialogEx::OnInitDialog();
You should add SetRange and SetPos calls after the above line.

Related

How to manually show CMFCToolBarComboBoxButton sub-menu?

Standard behaviour for CMFCToolBarComboBoxButton is to have a clickable button plus a drop-down arrow for displaying a submenu. I want to show the submenu independently of where the click was made. How can I do it?
My code to create the button is, more or less, the following (it has been extracted from a larger project, so I apologize for any missing not-too-important piece of code):
// In class declaration:
CMenu m_menu;
CMFCToolBar m_toolbar;
// Where toolbar initialization takes place:
m_menu.CreateMenu();
// ... populate menu
// ID_BUTTON is the ID in the resource file for the toolbar button, 0 is the index for the button icon
CMFCToolBarMenuButton button(ID_BUTTON, m_menu.GetSafeHmenu(), 0);
m_toolbar.ReplaceButton(ID_BUTTON, button);
I've been looking around for awhile and cannot find a related answer.
The solution happened to be very straightforward, just call the OnClick function of the CMFCToolBarComboBoxButton button from its associated ON_COMMAND.
// ... message map
ON_COMMAND(ID_BUTTON, OnToolbarMenuButtonClicked)
// ...
void MyWnd::OnToolbarMenuButtonClicked()
{
const int index = m_toolbar.CommandToIndex(ID_BUTTON);
auto button = (CMFCToolBarComboBoxButton*)m_toolbar.GetButton(index);
button->OnClick(NULL, TRUE);
}
This behaviour is not documented and, contrary to what common sense told me, it doesn't create an infinite recursive call. It seems that the "main" button is still controlled by CMFCToolBarButton, while just the "arrow-button" is controlled by the CMFCToolBarComboBoxButton.
PS: obviously, and out of the scope of the question, the OnToolbarMenuButtonClicked can be used for a very different purpose, such as the default action while the sub-menu contains other less-frequent options.

Where to initialize a rich edit control on another dialog?

I have an MFC dialog based application that has 2 Dialogs: Main Dialog CMyDlgand Second dialog CMyDlg2.
On the main Dialog I add a Button "Go dialog 2". So I added a handler for the button so that when clicked it pops up the second dialog. Everything works fine But on the second Dialog I have added a Rich Edit Control from toolbox. I Added for it a variable. I also added a class for the second dialog.
Now If I run the Application I get the dialog one and if I pressed "Go to dialog 2" I got what I want. But I need at some point to change the font of the rich edit control but my program crashes.
So I overrided OnInitDialog and inside it do some changes to the control but program crashes. After debugging I found that the handle of rich edit is null?!
So how and where can I change the color or do some initializations to the control?
(I called AfxInitRichEdit2() in OnInitInstance())
BOOL CMyDlg2::OnInitDialog() {
m_richEdit.SetWindowText("Hello there!"); // program crashes because the handle m_richEdit is null.
return TRUE;
}
And this is the handler of button that creates the Dialog2 and that contains the rich edit control:
void CMyDlg::OnBnClickedButton1(){
CMyDlg2 theDlg;
theDlg.DoModal();
// TODO: Add your control notification handler code here
}
If I create the rich edit control programmatically then everything works fine because I create it at OnInitDialog and then it works fine but I need the one that is I added using the wizard toolbox.
*** The thing is that if I write:
m_richEdit.SetWindowText(""); // program crashes but if I wirte:
GetDlgItem(IDC_RICHEDIT221).SetWindowText(""); it works fine?
You probably have the following code inserted by wizard:
void DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_RICHEDIT22, m_richEdit);
}
This tells the dialog to associate m_richEdit with the dialog control IDC_RICHEDIT22. But this association is not performed until the base class method CDialog::OnInitDialog(); is called.
BOOL CMyDlg2::OnInitDialog()
{
//this line should work:
GetDlgItem(IDC_RICHEDIT22)->SetWindowText("Hello");
//this line won't work:
//m_richEdit.SetWindowText("Hello there!"); <- richedit's handle is NULL
//this line will subclass m_richEdit
//plus run other initialization
CDialog::OnInitDialog();
//m_richEdit is ready
m_richEdit.SetWindowText("Hello there!");
return TRUE;
}
It's recommended to put CDialog::OnInitDialog() int the first line, to make sure the initialization is done.
GetDlgItem works because the control IDC_RICHEDIT22 exists in the dialog template and you have a valid dialog handle. You are basically making a simple call based on WinAPI's GetDlgItem:
HWND hedit = ::GetDlgItem(m_hWnd, IDC_RICHEDIT22);
::SetWindowText(hedit, "Hello world");
There is no additional initialization needed.
But m_richEdit is just a C++ object, declared as CRichEditCtrl m_richEdit; The constructor for this C++ class doesn't do much besides setting m_hWnd to NULL.
Once it's associated with a valid window handle, we can begin using its windows methods such as CRichEdit::SetWindowText

cmfcpropertygridctrl in dialog can't be edited

I create a dialog derived from CDialogEx, then add a CMFCPropertyGridCtrl on it, generate a control value of m_wndPropList binding to the CMFCPropertyGridCtrl, in OnInitDialog, I add the initial code:
BOOL CPropDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
InitPropList(); // here I add the initial function
return TRUE;
}
the codes in InitPropList() are just copy from the example code, generated by VS2015 when creating a MFC project with visual studio style.
when I have done all the work, the property ctrl display well, but it can't be edited, and doesn't respons to the mouse. please kindly help me, thanks!

QSystemTrayIcon handle left and right click separately?

I have a class called StatusIcon that extends QSystemTrayIcon. I want to set it up so right click opens the context menu and left click opens a window.
Currently the default behaviour seems to be both left and right click open the context menu.
I need to find a way to block the left click and run my own code instead.
From the documentation it looks like this could be achieved using eventFilter I have setup an eventFilter method on StatusIcon with a qdebug in it. This doesn't get called with a right or left click.
I installed it using a line of code like:
this->installEventFilter(this)
I'm wondering if its not working as its already overriding the virtual method as I've got QSystemTrayIcon as the super class.
Does anyone know why eventFilter is not being called?
Could anyone think of a way to achieve this functionality?
You don't need eventFilter. For left click:
//somewhere in constructor
connect(tray,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(showHide(QSystemTrayIcon::ActivationReason)));
//...
void MainWindow::showHide(QSystemTrayIcon::ActivationReason r)
{
if (r == QSystemTrayIcon::Trigger)
{
if (!this->isVisible()) {
this->show();
} else {
this->hide();
}
}
}
For menu, just use setContextMenu():
QMenu *menu = new QMenu(this);
//for example
menu->addAction(showHideAct);
menu->addAction(optionAct);
menu->addAction(infoAct);
menu->addSeparator();
menu->addAction(quitAct);
tray = new QSystemTrayIcon();
tray->setIcon(QIcon("://data/tray.png"));
tray->setContextMenu(menu);//important method for you
tray->show();

Sharing variable among class instances

class MyApp : public CWinApp {
afx_msg OnPrefrences();
};
OnPrefrences() get called when user selects tools->Preference from the menubar.
Now in one dialog(Say DlgX) there is one button, on clicking this I need to open the Preference dialog which has in fact many panes, but here I need to open the Preference dialog by selecting one the these pane as active. Also in that particular pane I need to hide some of the controls only when It gets open through this the dialog not through menu.
So I have created one variable(Say m_varX) in MainFrm class.
void DlgX::OnButtonXClick()
{
CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
if(pFrame)
{
pFrame->m_varX = TRUE;
((CMyApp*)(AfxGetApp()))->OnPrefrences();
pFrame->m_varX = FALSE;
}
}
And in button handler of DlgX I have made this m_varX TRUE and call the OnPreference() and after closing of this preference dialog I have made m_varX FALSE.
All this is working fine... But the problem is that things gets clutter in mainFrm. Also the project I am working on is legacy one so I cant make much changes.
Is there any patter available for handling such case?
Thanks
You could solve this with a custom dialog (if you don't have it already)
When you show the dialog from the main menu i.e. onPreferences() you fill and show all 'panes'. you would have to do a custom dialog where the ctor takes some arguments.
E.g.
enum { all, part };
void MainFrame::OnPreferences()
{
CMyPreferences dlg( GetDocument(), all );
dlg.DoModal();
}
but when you call it from within a dialog you only fill in the parts you need.
void YourDialog::OnPreferences()
{
CMyPreferences dlg( GetDocument(), part );
dlg.doModal();
}
The argument could be something more sophisticated for more fine tuned configuration of what to show/allow to edit.
I think for that special case, even if sometimes is no more considered a pattern, the singleton pattern would work for you.