How to determine which component has the program focus in C++Builder - c++builder

I am using C++Builder XE4 32bit VCL platform. I am writing for Windows OS.
I have a MainForm with a lot of components on it. When I press a keyboard arrow key and the Form's OnShortCut event is triggered, how do I determine which component has the program focus?
I have different actions which must be taken based on which component has the focus.
void __fastcall TMainForm::FormShortCut(TWMKey &Msg, bool &Handled)
{
//determine which component has the focus.
}

Use the global Screen->ActiveControl property:
Indicates which control currently has input focus on the screen.
Read ActiveControl to learn which windowed control object in the active form currently receives the input from the keyboard.
void __fastcall TMainForm::FormShortCut(TWMKey &Msg, bool &Handled)
{
TWinControl *ctrl = Screen->ActiveControl;
if (ctrl == Control1)
{
// do something...
}
else if (ctrl == Control2)
{
// do something else...
}
// and so on...
}
Or, you can use the Form's own ActiveControl property:
Specifies the control that has focus on the form.
Use ActiveControl to get or set the control that has focus on the form. Only one control can have focus at a given time in an application.
If the form does not have focus, ActiveControl is the control on the form that will receive focus when the form receives focus.
void __fastcall TMainForm::FormShortCut(TWMKey &Msg, bool &Handled)
{
TWinControl *ctrl = this->ActiveControl;
if (ctrl == Control1)
{
// do something...
}
else if (ctrl == Control2)
{
// do something else...
}
// and so on...
}

Related

WM_KEYDOWN in WndProc - doesn't trigger

I am trying to capture WM_KEYDOWN to process some keyboard events at the Form level. I know I can use KeyPreview=true and use the OnKeyDown event of TForm. However, I'd like to do it in the WndProc() to simplify event processing in a single function. The problem is, it doesn't fire in the WndProc(). Is there a particular reason why it doesn't? Aside from using BEGIN_MESSAGE_MAP to handle WM_KEYDOWN, is there another way?
void __fastcall TForm1::WndProc(TMessage &fMessage)
{
switch (fMessage.Msg)
{
default: break;
case WM_KEYDOWN: {
TWMKeyDown KDMsg = reinterpret_cast<TWMKeyDown&>(fMessage);
TShiftState KDSs = KeyDataToShiftState(KDMsg.KeyData);
if (KDMsg.CharCode == 'C' && KDSs.operator ==(TShiftState() << ssCtrl))
{
// Process CTRL+C key
fMessage.Result = 1;
return;
}
}
break;
}
TForm::WndProc(fMessage);
}
Keyboard (and mouse) messages are posted to the window that has input focus. If a TForm has a child control that has the focus, the messages will go directly to the child's WndProc, not the Form's WndProc.
That is where KeyPreview comes into play. When true, it tells child controls to forward their keyboard messages to their parent TForm for processing.
Otherwise, you can alternatively use the TApplication(Events)::OnMessage event to handle input messages before they are dispatched to their target windows.

Use TMonthCalendar for months and years only

My point is I want to keep the calendar always on the months view, like this:
Expected TMonthCalendar view:
So that when I click in a month, instead of showing the days of the month, it stays in this screen and call the event.
Prior to Vista, the underlying Win32 MonthCal control that TMonthCalendar wraps has no concept of views at all, so you can't do what you are asking for in XP and earlier, unless you find a 3rd party calendar that supports what you want on those Windows versions.
However, in Vista and later, the underlying MonthCal control is view-aware (but TMonthCalendar itself is not). You can manually send a MCM_SETCURRENTVIEW message to the TMonthCalendar's HWND to set its initial view to MCMV_YEAR, and subclass its WindowProc property to intercept CN_NOTIFY messages (the VCL's wrapper for WM_NOTIFY) looking for the MCN_VIEWCHANGE notification when the user changes the active view. You can't lock the control to a specific view, but you can react to when the user changes the active view from the Year view to the Month view, and then you can reset the calendar back to the Year view if needed.
For example:
class TMyForm : public TForm
{
__published:
TMonthCalendar *MonthCalendar1;
...
private:
TWndMethod PrevMonthCalWndProc;
void __fastcall MonthCalWndProc(TMessage &Message);
...
public:
__fastcall TMyForm(TComponent *Owner)
...
};
#include "MyForm.h"
#include <Commctrl.h>
#ifndef MCM_SETCURRENTVIEW
#define MCMV_MONTH 0
#define MCMV_YEAR 1
#define MCM_SETCURRENTVIEW (MCM_FIRST + 32)
#define MCN_VIEWCHANGE (MCN_FIRST - 4) // -750
typedef struct tagNMVIEWCHANGE
{
NMHDR nmhdr;
DWORD dwOldView;
DWORD dwNewView;
} NMVIEWCHANGE, *LPNMVIEWCHANGE;
#endif
__fastcall TMyForm(TComponent *Owner)
: TForm(Owner)
{
if (Win32MajorVersion >= 6)
{
SendMessage(MonthCalendar1->Handle, MCM_SETCURRENTVIEW, 0, MCMV_YEAR);
PrevMonthCalWndProc = MonthCalendar1->WindowProc;
MonthCalendar1->WindowProc = MonthCalWndProc;
}
}
void __fastcall TMyForm::MonthCalWndProc(TMessage &Message)
{
PrevMonthCalWndProc(Message);
if (Message.Msg == CN_NOTIFY)
{
if (reinterpret_cast<NMHDR*>(Message.LParam)->code == MCN_VIEWCHANGE)
{
LPNMVIEWCHANGE lpNMViewChange = static_cast<LPNMVIEWCHANGE>(Message.LParam);
if ((lpNMViewChange->dwOldView == MCMV_YEAR) && (lpNMViewChange->dwNewView == MCMV_MONTH))
{
// do something ...
SendMessage(MonthCalendar1->Handle, MCM_SETCURRENTVIEW, 0, MCMV_YEAR);
}
}
}
}
If you are using C++Builder 10.1 Berlin or later, look at the newer TCalendarView and TCalendarPicker components. They both have a DisplayMode property that you can set to TDisplayMode::dmYear for the current view, and an On(Calendar)ChangeView event to react to view changes by the user.

