IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++Builder Discussion :

Event sur la modification d'une propriété d'un composant


Sujet :

C++Builder

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 53
    Points : 24
    Points
    24
    Par défaut Event sur la modification d'une propriété d'un composant
    Bonjour à tous,

    Je travaille en C++ builder 6 (choix du client).

    Malgré mes recherches et l'aide apporté ici je n'arrive pas à faire un truc qui semble très simple :

    J'ai créé un Frame que je vais utiliser dans plusieurs Form (application multipage). La plupart du temps le Frame sera invisible à l'apparition du Form et n'apparaitra que sur certaines actions opérateur. Afin d'éviter de coder dans chaque Form utilisant le Frame ce que je veux faire à chaque apparition du Frame (vous suivez?), je veux ajouté un EVENT à la Frame sur la modification de sa propriété : Visible.

    cad que je veux exécuter du code chaque fois que la propriété Frame->Visible passe de true à false ou l'inverse.

    Ci dessous le code que j'ai fait

    Le .h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    #ifndef pop_clavierH
    #define pop_clavierH
     
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    #include <ExtCtrls.hpp>
     
    class Tcadre_clavier : public TFrame
    {
    __published:	// IDE-managed Components
            TButton *bp_a;
            TButton *bp_z;
            TButton *bp_e;
            TButton *bp_r;
            TButton *bp_t;
    [...]
            TButton *bp_egal;
     
            //----------------------------------------------
            void __fastcall bp_aClick(TObject *Sender);
            void __fastcall bp_zClick(TObject *Sender);
     
    private:	// User declarations
    public:	// User declarations
            __fastcall Tcadre_clavier(TComponent* Owner);
            //propriété rajouté
            __property bool Visible = {read=FVisible, write=SetVisible, default = false};
    protected:
            virtual void __fastcall SetVisible(bool value);
     
    };
    //------------------------------------------------------------------------
    extern PACKAGE Tcadre_clavier *cadre_clavier;
    //------------------------------------------------------------------------
    #endif
    Le .cpp :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #include <vcl.h>
    #pragma hdrstop
     
    #include "pop_clavier.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    Tcadre_clavier *cadre_clavier;
     
    //------------------------------------------------------------------------
    __fastcall Tcadre_clavier::Tcadre_clavier(TComponent* Owner)
            : TFrame(Owner)
    {
    }
    //------------------------------------------------------------------------
    void __fastcall Tcadre_clavier::SetVisible(bool value);
    {
            FVisible = value;
            ShowMessage("Ca marche!");
    }
    //------------------------------------------------------------------------
    Je pense que je ne maitrise pas encore la structure générale du logiciel mais je pense que résoudre ce point me permettrai de mieux le comprendre.

    J'espère avoir été suffisamment clair et en attendant vos réponses, je vous souhaite à tous une bonne journée.

    noahsaga

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Quelle est la Question ?

    1- Ta propriété Visible tu devrais la mettre dans la section __published pour qu'elle masque celle du TFrame (là j'ignore ce que cela fait ?)
    Cela m'étonne qu'il n'y ait pas un Warning indiquant la baisse de portée et même les RTTI (lors du chargement de la DFM) vont affecter le Visible du TFrame pas la Visible du Tcadre_clavier, du moins cela me semblerait cohérent, après la théorie, la pratique s'avère parfois différente...

    2- Ton FVisible, c'est ce que tu as déclaré, comme celui de TControl (voire la chaine d'héritage) est privé, tu ne peux pas y accèder, utilise plutôt
    TFrame::Visible ou inherited::Visible (correspond normalement à TCustomFrame) pour accéder la propriété de l'ancêtre que tu as masqué !
    Par ce que là si ton code était exécuté (ce n'est pas le cas ! non ?), cela n'afficherait plus la Tcadre_clavier, idem à vérifier

    3- Ne pas confondre l'héritage d'une TFrame au sein d'un Projet et le développement d'un nouveau composant dans un package qui apporte plus de possibilité au moment du DesignTime !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 53
    Points : 24
    Points
    24
    Par défaut
    Salut,

    Merci de ta réponse. Mon objectif est de créer un simulacre des EVENT OnShow et OnHide sur un composant qui n'en a pas (un TFrame par exemple). D'exécuter du code lors de la modif de la propriété native Visible du TFrame... Je n'y parviens toujours pas.

    Ce que tu dis dans le point 2 est exact, avec quelques modif de code, le projet s'execute mais le FVisible déclaré masque la propriété et du coup le Tcadre_clavier ne s'affiche plus. Par contre je ne parviens pas à comprendre comment déclarer (et/ou utiliser) le TFrame::Visible ou le inherited::Visible

    De plus, impossible de déclarer comme tu le dis dans ton point 1 la propriété dans la section __published qui est réservé sur un TFrame ==> // IDE-managed Components

    Ok pour le point 3 mais utiliser le TFrame me semble plus simple et plus rapide.

    A l'heure actuelle voilà comment j'ai fait :

    le header :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    #ifndef pop_clavierH
    #define pop_clavierH
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    #include <ExtCtrls.hpp>
    #include <ActnList.hpp>
    //---------------------------------------------------------------------------
    class Tcadre_clavier : public TFrame
    {
    __published:	// IDE-managed Components
            TButton *bp_a;
            TButton *bp_z;
            TButton *bp_e;
            TButton *bp_r;
      [...]
            TButton *bp_maj;
            TButton *bp_clear;
     
            //----------------------------------------------
            void __fastcall bp_alphanumClick(TObject *Sender);
            void __fastcall bp_backClick(TObject *Sender);
            void __fastcall bp_entreeClick(TObject *Sender);
            void __fastcall bp_majClick(TObject *Sender);
            void __fastcall bp_clearClick(TObject *Sender);
     
    private:// User declarations
            void __fastcall ShowClavier(TObject *Sender);
     
    public:
            __fastcall Tcadre_clavier(TComponent* Owner);
            // User declarations
            AnsiString Fsaisie; //memo de la saisie
            __property AnsiString saisie = {read=Fsaisie, write=Setsaisie};
     
            bool maj;         //memo de l'etat de la touche maj
            TForm *form_inst; //contient l'instance de la form contenant le frame
            Tcadre_clavier *clav_inst; //contient le clavier de la form active
            TEdit *ed_instance; //recup du Tedit actif
     
    protected:
            virtual void __fastcall Setsaisie(AnsiString contenu);
     
    };
    //---------------------------------------------------------------------------
    extern PACKAGE Tcadre_clavier *cadre_clavier;
    //---------------------------------------------------------------------------
    #endif
    le cpp :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    //---------------------------------------------------------------------------
    /*
      POUR SE SERVIR DE CE FRAME IL FAUT DEFINIR SUR LE FORM L'UTILISANT UN TEdit, UN
      TMaskEdit ou un TLabeledEdit
    */
    #include <vcl.h>
    #pragma hdrstop
     
    #include "pop_clavier.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    Tcadre_clavier *cadre_clavier;
     
    //---------------------------------------------------------------------------
    __fastcall Tcadre_clavier::Tcadre_clavier(TComponent* Owner)
            : TFrame(Owner)
    {
            maj=false;
            //récupération de l'identité de la form contenant le frame
            (TForm *)form_inst = (TForm *)Owner;
     
            for (int i = 0;i<form_inst->ComponentCount;i++)
            {
     
                    if (form_inst->Components[i]->ClassNameIs("Tcadre_clavier"))
                    {
                            (Tcadre_clavier *)clav_inst = (Tcadre_clavier *)form_inst->Components[i];
                            //if( ((Tcadre_clavier *)form_inst->Components[i])->Visible == true) ShowClavier;
                    }
                    //création de l'évènement ShowClavier sur le click du TEdit
                    else if ( (form_inst->Components[i]->ClassNameIs("TLabeledEdit")) ||
                            (form_inst->Components[i]->ClassNameIs("TEdit"))  ||
                            (form_inst->Components[i]->ClassNameIs("TMaskEdit")) )
                    {
                            ((TEdit *)form_inst->Components[i])->OnClick = ShowClavier;
                    }
            }
     
    }
    //---------------------------------------------------------------------------
    //a l'apparition du clavier on l'affiche, le positionne et on récupère l'ID du Tedit
    void __fastcall Tcadre_clavier::ShowClavier(TObject *Sender)
    {
            Visible = true; //on fait apparaitre le clavier
     
            //on fait afficher le clavier sous le Edit utiliser
            if ( ((TControl *)Sender)->Parent->ClassNameIs("TForm"))
            {
                    Top = ((TControl *)Sender)->Top + 20;
            }
            else   //si le control est intégré à un autre control on le descend de la hauteur du parent
            {
                    Top =  ((TControl *)Sender)->Parent->Top +
                                                    ((TControl *)Sender)->Top + 40;
            }
            //on recupère l'identité du TEdit actif
            (TEdit *)ed_instance = (TEdit *)Sender;
            saisie = ed_instance->Text; //on garde ce qui il y avait dans le edit pour ecrire à la suite
    }
    //---------------------------------------------------------------------------
    //Fonction appelée à la modif de saisie
    void __fastcall Tcadre_clavier::Setsaisie(AnsiString contenu)
    {
            Fsaisie = contenu;
            //on recopie dans le edit actif le contenu de saisie
            ed_instance->Text = Fsaisie;
    }
    cela ne me satisfait pas vraiment mais bon...

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 53
    Points : 24
    Points
    24
    Par défaut
    Ok amoureux du Delphi et du C++ voici votre nouveau défi. cela permettrai de clôturer le sujet.

    M'aider à traduire ce code Delphi en C++ builder

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
        * uses
        * Forms, Dialogs, Classes, Controls, StdCtrls, Windows, Messages;
        *
        * type
        *
        * MaFrame = class(TFrame)
        * private
        * _OnShow : TNotifyEvent;
        * _OnHide : TNotifyEvent;
        *
        * procedure _SetOnShow(ponshow: TNotifyEvent);
        * procedure _SetOnHide(ponhide: TNotifyEvent);
        *
        * procedure FrameOnShowHide(var M: TMessage); message CM_SHOWINGCHANGED;
        * published
        * property OnShow : TNotifyEvent write _SetOnShow;
        * property OnHide : TNotifyEvent write _SetOnHide;
        * end;
        *
        * implementation
        *
        * procedure MaFrame._SetOnShow(ponshow: TNotifyEvent);
        * begin
        * _OnShow := ponshow;
        * end;
        *
        * procedure MaFrame._SetOnHide(ponhide: TNotifyEvent);
        * begin
        * _OnHide := ponhide;
        * end;
        *
        * procedure MaFrame.FrameOnShowHide(var M: TMessage);
        * begin
        * inherited;
        *
        * if Showing then // onShow
        * if Assigned( _OnShow ) then
        * _OnShow( Self )
        * else // onHide
        * if Assigned( _OnHide ) then
        * _OnHide( Self );
        * end;
    J'attends vos réponses avec impatiences

    voila ce que j'ai fait et en fait ça marche presque sauf que l'objet n'apparait pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #ifndef onshowtestingH
    #define onshowtestingH
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    //---------------------------------------------------------------------------
    class TFrame1 : public TFrame
    {
    __published:	// IDE-managed Components
    private:	// User declarations
    public:		// User declarations
            __fastcall TFrame1(TComponent* Owner);
    protected:
            virtual void __fastcall OnShow(TMessage &Msg);
     
    BEGIN_MESSAGE_MAP
        MESSAGE_HANDLER(CM_SHOWINGCHANGED, TMessage, OnShow)
    END_MESSAGE_MAP(TFrame)
     
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TFrame1 *Frame1;
    //---------------------------------------------------------------------------
    #endif
    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #include <vcl.h>
    #pragma hdrstop
     
    #include "onshowtesting.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TFrame1 *Frame1;
    //---------------------------------------------------------------------------
    __fastcall TFrame1::TFrame1(TComponent* Owner)
            : TFrame(Owner)
    {
    }
    //---------------------------------------------------------------------------
    void __fastcall TFrame1::OnShow(TMessage &Msg)
    {
        if(Showing)
        {
          ShowMessage("showing");
          Invalidate();
        }
    }

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Ta syntaxe semble correct !
    l'ancêtre dans END_MESSAGE_MAP, TFrame devrait appeler la CMExit du TControl
    Ton ShowMessage s'affiche ?
    Mais pas la Frame ?
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 53
    Points : 24
    Points
    24
    Par défaut
    en fait il fallait rajouter

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TFrame::Dispatch(&Msg);
    pas sur de comprendre...

    voici le code final :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #ifndef onshowtestingH
    #define onshowtestingH
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    //---------------------------------------------------------------------------
    class Tcadre_show : public TFrame
    {
    __published:	// IDE-managed Components
    private:	// User declarations
      virtual void __fastcall ShowChange(TMessage &Msg);
     
    BEGIN_MESSAGE_MAP
        MESSAGE_HANDLER(CM_SHOWINGCHANGED, TMessage, ShowChange)
    END_MESSAGE_MAP(TFrame)
     
    public:		// User declarations
            __fastcall Tcadre_show(TComponent* Owner);
     
    };
    //---------------------------------------------------------------------------
    extern PACKAGE Tcadre_show *cadre_show;
    //---------------------------------------------------------------------------
    #endif
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #include <vcl.h>
    #pragma hdrstop
     
    #include "onshowtesting.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    Tcadre_show *cadre_show;
    //---------------------------------------------------------------------------
    __fastcall Tcadre_show::Tcadre_show(TComponent* Owner)
            : TFrame(Owner)
    {
    }
    //---------------------------------------------------------------------------
    void __fastcall Tcadre_show::ShowChange(TMessage &Msg)
    {
      TFrame::Dispatch(&Msg);
     
      if (this->Showing)
      {
            //code sur le show
      }
      else
      {
            //code sur le hide
      }
     
    }
    Par contre cela ne créé pas l'event OnShow, OnHide dans les propriété du Frame rendant l'event utilisable sur les Form utilisant le Frame. c'est donc du code "interne".

    quand j'aurai un peu de temps j'essaierai de créer les Event.

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Pour les events (published) dans l'inspecteur d'objet, il faut faire un composant et l'installer via un package
    Je ne sais pas si le Frame est compatible avec ce type d'utilisation !

    Dispatch, hum, normalement c'est
    tu as tenté d'appeler ta fonction "CMShowingChanged" au lieu de "ShowChange" ?

    redéfinir la propriété visible n'a pas fonctionner ??? même en la mettant en published (certe par d'effet sur l'IDE mais devrait en avoir en RunTime)
    c'est l'utilisation de TFrame::Visible qui te posait des problèmes ?
    Tu sais que ça permet d'appeler la méthode ancêtre comme inherited en delphi, super en java, parent:: en php !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    //------------------------------------------------------------------------
    void __fastcall Tcadre_clavier::SetVisible(bool value);
    {
        TFrame::Visible = value;
    }
    //------------------------------------------------------------------------
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

Discussions similaires

  1. Alerte sur la modification d'une table
    Par Mothership dans le forum Administration
    Réponses: 1
    Dernier message: 21/05/2008, 15h10
  2. [WCF] notification sur le changement d'une propriété.
    Par maa dans le forum Windows Communication Foundation
    Réponses: 6
    Dernier message: 23/03/2008, 11h19
  3. test sur le nom d'une propriété
    Par Hefbee dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 19/11/2007, 08h46
  4. Réponses: 2
    Dernier message: 09/11/2006, 14h46
  5. javascript > modification d'une propriété déjà définie en
    Par Cypselos dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 17/12/2005, 17h44

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo