i want prevent double clicked event at tree control in MFC? - mfc

i have implemented multi selection when LButtonDown from tree control in MFC
but when i do fast click repeatedly Mouse LButtonDown then a problem arises.
i thinks this problem is occoured by double clicked event when i clicked fast
repeadtly.
i want to acquired click event only except double clickevent.
importance is must be solved this problem in only LBUTTONDOWN event and LButtonClick event.
please help me. ~
my english writing is so badddest. sorry.
below is my source's part.
void CFileTreeCtrl::OnLButtonDown(UINT nFlags , CPoint point)
{
//LRESULT *pResult = 0;
GetCursorPos(&point);
::ScreenToClient(this->m_hWnd, &point);
HTREEITEM hItem = this->HitTest(point, &nFlags);
// if items is exist and event is occured
if (hItem != NULL && (nFlags & TVHT_ONITEMSTATEICON) != 0)
{
// if items is checked
if (this->GetCheck(hItem))
{
UnCheckChildItems(hItem);
}
// items is not checked
else
{
CheckChildItems(hItem);
}
}
CDragDropTreeCtrl::OnLButtonDown(nFlags, point);
}
//=========================================================
// checked all child items
//=========================================================
void CFileTreeCtrl::CheckChildItems(HTREEITEM hItem)
{
HTREEITEM hChildItem = this->GetChildItem(hItem);
while (hChildItem != NULL)
{
this->SetCheck(hChildItem, TRUE);
if (this->ItemHasChildren(hChildItem))
{
CheckChildItems(hChildItem);
}
hChildItem = this->GetNextItem(hChildItem, TVGN_NEXT);
}
}
//=========================================================
// Uncheck all child items.
//=========================================================
void CFileTreeCtrl::UnCheckChildItems(HTREEITEM hItem)
{
HTREEITEM hChildItem = this->GetChildItem(hItem);
while (hChildItem != NULL)
{
this->SetCheck(hChildItem, FALSE);
if (this->ItemHasChildren(hChildItem))
{
UnCheckChildItems(hChildItem);
}
hChildItem = this->GetNextItem(hChildItem, TVGN_NEXT);
}
}

Related

How to create a CDockablePane in a CFrameWnd with C++ in MFC

