TN021: Comando e il Routing dei messaggi

Questa nota viene descritta l'architettura di routing e di spedizione di comando, così come argomenti avanzati nella finestra generale il routing dei messaggi.

Per fare riferimento al manuale del programmatore di Visual C++ dettagli generali sulle architetture descritte qui, specialmente la distinzione tra messaggi di Windows, notifiche di controllo e comandi. La presente nota si presuppone molto familiarità con i problemi descritti nella documentazione stampata e solo affronta argomenti molto avanzati.

Funzionalità di Routing di comandi e Dispatch MFC 1.0 evolve a MFC 2.0 architettura

Windows ha il messaggio WM_COMMAND che viene sottoposto a overload per fornire avvisi di comandi di menu, tasti di scelta rapida e le notifiche di controllo della finestra di dialogo.

Classe per ottenere chiamato in risposta a una specifica WM_COMMANDderivata MFC 1.0 costruito su quel poco consentendo un gestore di comandi (ad esempio, "OnFileNew") in un CWnd . Questo è incollato insieme con una struttura di dati chiamata mappa messaggi e si traduce in un meccanismo di comando molto efficiente dello spazio.

MFC 1.0 ha anche fornito ulteriori funzionalità per la separazione delle notifiche del controllo dai messaggi di comando. I comandi sono rappresentati da un ID di 16 bit, noto anche come un ID di comando. Comandi iniziano normalmente da un CFrameWnd (ad esempio: un menu selezionate o un acceleratore tradotto) e ottenere indirizzato ad una varietà di altre finestre.

MFC 1.0 utilizzato routing di comandi in un certo senso limitato per l'implementazione di Multiple Document Interface (MDI). (Una finestra cornice MDI delegare i comandi per la sua finestra figlio MDI attivo).

Questa funzionalità è stata generalizzata ed estesa in MFC 2.0 per consentire i comandi per essere gestita da una vasta gamma di oggetti (non solo oggetti finestra). Esso fornisce una più formali e architettura estensibile per il routing dei messaggi e riutilizza il bersaglio routing di comandi per la gestione non solo dei comandi, ma anche per l'aggiornamento di oggetti dell'interfaccia utente (come voci di menu e pulsanti della barra degli strumenti) per riflettere la disponibilità attuale di un comando.

ID di comando

Per una spiegazione del comando routing e il processo di associazione, vedere il manuale del programmatore di Visual C++ . 20 Nota tecnica contiene le informazioni sull'ID di denominazione.

Usiamo il prefisso generico "ID" _ per gli ID di comando. Comando ID sono gt; = 0x8000. La barra di stato o linea di messaggio mostrerà la stringa di descrizione del comando se c'è una risorsa STRIN>ABLE con gli stessi ID come l'ID di comando.

Le risorse dell'applicazione, un comando che ID può appare in diverse località:

Nel codice sorgente dell'applicazione, un comando che ID può appare in diverse località:

Attualmente, l'unica implementazione in MFC che gli ID di comando è necessario essere gt; = 0x8000 è l'implementazione di finestre di dialogo &GOSUB/comandi.

Comandi GOSUB, utilizzando il comando architettura nelle finestre di dialogo

L'architettura di comando di routing e di abilitazione comandi funziona bene con finestre cornice, voci di menu, pulsanti barra degli strumenti, pulsanti della barra di dialogo, altre barre di controllo e altri elementi dell'interfaccia utente progettati per aggiornamento sulla domanda e rotta comandi o controllare gli ID ad un target di comando principale (solitamente la finestra del frame principale). Tale destinazione comando principale può instradare le notifiche di controllo o di comando per altri oggetti di destinazione del comando appropriata.

Una finestra di dialogo (modale o non modale) può trarre beneficio da alcune delle caratteristiche dell'architettura comando se si assegna l'ID del controllo del controllo di dialogo per l'ID di comando appropriato. Il supporto per le finestre di dialogo non è automatico, quindi devi scrivere del codice aggiuntivo.

Notare che per tutte queste funzionalità funzionare correttamente, la tuo ID di comando dovrebbe essere gt; = 0x8000. Poiché molte finestre di dialogo potrebbe ottenere indirizzati alla stessa cornice, dovrebbero essere condivisi comandi > = 0x8000, mentre dovrebbe essere il non condivisa IDC in una finestra di dialogo specifica < = 0x7FFF.

