Resumo
As aplicações baseadas no Windows exibem frequentemente caixas de diálogo de entrada de dados para solicitar informações dos utilizadores. Estas caixas de diálogo podem conter vários controlos de edição e dois botões de comando (push), marcados como OK e CANCEL. Um exemplo de uma caixa de diálogo de entrada de dados é aquele que solicita informações pessoais, tais como número de segurança social, morada, número de identificação (ID), data/hora, e assim por diante, dos utilizadores. Cada um destes itens é inserido num controlo de edição. Por predefinição, a tecla TAB é utilizada numa caixa de diálogo para deslocar o foco entre os controlos de edição. No entanto, como interface de utilizador comum, também se pode utilizar a tecla ENTER (RETURN) para mover-se entre os controlos de edição (por exemplo, depois de o utilizador introduzir uma informação, pressionar o ENTER move o foco para o campo seguinte). Existem algumas formas de permitir a utilização da tecla ENTER para mover-se entre os controlos de edição. Um método é fazer uso de WM_COMMAND e as mensagens de notificação que acompanham na caixa de diálogo para controlos e botões de edição. Outro método envolve subclassificar os controlos de edição. Um terceiro envolve a utilização do App Studio e do Assistente de Classe e a criação de uma nova função de membro da caixa de diálogo.
Mais Informações
Método I: (WM_COMMAND)
Este método baseia-se no seguinte comportamento das caixas de diálogo (Gestor de diálogo) e do manuseamento de foco no Windows.Se uma caixa de diálogo ou um dos seus controlos tiver atualmente o foco de entrada, premindo a tecla ENTER faz com que o Windows envie uma mensagem de WM_COMMAND com o parâmetro idItem (wParam) definido para o ID do botão de comando predefinido. Se a caixa de diálogo não tiver um botão de comando predefinido, então o parâmetro idItem é definido para IDOK por predefinição. Quando uma aplicação recebe a mensagem WM_COMMAND com idItem definida para o ID do botão de comando predefinido, o foco permanece com o controlo que tinha o foco antes da tecla ENTER ser premida. Call GetFocus() neste momento devolve o cabo do controlo que tinha o foco antes da tecla ENTER ser pressionada. A aplicação pode verificar esta pega de controlo e determinar se pertence a algum dos controlos de edição na caixa de diálogo. Se isso acontecer, o utilizador estava a introduzir dados num dos controlos de edição e, depois de o fazer, pressionou o ENTER. Neste ponto, a aplicação pode enviar a mensagem WM_NEXTDLGCTL para a caixa de diálogo para mover o foco para o controlo seguinte. No entanto, se o foco foi com um dos botões de comando (CANCEL ou OK), então o GetFocus () devolve um manípulo de controlo de botões, altura em que se pode descartar a caixa de diálogo. O pseudo código para esta lógica assemelha-se ao seguinte no procedimento da caixa de diálogo da aplicação:
case WM_COMMAND: if(wParam=IDOFDEFBUTTON || IDOK) { // User has hit the ENTER key. hwndTest = GetFocus() ; retVal = TesthWnd(hWndTest) ; //Where retVal is a boolean variable that indicates whether //the hwndTest is the handle of one of the edit controls. if(hwndTest) { //Focus is with an edit control, so do not close the dialog. //Move focus to the next control in the dialog. PostMessage(hDlg, WM_NEXTDLGCTL, 0, 0L) ; return TRUE ; } else { //Focus is with the default button, so close the dialog. EndDialog(hDlg, TRUE) ; return FALSE ; } } break ;
Método II
Este método envolve subclasse/superclassificação do controlo de edição na caixa de diálogo. Uma vez que os controlos de edição são subclassificados ou superclassificados, toda a entrada do teclado é enviada o procedimento subclasse/superclasse do controlo de edição que tem atualmente foco de entrada, independentemente de a caixa de diálogo ter ou não um botão de comando predefinido. A aplicação pode prender a chave para baixo (ou char) mensagens, procurar a tecla ENTER e fazer o processamento em conformidade. Segue-se um procedimento de subclasse de amostra que procura a chave ENTER:
//*------------------------------------------------------------------- //| Title: //| SubClassProc //| //| Parameters: //| hWnd - Handle to the message's destination window //| wMessage - Message number of the current message //| wParam - Additional info associated with the message //| lParam - Additional info associated with the message //| //| Purpose: //| This is the window procedure used to subclass the edit control. //*--------------------------------------------------------------------- long FAR PASCAL SubProc(HWND hWnd, WORD wMessage,WORD wParam,LONG lParam) { switch (wMessage) { case WM_GETDLGCODE: return (DLGC_WANTALLKEYS | CallWindowProc(lpOldProc, hWnd, wMessage, wParam, lParam)); case WM_CHAR: //Process this message to avoid message beeps. if ((wParam == VK_RETURN) || (wParam == VK_TAB)) return 0; else return (CallWindowProc(lpOldProc, hWnd, wMessage, wParam, lParam)); case WM_KEYDOWN: if ((wParam == VK_RETURN) || (wParam == VK_TAB)) { PostMessage (ghDlg, WM_NEXTDLGCTL, 0, 0L); return FALSE; } return (CallWindowProc(lpOldProc, hWnd, wMessage, wParam, lParam)); break ; default: break; } /* end switch */
Método 3
Este método envolve a utilização do App Studio e classWizard e a criação de uma nova função de membro da caixa de diálogo. Este método permitirá que um utilizador pressione a tecla ENTER e tenha o foco a avançar para o próximo controlo de edição. Se o foco estiver atualmente no último controlo de edição na caixa de diálogo, o foco avançará para o primeiro controlo de edição. Em primeiro lugar, utilize o App Studio para alterar o ID do botão OK da caixa de diálogo. O comportamento padrão do App Studio é dar ao botão OK o ID IDOK. O ID do botão OK deve ser alterado para outro valor, como IDC_OK. Além disso, altere as propriedades do botão OK de modo a que não seja um botão predefinido. Em seguida, use ClassWizard para criar um novo funciton membro da caixa de diálogo. Nomeie a função do novo membro algo como OnClickedOK. Esta função deve estar ligada à mensagem BN_CLICKED do controlo IDC_OK. Uma vez feito isto, escreva o corpo da função OnClickedOK. Deve colocar o código que normalmente colocaria na função OnOK na nova função OnClickedOK, incluindo a função OnOK de uma classe. Adicione o seguinte protótipo ao ficheiro do cabeçalho para a caixa de diálogo:
protected: virtual void OnOK();
Adicione uma função OnOK à caixa de diálogo e o código é como demonstrado abaixo:
void CMyDialog::OnOK() { CWnd* pwndCtrl = GetFocus(); CWnd* pwndCtrlNext = pwndCtrl; int ctrl_ID = pwndCtrl->GetDlgCtrlID(); switch (ctrl_ID) { case IDC_EDIT1: pwndCtrlNext = GetDlgItem(IDC_EDIT2); break; case IDC_EDIT2: pwndCtrlNext = GetDlgItem(IDC_EDIT3); break; case IDC_EDIT3: pwndCtrlNext = GetDlgItem(IDC_EDIT4); break; case IDC_EDIT4: pwndCtrlNext = GetDlgItem(IDC_EDIT1); break; case IDOK: CDialog::OnOK(); break; default: break; } pwndCtrlNext->SetFocus(); }