At first I called the Create method of the CFrameWnd within another class.
Then I continued with the Create method of CDockablePane with the FrameWnd as the pParentWnd parameter.
The second Create was not successful, an assertion occured in the following code:
void CMFCDragFrameImpl::Init(CWnd* pDraggedWnd)
{
ASSERT_VALID(pDraggedWnd);
m_pDraggedWnd = pDraggedWnd;
CWnd* pDockSite = NULL;
if (m_pDraggedWnd->IsKindOf(RUNTIME_CLASS(CPaneFrameWnd)))
{
CPaneFrameWnd* pMiniFrame = DYNAMIC_DOWNCAST(CPaneFrameWnd, m_pDraggedWnd);
pDockSite = pMiniFrame->GetParent();
}
else if (m_pDraggedWnd->IsKindOf(RUNTIME_CLASS(CPane)))
{
CPane* pBar = DYNAMIC_DOWNCAST(CPane, m_pDraggedWnd);
ASSERT_VALID(pBar);
CPaneFrameWnd* pParentMiniFrame = pBar->GetParentMiniFrame();
if (pParentMiniFrame != NULL)
{
pDockSite = pParentMiniFrame->GetParent();
}
else
{
pDockSite = pBar->GetDockSiteFrameWnd();
}
}
m_pDockManager = afxGlobalUtils.GetDockingManager(pDockSite);
if (afxGlobalUtils.m_bDialogApp)
{
return;
}
ENSURE(m_pDockManager != NULL); <-----------------------
}
Somehow a docking manager seems to be missing. Is it possible that CFrameWnd is not suitable for CDockablePane? Or the docking manager needs to be initialized?
Thanks for your help (code snippets are welcome)!
To add a dockable pane to your project, the first step is to derive a new class from CDockablePane and you must add two message handlers for OnCreate and OnSize, and add a member child window as the main content. Your simple CTreePane class should look like this:
class CTreePane : public CDockablePane
{
DECLARE_MESSAGE_MAP()
DECLARE_DYNAMIC(CTreePane)
protected:
afx_msg int OnCreate(LPCREATESTRUCT lp);
afx_msg void OnSize(UINT nType,int cx,int cy);
private:
CTreeCtrl m_wndTree ;
};
int CTreePane::OnCreate(LPCREATESTRUCT lp)
{
if(CDockablePane::OnCreate(lp)==-1)
return -1;
DWORD style = TVS_HASLINES|TVS_HASBUTTONS|TVS_LINESATROOT|
WS_CHILD|WS_VISIBLE|TVS_SHOWSELALWAYS | TVS_FULLROWSELECT;
CRect dump(0,0,0,0) ;
if(!m_wndTree.Create(style,dump,this,IDC_TREECTRL))
return -1;
return 0;
}
In the OnSize handler, you should size your control to fill the entire dockable pane client area.
void CTreePane::OnSize(UINT nType,int cx,int cy)
{
CDockablePane::OnSize(nType,cx,cy);
m_wndTree.SetWindowPos(NULL,0,0,cx,cy, SWP_NOACTIVATE|SWP_NOZORDER);
}
To support a dockable pane in your frame, you must first derive from the Ex family of frames (CFrameWndEx, CMDIFrameWndEx, ..) and in the OnCreate handler, you should initialize the docking manager by setting the allowable docking area, general properties, smart docking mode, …etc.
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
...
CDockingManager::SetDockingMode(DT_SMART);
EnableAutoHidePanes(CBRS_ALIGN_ANY);
...
}void CMainFrame::OnTreePane()
{
if(m_treePane && m_treePane->GetSafeHwnd())
{
m_treePane->ShowPane(TRUE,FALSE,TRUE);
return ;
}
m_treePane = new CTreePane;
UINT style = WS_CHILD | CBRS_RIGHT |CBRS_FLOAT_MULTI;
CString strTitle = _T("Tree Pane");
if (!m_treePane->Create(strTitle, this,
CRect(0, 0, 200, 400),TRUE,IDC_TREE_PANE, style))
{
delete m_treePane;
m_treePane = NULL ;
return ;
}
m_treePane->EnableDocking(CBRS_ALIGN_ANY);
DockPane((CBasePane*)m_treePane,AFX_IDW_DOCKBAR_LEFT);
m_treePane->ShowPane(TRUE,FALSE,TRUE);
RecalcLayout();
}

Qt QColorDialog - Escape Key not "eaten" (i.e. not remove from the event queue)