Two TListBoxes using the same TPopup menu?

I have one TListBox with 'movie' items and another one with 'snapshots'. I want to use one popup menu for both Listboxes. However, in the onClick event for a popups menuitem, how do I resolve which list box was used?
I tried this:
void __fastcall TMainForm::DeleteAll1Click(TObject *Sender)
{
TListBox* lb = dynamic_cast<TListBox*>(Sender);
if(lb == mMoviesLB)
{
...
where DeleteAll1 is a TMenuItem in the Popup menu. The lb is always NULL so there is something missing here..
The TPopupMenu::PopupComponent property tells you which UI control displayed the popup menu, eg:
void __fastcall TMainForm::DeleteAll1Click(TObject *Sender)
{
TListBox* lb = dynamic_cast<TListBox*>(PopupMenu1->PopupComponent);
...
}
If the TPopupMenu is displayed automatically (ie: right-clicking on a control when TPopupMenu::AutoPopup is true), the PopupComponent is populated automatically. However, if you call TPopupMenu::Popup() yourself, the PopupComponent will be NULL unless you assign it beforehand, eg:
PopupMenu1->PopupComponent = ListBox1;
PopupMenu1->Popup(X, Y);

Automatic Lock Form2 Positioning in C++ Builder

My application is using two forms. When I click a panel in main form, the Form2 should showing up. There're a few pixels distance between the Main Form and Form2.
Now what I need is when I move the Main Form to anywhere, then Form2 moves where ever Main Form goes. I mean I need Form2 to be lock on Main Form.
Have the MainForm override the virtual WndProc() method to reposition Form2 as needed relative to the MainForm's current position whenever a WM_WINDOWPOSCHANGING or WM_WINDOWPOSCHANGED message is received.
class TMainForm : public TForm
{
...
protected:
void __fastcall WndProc(TMessage &Message);
...
};
...
#include "Form2.h"
...
void __fastcall TMainForm::WndProc(TMessage &Message)
{
TForm::WndProc(Message);
switch (Message.Msg)
{
case WM_WINDOWPOSCHANGING:
case WM_WINDOWPOSCHANGED:
{
if ((Form2) && (Form2->Visible))
{
Form2->Left = ...; // such as this->Left
Form2->Top = ...; // such as this->Top + this->Height
}
break;
}
}
}

ActiveX in CPropertyPage can't be used by keyboard

in my sample project (c++ vs10) i placed an ActiveX control in an Dialog (used as PropertyPage). The Dialog is connected to a CPropertyPage derived class called CTestPage. If i open a PropertySheet with DoModal, where the CTestPage is added, the ActiveX control appears, but i cant handle it by keyboard. If i click the ActiveX control (e.g. Calendar Control 8.0) the control receives the click and works fine. But no keyboard stroke is handled by the control. I tested ten different ActiveX controls on my developer machine -> always the same behavior.
If i place the ActiveX control in a normal Dialog everything works fine.
Any hints what i do wrong?
Thanks a lot
heribert
PS. Yes, AfxEnableControlContainer is called in InitInstance.
A PropertyPage sends WM_GETDLGCODE to every control to check out, which keyboard input can be handled by the control.
All the ActiveX controls i have tested results with 0 as answer on the request! Cool, so no one will receive any keyboard input.
The ActiveX Control i will use is written by me in c#. The ActiveX layer is needed to offer the complex c# control to c++.
But the underlying complex c# control returns with a 0 on a WM_GETDLGCODE message, too.
So i subclassed the c# control like the following code and now it works fine!!
internal class SubclassedComplexControl : ComplexControl
{
[SecurityPermission(SecurityAction.LinkDemand,
Flags = SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref System.Windows.Forms.Message m)
{
const int WM_GETDLGCODE = 0x0087;
const int DLGC_WANTARROWS = 0x0001;
const int DLGC_WANTALLKEYS = 0x0004;
const int DLGC_WANTCHARS = 0x0080;
const int VK_ESCAPE = 0x1B;
const int VK_RETURN = 0x0D;
if (m.Msg == WM_GETDLGCODE)
{
if (m.WParam.ToInt32() == VK_RETURN || m.WParam.ToInt32() == VK_ESCAPE)
m.Result = (IntPtr) DLGC_WANTALLKEYS;
else
m.Result = (IntPtr)(DLGC_WANTARROWS | DLGC_WANTCHARS);
return;
}
base.WndProc(ref m);
}
}

Resources