È possibile inserire un pulsante normale in una normale finestra di dialogo modale con l'IDC del pulsante per impostare l'ID di comando appropriato. Quando l'utente seleziona il pulsante, il proprietario della finestra di dialogo (di solito la finestra del frame principale) ottiene il comando proprio come qualsiasi altro comando. Questo si chiama un comando GOSUB, dato che di solito è usato per portare un'altra finestra di dialogo (un GOSUB della finestra di dialogo prima).

Puoi anche chiamare la funzione CWnd::UpdateDialogControls tuo nella finestra di dialogo e passarlo all'indirizzo della finestra del frame principale. Questa volontà di funzione abilitata o disattivare i controlli di dialogo basato su che dispongano di gestori di comandi del fotogramma. Questa funzione viene chiamata automaticamente per voi per barre di controllo nel ciclo di inattività dell'applicazione, ma è necessario chiamare direttamente per i normali dialoghi che si desiderano avere questa caratteristica.

Quando viene chiamato ON_UPDATE_COMMAND_UI

Mantenere lo stato abilitato/controllato delle voci di menu di tutti un programma tutto il tempo può essere un problema computazionalmente costoso. Una tecnica comune è quello di abilitare o controllo voci di menu solo quando l'utente seleziona il POPUP. L'implementazione MFC 2.0 di CFrameWnd gestisce il messaggio WM_INITMENUPOPUP e l'architettura del comando routing viene utilizzato per determinare gli Stati dei menu tramite i gestori ON_UPDATE_COMMAND_UI.

CFrameWnd gestisce anche il messaggio WM_ENTERIDLE per descrivere il menu attuale elemento selezionato sulla barra (conosciuto anche come la linea di messaggio) di stato.

Struttura di menu di un'applicazione, a cura di Visual C++, viene utilizzata per rappresentare i comandi potenziali disponibili in fase di WM_INITMENUPOPUP . I gestori ON_UPDATE_COMMAND_UI possono modificare lo stato o il testo di un menu o per usi avanzati (come l'elenco di File MRU o menu a comparsa OLE verbi), effettivamente modificare la struttura di menu prima viene disegnato il menu.

Lo stesso tipo di elaborazione ON_UPDATE_COMMAND_UI è fatto per le barre degli strumenti (e altre barre di controllo) quando l'applicazione entra nel suo ciclo idle. Per ulteriori informazioni su barre di controllo, vedere il Riferimento alla libreria di classi e tecnica nota 31.

Menu contestuali nidificati

Se si utilizza una struttura di menu nidificate, si noterà che il gestore ON_UPDATE_COMMAND_UI per la prima voce di menu nel popup viene chiamato in due diversi casi.

In primo luogo si chiama per il popup se stessa. Questo è necessario dal momento che i menu contestuali non dispongono di ID e usiamo l'ID della voce di menu prima del popup per riferirsi all'intero menu di scelta rapida. In questo caso la variabile membro m_pSubMenu dell'oggetto CCmdUI sarà diverso da NULL e punterà al menu a comparsa.

In secondo luogo si chiama appena prima che le voci di menu nel popup sono da trarre. In questo caso l'ID si riferisce solo alla voce di menu prima e la variabile membro m_pSubMenu dell'oggetto CCmdUI saranno NULL.

Ciò consente di attivare il distinto dal sua voci di menu popup, ma richiede che scrivere del codice consapevoli di menù. Per esempio, in un menu nidificate con la seguente struttura:

Filegt;
    Nuovo >
        Foglio (ID_NEW_SHEET)
        Grafico (ID_NEW_CHART)

I comandi ID_NEW_SHEET e ID_NEW_CHART possono essere autonomamente attivati o disabilitati. Menu a comparsa "New" deve essere abilitato se uno dei due è abilitato.

Il gestore di comandi per ID_NEW_SHEET (il primo comando nel popup) sembrerebbe qualcosa di simile:

public static void CMyApp::OnUpdateNewSheet (CCmdUI pCmdUI)
{
 nbsp;  Se (pCmdUI - > m_pSubMenu! = NULL)
    {
        / / Abilita intero popup per "Nuovo" di fogli e grafico
        BOOL bAttivare = m_bCanCreateSheet | | m_bCanCreateChart;

/ / CCmdUI::Enable non è un-op per questo caso, così abbiamo
        / / deve fare quello che avrebbe fatto.
        pCmdUI - > m_pMenu - > EnableMenuItem (pCmdUI - > m_nIndex,
            MF_BYPOSITION | 
                (bAttivare? MF_ENABLED: (MF_DISABLED | MF_GRAYED)));
        ritorno;
    }
    / / altrimenti appena il comando nuovo foglio
    pCmdUI - > Enable(m_bCanCreateSheet);
}

Il gestore di comandi per ID_NEW_CHART sarebbe un normale aggiornamento gestore di comandi e sguardo qualcosa di simile:

public static void CMyApp::OnUpdateNewChart (CCmdUI pCmdUI)
{
 nbsp;  pCmdUI - > Enable(m_bCanCreateChart);
}

ON_COMMAND e ON_BN_CLICKED

Le macro di mappa del messaggio per ON_COMMAND e ON_BN_CLICKED sono le stesse. Il MFC comando e controllo routing meccanismo di notifica solo utilizza l'ID di comando decidere dove indirizzare a. Le notifiche di controllo con il codice di controllo notifica di zero (BN_CLICKED) vengono interpretate come comandi.

Nota avanzata: In realtà, tutti i messaggi di notifica di controllo passano attraverso la catena di comando gestore. Pertanto è tecnicamente possibile scrivere un gestore di notifica di controllo per dire EN_CHANGE in documento di classe. Questo non è in genere consigliabile poiché le applicazioni pratiche di questa caratteristica sono pochi, la funzionalità non è supportata da ClassWizard e utilizzo della funzionalità può generare codice fragile.

Disabilitando la disabilitazione automatica dei controlli Button

Se si inserisce un controllo pulsante su una barra della finestra di dialogo o in una finestra di dialogo utilizzando dove si sta chiamando CWnd::UpdateDialogControls sul vostro proprio, si noterà che pulsanti che non hanno i gestori ON_COMMAND o ON_UPDATE_COMMAND_UI verranno automaticamente disabilitato per te dal framework. In alcuni casi non sarà necessario un gestore, ma è preferibile il pulsante di rimanere abilitato. Il modo più semplice per raggiungere questo obiettivo è quello di aggiungere un gestore di comandi fittizio (facile da fare con ClassWizard) e fare nulla in essa.

Finestra il Routing dei messaggi

Di seguito sono descritti alcuni argomenti più avanzati sulle classi MFC e come il routing dei messaggi di Windows e di altri argomenti loro impatto. Le informazioni qui sono descritto solo brevemente. Fare riferimento al Riferimento alla libreria di classi per i dettagli sulle API pubbliche. Si prega di riferirsi al codice sorgente libreria MFC per ulteriori informazioni sui dettagli di implementazione.

Vai alla tecnica nota 17 per dettagli sulla pulitura della finestra, un argomento molto importante per tutti i CWnd-classi derivate.

Problemi di CWnd

La funzione di membro di implementazione CWnd::OnChildNotify offre un'architettura potente ed estensibile per finestre figlio (noto anche come controlli) per collegare o altrimenti essere informati dei messaggi, i comandi e le notifiche di controllo che vanno a loro genitore (o "proprietario"). Se la finestra figlio (/ controllo) è un oggetto C++ CWnd se stessa, la funzione virtuale OnChildNotify viene chiamato per primo con i parametri dal messaggio originale (che è, una struttura MSG ). Finestra figlio può lasciare solo il messaggio, mangiare o modificare il messaggio per il genitore (raro).

L'implementazione predefinita CWnd gestisce i seguenti messaggi e utilizza l'hook OnChildNotify per consentire di finestre figlio (controlli) per ottenere prima crepa del messaggio:

Si noterà che l'hook OnChildNotify viene utilizzato per modificare i messaggi creati dal proprietario in messaggi self-draw.