In my application, I have a QTableWidget with one column where the user may click to select a color. It work correctly with the following restriction: when the user type the Escape Key, the dialog is cancelled and close as expected, but the key event remains in the queue. This lead to a second effect of this key event, when the dialog has been closed, as if the user pressed the key twice.
Here is the whole code:
void CChildrenConfigScreen::actionCellClicked(int row, int col)
{
// ui->config_children_table->selectRow(row);
switch(col) {
case eColChildColor: {
CBiStateButton* cbox = reinterpret_cast<CBiStateButton*>(ui->config_children_table->cellWidget(row, 0));
assert( cbox != nullptr );
if( cbox->state() != Qt::Unchecked ) {
QTableWidgetItem* cell = ui->config_children_table->item(row, col);
cell->setSelected(false);
// =======
QColorDialog dialog(this);
dialog.setCurrentColor(cell->background().color());
dialog.exec();
if( dialog.result() == QDialog::Accepted ) {
cell->setBackground(QBrush(dialog.currentColor()));
} else {
// drop escape key event ???
}
// =======
}
}
break;
}
}
So, my questions:
Is it the normal behavior? Or a bug in Qt?
Am I doing something wrong?
If yes, what?
If not, what can I do to "eat" this event? (preferably without the hassle of creating a QColorDialog daughter class)
Here is the solution I implemented. Not really beautiful but the best I was able to do so far and works as required. The definition is a bit verbose but the usage is really convenient.
First, a stack based object (Android and MacOS not yet implemented, only Windows):
// ==============================
// Used to disable the Escape key
class CKeyEventFilter {
public:
typedef char KeyType;
typedef std::function<void()> Functor;
private:
class CFilter: public QAbstractNativeEventFilter
{
public:
private:
KeyType mKey;
Functor mAction;
public:
explicit CFilter(KeyType key, Functor action)
: mKey(key)
, mAction(action)
{
}
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override
{
bool stop_it = false;
#if defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)
if (eventType == "xcb_generic_event_t") {
xcb_generic_event_t* event = reinterpret_cast<xcb_generic_event_t *>(message);
assert(event != nullptr);
// ...
}
#elif defined(Q_OS_MACOS)
if (eventType == "mac_generic_NSEvent" {
MSG * event = reinterpret_cast<NSEvent*>(message);
assert(event != nullptr);
// ...
}
#elif defined(Q_OS_WINDOWS)
if (eventType == "windows_generic_MSG" || eventType == "windows_dispatcher_MSG") {
MSG* event = reinterpret_cast<MSG*>(message);
assert(event != nullptr);
if(event->message == WM_KEYDOWN || event->message == WM_KEYUP ) {
if( event->wParam == mKey ) {
// keep stop_it to false for the key being processed
// but tells the 'next client' that he doesn't need
// to process it a second time.
mAction();
}
}
}
#else
#error "Yet unsupported OS"
#endif
return stop_it;
}
};
CFilter mFilter;
public:
explicit CKeyEventFilter(KeyType key, Functor action)
: mFilter(key, action)
{
qApp->installNativeEventFilter(&mFilter);
}
virtual ~CKeyEventFilter()
{
qApp->removeNativeEventFilter(&mFilter);
}
};
Usage:
{
// Workaround with this stack based object (0x1B = 27 = ascii code for Esc char)
CKeyEventFilter filter(0x1B, []() { CMainWindow::win()->setSkipEscape(); } );
// Example of purpose: if dialog is left with the Escape Key,
// CMainWindow::setSkipEscape() in the lambda above will be called
QTableWidgetItem* cell = ui->config_children_table->item(row, col);
cell->setSelected(false);
QColorDialog dialog(this);
dialog.setCurrentColor(cell->background().color());
dialog.exec();
if( dialog.result() == QDialog::Accepted ) {
cell->setBackground(QBrush(dialog.currentColor()));
}
}
Skip the Esc key where it was in fact already processed (in this example, in the QColorDialog above, but might be a QMessageBox or any other dialog):
void CMainWindow::popScreen()
{
// mSkipEscape is initialized to false in CMainWindow's constructor
// and set by CMainWindow::setSkipEscape() in the lambda above.
if( mSkipEscape ) {
mSkipEscape = false;
} else {
if( ! mScreenStack.empty()) {
EScreens screen = mScreenStack.top();
mScreenStack.pop();
this->goScreen(screen);
}
}
}
I hope this will be useful to some people.

Spin Control GetPos() value is delayed

I have an edit control buddied with a spin control with the initial position set to 0. When the up arrow is clicked the edit box goes from 0 to 1, which is fine. But when I use GetPos() the MyValue is 0. When the spin control is incremented again from 1 to 2, the MyValue becomes 1. When down arrow is pressed the edit box goes from 2 to 1, but the value becomes 2. It seems that the MyValue is always one action behind the spin control.
BOOL CAlphaDlg::OnInitDialog()
{
// default code left out to keep it short ...
// TODO: Add extra initialization here
// set range and initial position
mSpinControl.SetRange(0, 3600); // range
mSpinControl.SetPos(0); // inital position
MyValue = mSpinControl.GetPos();
// display initial value in buddy editcontrol
mEditControlDisplay.Format("%d", MyValue);
UpdateData(false);
return TRUE;
}
void CAlphaDlg::OnDeltaposSpin1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMUPDOWN pNMUpDown = reinterpret_cast<LPNMUPDOWN>(pNMHDR);
// TODO: Add your control notification handler code here
UpdateData(true);
int MyValue= mSpinControl.GetPos();
std::cout << MyValue << std::endl;
*pResult = 0;
}
I have tried getting the value from the editcontrol but the value is exhibiting the same behavior. How do I get the value of the GetPos() to match what is showing in the edit control?
Thank you in advance.
edit: Here is the full code
// AlphaDlg.cpp : implementation file
//
#include "stdafx.h"
#include "Alpha.h"
#include "AlphaDlg.h"
#include "afxdialogex.h"
#include <iostream>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialogEx
{
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() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CAlphaDlg dialog
CAlphaDlg::CAlphaDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_ALPHA_DIALOG, pParent)
, mEditControlDisplay(_T(""))
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CAlphaDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT1, mEditControlDisplay);
DDX_Control(pDX, IDC_SPIN1, mSpinControl);
}
BEGIN_MESSAGE_MAP(CAlphaDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN1, &CAlphaDlg::OnDeltaposSpin1)
END_MESSAGE_MAP()
// CAlphaDlg message handlers
BOOL CAlphaDlg::OnInitDialog()
{
CDialogEx::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)
{
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
mSpinControl.SetRange(0, 10);
mSpinControl.SetPos(0);
int MyValue = mSpinControl.GetPos();
mEditControlDisplay.Format("%d", MyValue);
UpdateData(false);
return TRUE; // return TRUE unless you set the focus to a control
}
void CAlphaDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::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 CAlphaDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<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;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CAlphaDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CAlphaDlg::OnDeltaposSpin1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMUPDOWN pNMUpDown = reinterpret_cast<LPNMUPDOWN>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
UpdateData(true);
int MyValue = mSpinControl.GetPos();
std::cout << mEditControlDisplay << std::endl;
std::cout << MyValue << std::endl;
}
Firstly, consider mapping your edit box to a int and then you do not need to cast to a string. And the default value is 0 to begin with so the spinner will be OK. You can also switch off the auto buddy.
In the deltapos handler you could do this:
void CMFCApplication1Dlg::OnDeltaposSpin1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMUPDOWN pNMUpDown = reinterpret_cast<LPNMUPDOWN>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
SetDlgItemInt(IDC_EDIT1, pNMUpDown->iPos);
UpdateData(TRUE);
CString a;
a.Format(_T("%d"), iNumberValue);
AfxMessageBox(a);
}
For me the results in the popup message and the edit control are the same.
Update
You can workout what the new value would be by looking at the structure:
void CMFCApplication1Dlg::OnDeltaposSpin1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMUPDOWN pNMUpDown = reinterpret_cast<LPNMUPDOWN>(pNMHDR);
int iCurrentPos = pNMUpDown->iPos;
if (pNMUpDown->iDelta > 0)
iCurrentPos++;
else
iCurrentPos--;
CString strNewValue;
strNewValue.Format(_T("%d"), iCurrentPos);
AfxMessageBox(strNewValue);
*pResult = 0;
}
For Consideration
You might want to give some thought to CSpinButtonCtrl::SetAccel which sets the acceleration for a spin button control.
In your case I don't think it is going to matter because your range is only 10
units. But if you had a larger range then it is possible that it would increment by more than one unit. It is just something to keep in mind.
According to this reference for UDN_DELTAPOS it says:
The iDelta member of the structure is a signed integer that contains the proposed change in position.
So you could improve the code and increment/decrement based on the iDelta value instead of 1. This would factor in for acceleration. So:
int iCurrentPos = pNMUpDown->iPos + pNMUpDown->iDelta;

Print button in PrintPreview dialog doesn't work

After pressing the print button in PrintPreview dialog, nothing comes out.
I think that Print dialog should come out after pressing the print button in PrintPreview dialog, but it doesn't.
It just goes back to the main screen.
P.S.
It's not the functions which were already made when I started the project.
I added this functions manually, because I used another view which is derived from CScrollView, and the original view (CMyView) isn't used.
Here's the code:
void SignalView::OnFilePrintPreview()
{
PRINTDLG printDlg = { 0 };
printDlg.lStructSize = sizeof(PRINTDLG);
if (AfxGetApp()->GetPrinterDeviceDefaults(&printDlg))
{
if (printDlg.hDevMode)
{
DEVMODE *dm = (DEVMODE*)::GlobalLock(printDlg.hDevMode);
if (dm)
{
dm->dmFields |= DM_ORIENTATION;
dm->dmOrientation = DMORIENT_LANDSCAPE;
::GlobalUnlock(printDlg.hDevMode);
}
}
}
CScrollView::OnFilePrintPreview();
}
BOOL SignalView::OnPreparePrinting(CPrintInfo* pInfo)
{
__try {
pInfo->SetMinPage(1);
pInfo->SetMaxPage(1);
// pInfo->m_bPreview = TRUE;
return DoPreparePrinting(pInfo);
}__except (GetExceptionCode()==EXCEPTION_ACCESS_VIOLATION){
AfxMessageBox(_T("Printer Error!"));
return FALSE; // Fail!
}
}
void SignalView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)
{
}
void SignalView::OnEndPrinting(CDC* pDC, CPrintInfo* pInfo)
{
}
Is there something that I missed?

How to change the state of button to clicked in cocos2d-x

I am pretty new to cocos2d-x.I have created a button and i wanted to change the state of the button when i tap the button . i am having trouble changing the state from play to pause similar to a music player.Below is the code.
void Gallery::buttonUI(Size visibleSize,Vec2 origin)
{
button = Button::create("play.png");
//button->loadTextures("pause.png","play.png","pause.png");
button->setPosition(Point((visibleSize.width/2)+origin.x,(visibleSize.height/2)+origin.y-80));
button->setContentSize(Size(100.0f, button->getVirtualRendererSize().height));
button->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type){
switch (type)
{
case Widget::TouchEventType::BEGAN:
break;
case Widget::TouchEventType::ENDED:
CCLOG("Characters: %c %c", 'a', 65);
if (!flag)
Gallery::pauseSong();
else
Gallery::resumeSong();
break;
default:
break;
}
});
this->addChild(button);
}
void Gallery::playSong()
{
CocosDenshion::SimpleAudioEngine::getInstance()->preloadBackgroundMusic("1.mp3");
CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic("1.mp3");
flag = false;
}
void Gallery::pauseSong()
{
CocosDenshion::SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
flag = true;
}
void Gallery::resumeSong()
{
CocosDenshion::SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
flag = false;
}
I don’t know of such methods for the ui::Button. But I don’t see the use of specific ui::Button items (capinsets, different methods for different touch events etc.) in your method also.
So, I think the MenuItemImage is better in your case:
bool flag = true;
MenuItemImage *button = MenuItemImage::create("play.png", "play_pressed.png", CC_CALLBACK_0(Gallery::playSong, this));
button->setPosition(Vec2((visibleSize.width/2)+origin.x,(visibleSize.height/2)+origin.y-80)); // better is use Vec2, Point can be ambiguous
Menu* menu = Menu::create(button, NULL); // add created button on Menu
menu ->setPosition(0,0);
this->addChild(menu);
And then set the images in handler pressing:
void Gallery::playSong()
{
if(flag)
{
// preload better move to AppDelegate.cpp
// CocosDenshion::SimpleAudioEngine::getInstance()->preloadBackgroundMusic("1.mp3");
flag = false;
CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic("1.mp3");
button->setNormalImage(Sprite::create(“pause.png”));
button->setSelectedImage(Sprite::create(“pause_pressed.png”)); // if you use selected image
}
else
{
flag = true;
CocosDenshion::SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
button->setNormalImage(Sprite::create(“play.png”));
button->setSelectedImage(Sprite::create(“play_pressed.png”));
}
}
In cocos 3.x use property: setHighlighted(bool)
Example:
When press a key: button->setHighlighted(true);
When release the key:
button->setHighlighted(false);