Board index » cppbuilder » Setting focus on next active control...
Eduardo Jauch
![]() CBuilder Developer |
Eduardo Jauch
![]() CBuilder Developer |
Setting focus on next active control...2004-07-10 06:58:20 AM cppbuilder1 Hello to all... I'd like to set focus on the next enabled control in an modal when user press a key like an 'enter' in one control... These controls are commonly edit boxes... I try to use TWinControl::SelectNext, but with no success... Compiler told that it's not accessible... Any ideas? Thanks for the help... Eduardo Jauch. |
JD
![]() CBuilder Developer |
2004-07-10 10:07:44 AM
Re:Setting focus on next active control...
Eduardo Jauch < XXXX@XXXXX.COM >wrote:
QuoteI'd like to set focus on the next enabled control in an ~ JD |
Eduardo Jauch
![]() CBuilder Developer |
2004-07-10 10:27:05 AM
Re:Setting focus on next active control...
JD wrote:
QuoteIs this a form that you have created? If not, what is the From this form, i call another (that i put after in my project with the comand 'new form') with this line of code, when the user press a button: MyForm->ShowModal(); In this form (MyForm), i have some controls (TEdit and TCheckBox) What i want is move the focus from one TEdit or TCheckBox to the next in the Tab Order when the user press enter in one of then... If i couldn't give you your answer forgive me, but i really don't understand what you mean with source of window... I'me new to windows program... Many of the concepts are confuse to me many times... And i'm still trying to develop my skills... Thanks for the reply. Eduardo Jauch. {smallsort} |
Bruce Salzman
![]() CBuilder Developer |
2004-07-10 10:49:16 AM
Re:Setting focus on next active control...QuoteI'd like to set focus on the next enabled control in an modal when if (Key == VK_ENTER){ if (ActiveControl == OKButton) ModalResult = mrOk; else PostMessage(this->Handle, WM_NEXTDLGCTL); // allow enter key to move to next control } Regards, Bruce |
JD
![]() CBuilder Developer |
2004-07-10 04:58:30 PM
Re:Setting focus on next active control...
Eduardo Jauch < XXXX@XXXXX.COM >wrote:
Quote[...] From this form, i call another [...] key. The other is to add a form wide event that does basically the same but is implemented a little differently. To use the application wide method, you declare the function in the main form's header and assign the function to the global TApplication::OnMessage event: class TMainForm : public TForm { __published: private: void __fastcall AppOnMessage( TMsg &Msg, bool &Handled ); public: __fastcall TMainForm(TComponent* Owner); }; //------------------------------------------------------------- __fastcall TMainForm::TMainForm(TComponent* Owner) : TForm(Owner) { Application->OnMessage = AppOnMessage; } //------------------------------------------------------------- void __fastcall TMainForm::AppOnMessage( TMsg &Msg, bool &Handled ) { if( Msg.message == WM_KEYDOWN || Msg.message == WM_KEYUP ) { if( Msg.wParam == VK_ENTER ) { if( Screen->ActiveForm == MyForm ) { if( you want to tab to the next control ) { // see below for more // change the key to VK_TAB Msg.wParam = VK_TAB; } } } } } //------------------------------------------------------------- If you have a control in the form that makes use of the enter key, you'll need to use the global Screen->ActiveControl variable to know what control has focus. You can brute force the testing by checking against every control: if( Screen->ActiveControl == MyForm->Edit1 ) { } else if( Screen->ActiveControl == MyForm->Edit2 ) { } else if( Screen->ActiveControl == MyForm->CheckBox1 ) { } or you can do something like: TEdit* pEdit = dynamic_cast<TEdit*>( Screen->ActiveControl ); if( pEdit ) { // the active control is an edit } else { TGroupBox* pBox = dynamic_cast<TGroupBox*>( Screen->ActiveControl ); if( pBox ) { // the active control is a TGroupBox } else { // continue testing for the other classes } } or you can: if( Screen->ActiveControl->ClassNameIs("TEdit") ) { // the active control is a TEdit } The other choice that you have is to add an OnKeyDown event to the form as Bruce suggested. The actual code used to set focus to the next control can be one of many things and what Bruce posted is a valid method. However, he left out 2 very important details. The first is that for it to work as expected, you must set the form's KeyPreview property to true. The second is that if you don't replace the VK_ENTER value with something else, the system bell will *always* sound if the control doesn't accept returns. Just as with the Application wide method, you need to define the event in the header but this time it goes in the TMyForm class instead of the MainForm and again, you assign the event in the forms constructor: class TMyForm : public TForm { __published: void __fastcall FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift); private: public: __fastcall TMyForm(TComponent* Owner); }; //------------------------------------------------------------- __fastcall TMyForm::TMyForm(TComponent* Owner) : TForm(Owner) { KeyPreview = true; OnKeyDown = FormKeyDown; } //------------------------------------------------------------- void __fastcall TMyForm::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift) { if( Key == VK_ENTER ) { // use the same techniques as above to determine if // you want to tab to the next control but now you // can use the form's ActiveControl propert instead if( you want to change focus ) { Key = 0; Perform( WM_NEXTDLGCTL, 0, 0 ); } } } //------------------------------------------------------------- One type of control that can accept returns that I didn't include a sample of testing for is a TMemo: TMemo* pMemo = dynamic_cast<TMemo*>( ActiveControl ); if( pMemo ) { if( ! pMemo->WantReturns ) { Key = 0; Perform( WM_NEXTDLGCTL, 0, 0 ); } } Quote[...] but i really don't understand what you mean with source SHBrowseForFolder API. The reason is that the source of the window dictates what you have to do to accomplish what you want. Since you are creating the form yourself, you have easy access to the controls and their events. If not, it would be quite complicated. QuoteMany of the concepts are confuse to me many times ~ JD |
Eduardo Jauch
![]() CBuilder Developer |
2004-07-10 09:50:13 PM
Re:Setting focus on next active control...
Hello!
I founde some problem to implement the option that use de KeyPreview e OnKeyDown from MyForm... In this form i have 2 buttons... And when i hit the enter key, the form is closed like if i press the button OK (that in MyForm is put as Custon and with code of return mrNone)... The code tha i used for FormKeyDown is: if( Key == 13 ) { if (ActiveControl == TISPButtonOK) { ModalResult = mrOk; } else { Key = 0; Perform( WM_NEXTDLGCTL, 0, 0 ); } } If i have some mistake plese tell me... I try to use the code of both of you (JD and Bruce).. But anyway, if i put a breakpoint in first line, i figure that this procedure is never valled when i press the key enter... What is going on? There´s some setting that put this type of behavior to the window? How can i fix it? |
Eduardo Jauch
![]() CBuilder Developer |
2004-07-10 09:53:31 PM
Re:Setting focus on next active control...
Hello again!!
I discover that if i disabled the button OK, the code work fine... But i need this button... What i have to do? Eduardo Jauch. |
Eduardo Jauch
![]() CBuilder Developer |
2004-07-10 09:57:20 PM
Re:Setting focus on next active control...
Thank's Bruce!
Work's fine... But i dont understand this line: if (ActiveControl == OKButton) OKButton is what exactly? The name of the button OK? Eduardo Jauch. |
Eduardo Jauch
![]() CBuilder Developer |
2004-07-10 10:01:45 PM
Re:Setting focus on next active control...
Eduardo Jauch wrote:
QuoteHello again!! But i'm still don't understang why i have to do this... Becayse for me, the buttons are same... Only that in first time, i put the buttons mbOK and mbCancel and after i changed the results from mrOk and mrCancel to mrNone... Was some more action that i have to do? Like some other property that i have to change? Thanks! Eduardo Jauch. |
JD
![]() CBuilder Developer |
2004-07-11 03:09:49 AM
Re:Setting focus on next active control...
Eduardo Jauch < XXXX@XXXXX.COM >wrote:
Quote[...] i put the buttons mbOK and mbCancel and after i you were not checking the returned result. If you need to check if the user clicked OK or Cancel, then you would do something like: if( MyForm->ShowModal() == mrOK ) { // the user clicked the OK button } else { // the user clicked the Cancel button } but for that to work, you have to set the button's ModalResult property to mrOK and mrCancel or use the method in my other post. ~ JD |
JD
![]() CBuilder Developer |
2004-07-11 03:16:30 AM
Re:Setting focus on next active control...
Eduardo Jauch < XXXX@XXXXX.COM >wrote:
Quote[...] The code tha i used for FormKeyDown is: should be using the virtual key code ( VK_xx ) instead of the actual integer value. You also failed to check if the user pressed enter while the Cancel button had focus. ~ JD |
JD
![]() CBuilder Developer |
2004-07-11 03:56:30 AM
Re:Setting focus on next active control...
Eduardo Jauch < XXXX@XXXXX.COM >wrote:
QuoteI discover that if i disabled the button OK, the code work best for you. It still hasn't been established that you need the modal result but since your OnKeyDown event is setting the result, I'll assume that you want to use it. If that's correct, I would suggest that set the button's ModalResult's to mrOK and mrCancel and make sure that the Default property for each button is set to false. Then use the following: void __fastcall TMyForm::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift) { if( Key == VK_ENTER ) { if( ActiveControl != TISPButtonOK && ActiveControl != TISPButtonCancel ) { Key = 0; Perform( WM_NEXTDLGCTL, 0, 0 ); } } } Now to get the desired resilts, you need to set each control's TabStop property. If you don't want the control in the TabOrder, set TabStop to false. Next, set each control's (that has TabStop = true) TabOrder. Start with the control that you want to have focus when the form first opens and set it's TabOrder to 1 and set the next to 2 and so on. Finish by setting the form's ActiveControl property to the control that you want to have focus when the form first opens. You can do this in the IDE or by setting it in the form's constructor (same place I showed where to set the KeyPreview property): ActiveControl = Edit1; One final note: I'm not sure what will happen if the user closes the form by clicking the system close button or by using the system menu. If you find that it causes a problem for you, you will have to either remove the form's biSystem buttons or change your code. If you have to change your code, set the button results to mrNone and add OnClick events for both buttons, add an OnClose event for the form and use the OnKeyDown sample where you set the ModalResult if the button(s) was focused. You would also need to add a global bool flag: // --- in the MyForm header private: bool ResultFlag; //------------------------------------------------------------- __fastcall TMyForm::TMyForm(TComponent* Owner) : TForm(Owner) { ResultFlag = false; KeyPreview = true; OnKeyDown = FormKeyDown; } //------------------------------------------------------------- void __fastcall TMyForm::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift) { if( Key == VK_ENTER ) { if( ActiveControl == TISPButtonOK ) { ModalResult = mrOk; } else if( ActiveControl == TISPButtonCancel ) { ModalResult = mrCancel; } else { Key = 0; Perform( WM_NEXTDLGCTL, 0, 0 ); } } } //------------------------------------------------------------- void __fastcall TMyForm::OKBtnClick(TObject *Sender) { ModalResult = mrOk; } //------------------------------------------------------------- void __fastcall TMyForm::CancelBtnClick(TObject *Sender) { ModalResult = mrCancel; } //------------------------------------------------------------- void __fastcall TTIDEAtumFormulas::FormClose(TObject *Sender, TCloseAction &Action) { if( !ResultFlag ) ModalResult = mrCancel; } //------------------------------------------------------------- ~ JD |
Eduardo Jauch
![]() CBuilder Developer |
2004-07-11 04:16:05 AM
Re:Setting focus on next active control...
JD wrote:
QuoteEduardo Jauch < XXXX@XXXXX.COM >wrote: I think i need buy a good book of c++ to study more... I never upgrade completely from my old Turbo C do Borland C++... In this case i receve an error, because the compiler not recognize the VK_... I swap the VK_ for 13 only to make the code work... In what header file is located the VK_xx statments? Thanks for the help! I appreciated very much! |
Eduardo Jauch
![]() CBuilder Developer |
2004-07-11 04:24:50 AM
Re:Setting focus on next active control...
JD wrote:
Quote
the form... QuoteIf that's correct, I would suggest that set the button's Now work fine! Quote
|
Bruce Salzman
![]() CBuilder Developer |
2004-07-13 09:51:07 AM
Re:Setting focus on next active control...
Hi, Eduardo
QuoteWork's fine... happens when you press Enter in a dialog. OKButton is the pointer to your default button, eg. in the form's decalaration: TButton* OKButton; When the user presses enter when the OKButton is active, the form closes. FWIW, I've used this technique in the past for users who weren't familiar with Windows. It seemed natural that enter moves to the next field. But once they got used to the Windows interface (and using the tab key) this trick started to seem awkward and unexpected. So I've stopped using it (YMMV). Regards, Bruce |