Il gancio OnChildNotify , oltre a messaggi di scorrimento hanno comportamento di routing ulteriormente. Per favore vedi sotto per maggiori dettagli sulle barre di scorrimento e fonti dei WM_VSCROLL messaggi WM_HSCROLL e.

CFrameWnd edizioni

La classe CFrameWnd fornisce la maggior parte del routing di comandi e interfaccia utente aggiornando implementazione. Questo viene utilizzato principalmente per la finestra cornice principale dell'applicazione (CWinApp::m_pMainWnd), ma si applica a tutte le finestre con frame.

La finestra del frame principale è la finestra con la barra dei menu ed è l'elemento della barra di stato o un messaggio di linea. Consultare la precedente discussione sul routing di comandi e WM_INITMENUPOPUP.

La classe CFrameWnd fornisce gestione della visualizzazione attiva. I seguenti messaggi vengono instradati attraverso la visualizzazione attiva:

Questioni CMDIFrameWnd/CMDIChildWnd

Sia classi di finestre cornice MDI derivano da CFrameWnd e pertanto sono entrambi abilitati per lo stesso tipo di routing di comandi e interfaccia utente l'aggiornamento fornito nel CFrameWnd. In una tipica applicazione MDI, solo la finestra del frame principale (cioè, l'oggetto CMDIFrameWnd ) detiene la barra dei menu e la barra di stato e quindi è la principale fonte dell'implementazione di instradamento di comando.

Del regime generale di routing è che la finestra figlio MDI attiva ottiene la prima crepa a comandi. Le funzioni di PreTranslateMessage predefinito gestiscono tabelle di acceleratore per entrambi finestre figlio MDI (prima) e la cornice MDI (secondo), come pure gli acceleratori di comando del sistema MDI standard normalmente gestiti da TranslateMDISysAccel (ultimo).

Problemi di barra di scorrimento

Durante la gestione di messaggi di scorrimento (WM_HSCROLL/OnHScroll e/o WM_VSCROLL/OnVScroll ), si dovrebbe cercare di scrivere il codice del gestore, in modo da non fare affidamento su dove il messaggio di barra di scorrimento è venuto da. Questo non è solo una questione Windows generale, dal momento che i messaggi di scorrimento possono provenire da vero scorrimento barra controlli o da WS_HSCROLL/WS_VSCROLL le barre di scorrimento che sono non scroll bar controlli.

MFC estende che per consentire controlli barra di scorrimento sia il bambino o i fratelli della finestra sta durante lo scorrimento (in realtà la relazione padre/figlio tra la barra di scorrimento e la finestra sta scorre può essere qualsiasi cosa). Questo è particolarmente importante per le barre di scorrimento condivisa con CreateStatic. Per informazioni dettagliate sull'attuazione del CSplitterWnd incluse ulteriori informazioni sulle questioni di barra di scorrimento condivisa fare riferimento a tecniche nota 29.

Su un lato nota, ci sono due CWnd classi derivate, dove gli stili di barra di scorrimento specificati a creano il tempo sono intrappolate e non passate a Windows. Quando passò a una routine di creazione, WS_HSCROLL e WS_VSCROLL può essere impostare in modo indipendente, ma dopo la creazione non può essere cambiato. Naturalmente, si dovrebbe non direttamente testare o impostare il WS_?SCORRERE il bit di stile della finestra che hanno creato.

Per CMDIFrameWnd gli stili di barra di scorrimento che passare a Crea o LoadFrame vengono utilizzati per creare il MDICLIENT. Se si desidera avere una area MDICLIENT scorrevole (come il Program Manager di Windows) assicurarsi di impostare entrambi lo scorrimento barra stili (WS_HSCROLL | WS_VSCROLL) per lo stile utilizzato per creare il CMDIFrameWnd.

Per CSplitterWnd gli stili di barra di scorrimento si applicano per le barre di scorrimento condivise speciali per le regioni di splitter. Per windows separatore statico, normalmente non verrà impostata sia stile barra di scorrimento. Per windows sdoppiatore dinamico si avrà solitamente lo scroll bar di stile impostato per la direzione che dividerà, cioè, WS_HSCROLL se è possibile dividere le righe, WS_VSCROLL se è possibile dividere le colonne.

&Note tecniche per numero |nbsp; Note tecniche per la categoria

Index