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

Composants VCL Delphi Discussion :

Modif du Tabindex d'un PageControl situé dans 1 Frame


Sujet :

Composants VCL Delphi

  1. #1
    Expert éminent
    Avatar de qi130
    Homme Profil pro
    Expert Processus IT
    Inscrit en
    Mars 2003
    Messages
    3 925
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France

    Informations professionnelles :
    Activité : Expert Processus IT
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2003
    Messages : 3 925
    Points : 6 040
    Points
    6 040
    Par défaut Modif du Tabindex d'un PageControl situé dans 1 Frame
    Bonjour à tous,

    C'est par pure commodité, afin de remédier à l'oubli de remettre la bonne ActivePage dans l'IDE quand je modifie 1 autre page

    Mon problème est que le PageControl est dans 1 frame, et mon inexpérience de cette particularité me fait perdre bcp de temps... Les quelques essais qui "passent" à la compil ne me satisfont pas entièrement : c'est bien la bonne page qui s'affiche, mais un traitement préalable à l'apparition de la frame provoque 1 exception ( ... lecture de l'adresse ...) - Cette exception ne se produit pas si la bonne page est active dans l'IDE lors de la compil.

    Bref, où intervenir et en quels termes ?

    Merci par avance.

    La déclaration issue d'un post (~2010) sur le forum que je n'ai pas retrouvé (ou su chercher)

    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
    unit FBMframe00;
     
    interface
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ComCtrls;
     
    type
      TFrameClass = class of TFrame;
      TFrameType = (ftTypeDB,ftTypeTB,ftTypeSQL);
     
      IMyInterface0 = interface(IInterface)       // onglet type DB
      ['{85B6F6B6-8E48-4438-BB3F-0091612344CC}']
    //    procedure monAction;
      end;
    La partie création
    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
     
    function TForm1.addTabsheet(APageControl: TPageControl;
                                FrameType: TFrameType):TTabSheet;
    const
      CTABNAME   = 'TAB%d';
      CFRAMENAME = 'FRAME%d';
    var
      AFrame: TFrame;
      CFrame: TComponent;
    begin
      Result := TTabSheet.Create(APageControl);
      Result.PageControl := APageControl;
    //  Result.Visible:=False;
    //  Result.TabVisible:=False;
     
      Inc(tabCount);
      Result.Name := format(CTABNAME,[tabCount]);
      Result.Caption := TDBinfos(DBinfosList[CurrentDB]).Alias;
      Result.Hint:=CurrentUser+'@'+TDBinfos(DBinfosList[CurrentDB]).serveur;
      Result.ParentShowHint:=False;
      TDBinfos(DBinfosList[CurrentDB]).LastUse:=Now;
      case FrameType of
        ftTypeDB : begin
            AFrame := TFrameClass(findClass('TAncestorFrame0')).Create(Result);
     
        end;
      end;
      AFrame.Name := format(CFRAMENAME,[tabCount]);
      AFrame.Parent := Result;
      AFrame.Align := alClient;
      Result.ImageIndex:=AddBmpToImageList(TDBinfos(DBinfosList[CurrentDB]).visuel);
      APageControl.ActivePageIndex := Result.PageIndex;
      CFrame := FocusedFrame;
      if Assigned(CFrame)
        then
          if Supports(CFrame,IMyInterface0) then begin
             (CFrame as TAncestorFrame0).PageControl4.TabIndex:=0;                             // <<< résultat OK mais exception avant affichage
             (CFrame as TAncestorFrame0).InitConnexion(CurrentDB);
          end;
    end;
    Le début de la frame:
    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
    unit FBMframeDB;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
      Dialogs, ImgList, StdCtrls, ComCtrls, ToolWin, NxColumnClasses, NxColumns,
      NxScrollControl, NxCustomGridControl, NxCustomGrid, NxGrid, Buttons, ExtCtrls,
      SynEdit,  SynEditHighlighter, SynHighlighterSQL,FBMframe00,
      FBMframeTB,FBMframeSQL, uiblib, FBMdm,
      StrUtils, uib, UIBMetaData,TypInfo, Vcl.Menus, Vcl.Samples.Spin,
      System.ImageList, NxEdit, Data.DB, uibdataset,ShellAPI,
      NxCollection, Vcl.Imaging.pngimage, SynMemo, PDJRotoLabel, DosCommand;
     
    type
      TAncestorFrame0 = class(TFrame,IMyInterface0)
        Panel2: TPanel;
        Splitter2: TSplitter;
        Panel3: TPanel;
        PageControl4: TPageControl;                                       //  << le pagecontrol concerné
        TabSheet13: TTabSh
    "Il n'y a pas de bonnes réponses à une mauvaise question." (M. Godet)
    -----------------------
    Pensez à cloturer votre sujet - Aucune réponse aux sollicitations techniques par MP
    Usus magister est optimus

  2. #2
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 840
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 840
    Points : 13 607
    Points
    13 607
    Par défaut
    Citation Envoyé par qi130 Voir le message
    C'est par pure commodité, afin de remédier à l'oubli de remettre la bonne ActivePage dans l'IDE quand je modifie 1 autre page
    Un code sacrément alambiqué juste pour activer un onglet, non ?

    Le problème vient certainement du comportement de supports. L'avertissement précise que sur une instance son compteur de référence est incrémenté, ce qui entraîne immanquablement une décrémentation à la sortie de la procédure et de cause à effet la libération de l'objet si le compteur est à zéro. Donc pour palier à cela, il suffirait d'augmenter manuellement le compteur par CFrame._AddRef.

    Je comprends bien que ton problème est qu'un frame n'a pas d'événement OnCreate pour définir l'onglet actif. On peut cependant facilement le faire par une p'tit surcharge du PageControl.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    type
      TPageControl = class(Vcl.ComCtrls.TPageControl)
      protected
        procedure Loaded; override;
      end;
     
    procedure TPageControl.Loaded;
    begin
      inherited;
      ActivePageIndex := 0;
    end;
    Le même principe est valable depuis TAncestorFrame0.Loaded.

    Ne serait-ce pas plus simple ainsi

  3. #3
    Expert éminent
    Avatar de qi130
    Homme Profil pro
    Expert Processus IT
    Inscrit en
    Mars 2003
    Messages
    3 925
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France

    Informations professionnelles :
    Activité : Expert Processus IT
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2003
    Messages : 3 925
    Points : 6 040
    Points
    6 040
    Par défaut
    Bonjour, et merci pour tes éléments de réponse.

    J'ai implémenté ta suggestion en mode "singe voit-singe fait", mais la compil est KO sur cette ligne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    PC:=((((((((Sender as TSpeedButton).Parent) as TPanel).Parent) as TPanel).Parent) as TFrame).Parent as TTabsheet).PageControl;
    [dcc32 Erreur] FBMframeDB.pas(655): E2010 Types incompatibles : 'FBMframeDB.TPageControl' et 'Vcl.ComCtrls.TPageControl'
    Tu vas dire que l'alambiqué est très complexe, mais c'est lié à mon soft qui me permet d'ouvrir des bases Firebird:
    la form principale ne contient qu'un pagecontrol dans lequel j'ajoute 1 onglet (frameDB) pour chaque base ouverte. Pour chaque base ouverte, j'ai 1 pagecontrol pour les "objets" (tables, vues, etc.), 1 autre pour des requêtes (via 1 Frame), et le pagecontrol4 que j'enrichis d'un onglet pour chaque table ou vue ouverte via autre Frame), en plus des onglets constants:
    Nom : Capture.PNG
Affichages : 50
Taille : 60,5 Ko

    Cependant,
    un frame n'a pas d'événement OnCreate pour définir l'onglet actif.
    m'a fait avancé puisque j'ai ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    procedure TAncestorFrame0.CreateWnd;
    begin
         inherited;
         DragAcceptFiles(Handle, True);
    end;
    il m'a suffi d'y ajouter
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    PageControl4.ActivePageIndex:=0;
    "Il n'y a pas de bonnes réponses à une mauvaise question." (M. Godet)
    -----------------------
    Pensez à cloturer votre sujet - Aucune réponse aux sollicitations techniques par MP
    Usus magister est optimus

  4. #4
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 840
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 840
    Points : 13 607
    Points
    13 607
    Par défaut
    Citation Envoyé par qi130 Voir le message
    PC:=((((((((Sender as TSpeedButton).Parent) as TPanel).Parent) as TPanel).Parent) as TFrame).Parent as TTabsheet).PageControl;
    Pas très évolutif, tu devrais remplacer ça par une méthode qui remonte dans la hiérarchie.

    Citation Envoyé par qi130 Voir le message
    Tu vas dire que l'alambiqué est très complexe, mais c'est lié à mon soft qui me permet d'ouvrir des bases Firebird:
    D'accord mais tu complexifies inutilement.
    AFrame := TFrameClass(findClass('TAncestorFrame0')).Create(Result); égale AFrame := TAncestorFrame0.Create(Result);.
    Une variable Info :TDBinfos faciliterais aussi la lecture/maintenance.

    Citation Envoyé par qi130 Voir le message
    procedure TAncestorFrame0.CreateWnd;
    Tu peux mais ce n'est pas le meilleur endroit. CreateWnd peut être appelé en différentes occasions alors que Loaded n'est appelé qu'une seule fois après traitement du DFM.

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 726
    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 726
    Points : 25 628
    Points
    25 628
    Par défaut
    La TFrame, je n'ai jamais apprécié cette chose, j'ai vu tellement de fois l'erreur du "TFrame non trouvé" par l'IDE car impossible d'ouvrir un TForm sans ouvrir le projet lorsque celui contient une TFrame ou alors lorsque l'on utilise un groupe de projet, il ne sait plus trop comment géré si le développeur a eu la mauvaise idée de nommer plusieurs TFrame avec le même nom (parfois la même dupliquée) dans plusieurs projets du groupe de projet, la panique de l'IDE !

    Je préfère de loin une TForm que l'on ancre dans le TabSheet

    J'ai d'ailleurs comme toi, utiliser des IInterface pour la communication entre Parent et Enfant, cela permet d'avoir un code au couplage faible, et d'avoir plusieurs types de TForm dockage / TFrame utilisant les mêmes protoypes.
    Cependant, je n'utilise QUE les interfaces, et uniquement les interfaces, jamais les références (comme toi, une Factory pouvant créer différent type d'onglet), ce mélange de manipulation interface/référence n'est jamais très bon pour un objet lambda ayant pour ancêtre un TInterfacedObject.

    Voici un exemple où j'ai même utilisé plusieurs Panel au sein d'une TForm servant d'équivalent de TFrame dans un Conteneur : Partage d'un formulaire entre deux applications, le Conteneur était générique et les "Frame" permettait de le spécialiser sur une activité spécifique (différent poste logistique)
    Aucune manipulation directe de la "Frame", tout passe par des Interface, c'est justement ce mélange où tu es tenté d'utiliser l'intérieur de tes "Frame" qui t'amène à avoir des erreurs dans les flux.

    Je n'ai pas le code sous la main mais j'avais exactement ton cas, un TPageControl dans une "Frame / Form ancrée" dont la page Active est modifiée par le Conteneur.


    Par contre pour un TFrame qui hérite de TComponent, il n'y a pas de compteur de référence donc pas de libération lorsque l'on utilise des interfaces sur un TFrame.



    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    PC:=((((((((Sender as TSpeedButton).Parent) as TPanel).Parent) as TPanel).Parent) as TFrame).Parent as TTabsheet).PageControl;
    Je ne l'ai pas sous la main mais c'est un grand classique que j'ai écrit plein de fois, une version tapée directement sur le forum donc surement quelques erreurs)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function GetPageControl(AControl: TControl): TPageControl;
    var
      P: TWinControl;
    begin
      if not Assigned(AControl) then
        Exit(nil);
     
      P := AControl.Parent;
      if P is TTabsheet then
        Result := TTabsheet(P).PageControl
      else
        Result := GetPageControl(P);
    end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    PC := GetPageControl(Sender as TControl);

    [dcc32 Erreur] FBMframeDB.pas(655): E2010 Types incompatibles : 'FBMframeDB.TPageControl' et 'Vcl.ComCtrls.TPageControl'
    Avec la proposition de Andnotor, cela a reféfini TPageControl dans FBMframeDB, c'est donc tout a fait normal

    Du coup, si la TFrame n'est pas ancré dans son parent en DesignTime, il n'y a vraiment aucun intérêt à faire une TFrame, autant faire une TForm, en plus on pourra de-docker l'onglet en retirant le Parent


    Pour ancrer de façon simpliste une TForm dans un Tabsheet

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
      Form := TFormTrucMachin.Create(ATabsheet);
      Form.BorderStyle := bsNone;
      Form.Align := alClient;
      Form.Parent := ATabsheet;
      Form.Visible := True;
    la libération du Tabsheet provoquera la libération du Form, à cause du lien de parentalité (un control enfant ne peut survivre à son control parent) qui se produit avant le même le lien de possession (Owner)
    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

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Lire un fichier situé dans 2 sous dossier...
    Par Pleymo dans le forum Langage
    Réponses: 10
    Dernier message: 08/12/2005, 10h30
  2. Comment parcourir les dossiers situé dans le client
    Par etarip dans le forum Général JavaScript
    Réponses: 8
    Dernier message: 17/11/2005, 11h16
  3. [MFC]Recuperation de variable situé dans un thread
    Par dreamkiller dans le forum MFC
    Réponses: 26
    Dernier message: 05/04/2005, 16h26
  4. Réponses: 2
    Dernier message: 23/11/2003, 19h44

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