Newsgroup: it.comp.lang.delphi
Titolo: DBNavigator e Glyph

 Vorrei Modificare le glyph del DBNavigator,  possibile??
Cla F.
--- posted by geoForum on 
http://www.delphiedintorni.it

 Vorrei Modificare le glyph del DBNavigator,  possibile??
IMHO fai prima a crearti dei pulsanti ad hoc (magari più user friendly) che
richiamano direttamente le operazioni sul dataset.
Altrimenti, puoi fargli richiamare i pulsanti del DB Navigator, usando il
metodo BtnClick, mantenendolo nascosto... non so perché, ma il DBN è un
componente che non mi è mai piaciuto.
--
Jax
====
L'uomo campa cent'anni... e si preoccupa per mille.

)

 componente che non mi è mai piaciuto.
Le icone che vedi (le freccette per intenderci..) sono delle icone,
basta derivare e modificare, questa è programmazione ad oggetti, scusa
se te lo dico ma la prima risposta è corretta, la seconda è 'na
zozzeria... ;-P
Comunque in allegato il codice per fare le icone sulla DBNavigator, il
codice funziona ma andrebbe migliorato qua e la, per completezza
alcuni pezzi li ho presi dalla rete.
Attenzione alla licensa !!
{
    This program is free software; you can redistribute it and/or
modify
    it under the terms of the GNU General Public License as published
by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
02111-1307  USA
}
unit DBNavigatorMax;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs,
  ExtCtrls, DBCtrls, Buttons, DB, ImgList;
resourcestring
  SDeleteRecordQuestion = 'Conferma cancellazione record ?';
type
  ENavClickMx = procedure (Sender: TObject; Button: TNavigateBtn;
    var EAbort: boolean; var ErrorHandle: boolean) of object;
  EHandleError = procedure (Sender: TObject; EException: Exception) of
object;
  TNavDataLinkMX = class;
  TDBNavigatorMax = class(TDBNavigator)
  private
    { Private declarations }
    FBeforeAction: ENavClickMx;
    FOnHandleError: EHandleError;
    FCaptions: TStrings;
    FLayout: TButtonLayout;
    FMargin: Integer;
    FSpacing: Integer;
    FShowCaptions: boolean;
    FDataLink: TNavDataLinkMX;
    FGlyphs: TImageList;
    FButtonClick: TNavigateBtn;
    FNumGlyph: integer;
    FMsgConfirmDelete: string;
    procedure SetLayout(Value: TButtonLayout);
    procedure SetMargin(Value: integer);
    procedure SetSpacing(Value: integer);
    procedure SetCaptions(const Value: TStrings);
    procedure SetShowCaptions(const Value: boolean);
    procedure SetGlyphs(Value: TImageList);
    function GetDataSource: TDataSource;
    procedure SetDataSource(const Value: TDataSource);
    procedure SetNumGlyph(const Value: integer);
    procedure InitButtons;
  protected
    { Protected declarations }
    procedure DataChanged; dynamic;
    procedure EditingChanged; dynamic;
    procedure ActiveChanged; dynamic;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure BtnClick(Index: TNavigateBtn); override;
  published
    { Published declarations }
    property MsgConfirmDelete: string read FMsgConfirmDelete write
FMsgConfirmDelete;
    property Captions: TStrings read FCaptions write SetCaptions;
    property NumGlyph: integer read FNumGlyph write SetNumGlyph
default 2;
    property Glyphs: TImageList read FGlyphs write SetGlyphs;
    property DataSource: TDataSource read GetDataSource write
SetDataSource;
    property Layout: TButtonLayout read FLayout write SetLayout;
    property Spacing: Integer read FSpacing write SetSpacing default
2;
    property Margin: Integer read FMargin write SetMargin;
    property ShowCaptions: boolean read FShowCaptions write
SetShowCaptions;
    property BeforeAction: ENavClickMx read FBeforeAction write
FBeforeAction;
    property OnHandleError: EHandleError read FOnHandleError write
FOnHandleError;
  end;
{ TNavDataLink }
  TNavDataLinkMX = class(TDataLink)
  private
    FNavigator: TDBNavigatorMax;
  protected
    procedure EditingChanged; override;
    procedure DataSetChanged; override;
    procedure ActiveChanged; override;
  public
    constructor Create(ANav: TDBNavigatorMax);
    destructor Destroy; override;
  end;
procedure Register;
implementation
procedure Register;
begin
  RegisterComponents('Max', [TDBNavigatorMax]);
end;
 
 
const
  DefaultCaption: array[0..9] of string =
    ('Primo','Prec.','Succ.','Ultimo','Nuovo',
     'Elimina','Modifica','Salva','Annulla','Refresh');
  {
  EnglishCaption: array[0..9] of string =
     ('First','Prior','Next','Last','Insert',
     'Delete','Edit','Accept','Undo','Refresh');
  }
  BtnTypeName: array[TNavigateBtn] of PChar = ('FIRST', 'PRIOR',
'NEXT',
    'LAST', 'INSERT', 'DELETE', 'EDIT', 'POST', 'CANCEL', 'REFRESH');
{ TDBNavigatorMax }
procedure TDBNavigatorMax.InitButtons;
var
  I: TNavigateBtn;
  ResName: string;
begin
  if not (csDesigning in ComponentState) then
    for I := Low(Buttons) to High(Buttons) do
    begin
      Buttons[I].NumGlyphs := 2;
      FmtStr(ResName, 'dbn_%s', [BtnTypeName[I]]);
      Buttons[I].Glyph.LoadFromResourceName(HInstance, ResName);
    end;
end;
procedure TDBNavigatorMax.BtnClick(Index: TNavigateBtn);
Var
  iAbort: boolean;
  EHandle: boolean;
begin
  iAbort       := False;
  EHandle      := False;
  FButtonClick := Index;
  if (DataSource <> nil) and (DataSource.State <> dsInactive) then
  begin
    if not (csDesigning in ComponentState) and Assigned(FBeforeAction)
then
      FBeforeAction(Self, Index, iAbort, EHandle);
    if not iAbort then
    begin
      try
        with DataSource.DataSet do
        begin
          case Index of
            nbPrior: Prior;
            nbNext: Next;
            nbFirst: First;
            nbLast: Last;
            nbInsert: Insert;
            nbEdit: Edit;
            nbCancel: Cancel;
            nbPost: Post;
            nbRefresh: Refresh;
            nbDelete:
              if not ConfirmDelete or
                (MessageDlg(FMsgConfirmDelete, mtConfirmation,
                mbOKCancel, 0) <> idCancel) then Delete;
          end;
        end;
      except
        On E: Exception do
          if EHandle then
          begin
            if Assigned(FOnHandleError) then
              FOnHandleError(Self, E)
          end
          else
            raise;
      end;
      if not (csDesigning in ComponentState) and Assigned(OnClick)
then
        OnClick(Self, Index);
    end;
  end;
end;
constructor TDBNavigatorMax.Create(AOwner: TComponent);
Var
  x:integer;
begin
 
  inherited;
  {initialize values}
  FCaptions := TStringList.Create;
  FDataLink := TNavDataLinkMX.Create(Self);
 
  FMsgConfirmDelete := SDeleteRecordQuestion;
  //SetSpacing(FSpacing);
  SetMargin(-1);
  FNumGlyph := 2;
//  SetNumGlyph(2);
  //SetLayout(FLayout);
  //SetGlyphs(FGlyphs);
  FCaptions.Clear;
  for x := 0 to 9 do
    FCaptions.Add(DefaultCaption[x]);
  SetCaptions(FCaptions);
end;
destructor TDBNavigatorMax.Destroy;
begin
  FCaptions.Free;
  FreeAndNil(FDataLink);
  inherited;
end;
procedure TDBNavigatorMax.SetCaptions(const Value: TStrings);
var
  t: TNavigateBtn;
begin
  FCaptions := Value;
  for t:= Low(TNavigateBtn) to High(TNavigateBtn) do
  begin
    if (FShowCaptions) then
    begin
      if (Ord(t) < Value.Count) then
        Buttons[t].Caption := Value[Ord(t)]
      else
        Buttons[t].Caption := DefaultCaption[Ord(t)];
    end
    else begin
      Buttons[t].Caption := '';
    end;
  end;
  Invalidate;
end;
procedure TDBNavigatorMax.SetLayout(Value: TButtonLayout);
var
  t: TNavigateBtn;
begin
  FLayout := Value;
  for t:= Low(Buttons) to High(Buttons)do
    Buttons[t].Layout := Value;
  Invalidate;
end;
procedure TDBNavigatorMax.SetSpacing(Value: integer);
var
  t: TNavigateBtn;
begin
  FSpacing := Value;
  for t:= Low(TNavigateBtn) to High(TNavigateBtn) do
    Buttons[t].Spacing := Value;
  Invalidate;
 
end;
procedure TDBNavigatorMax.SetMargin(Value: integer);
var
  t: TNavigateBtn;
begin
  FMargin := Value;
  SetCaptions(FCaptions);
  for t:= Low(TNavigateBtn) to High(TNavigateBtn) do
    Buttons[t].Margin := Value;
  Invalidate;
end;
procedure TDBNavigatorMax.SetShowCaptions(const Value: boolean);
begin
  FShowCaptions := Value;
  SetCaptions(FCaptions);
end;
procedure TDBNavigatorMax.ActiveChanged;
var
  I: TNavigateBtn;
begin
  if not (Enabled and FDataLink.Active) then
    for I := Low(Buttons) to High(Buttons) do
      Buttons[I].Enabled := False
  else
  begin
    DataChanged;
    EditingChanged;
  end;
end;
procedure TDBNavigatorMax.DataChanged;
var
  UpEnable, DnEnable: Boolean;
  stEnable: boolean;
  IsEmpty: boolean;
begin
  stEnable := Enabled and FDataLink.Active and
      FDataLink.DataSet.CanModify;// and
      //not (FDataLink.DataSet.BOF and FDataLink.DataSet.EOF);
  IsEmpty := (FDataLink.DataSet.BOF and FDataLink.DataSet.EOF);
//  if not (FDataLink.DataSet.State = dsInsert) then
  if not FDataLink.Editing then
  begin
    UpEnable := Enabled and FDataLink.Active and not
FDataLink.DataSet.BOF;
    DnEnable := Enabled and FDataLink.Active and not
FDataLink.DataSet.EOF;
    Buttons[nbFirst].Enabled    := UpEnable;
    Buttons[nbPrior].Enabled    := UpEnable;
    Buttons[nbNext].Enabled     := DnEnable;
    Buttons[nbLast].Enabled     := DnEnable;
    Buttons[nbDelete].Enabled   := stEnable and not IsEmpty;
    Buttons[nbEdit].Enabled     := stEnable and not IsEmpty;
    Buttons[nbRefresh].Enabled  := stEnable and not IsEmpty;
  end
  else begin
    Buttons[nbFirst].Enabled    := False;
    Buttons[nbPrior].Enabled    := False;
    Buttons[nbNext].Enabled     := False;
    Buttons[nbLast].Enabled     := False;
    Buttons[nbDelete].Enabled   := not stEnable;
    Buttons[nbEdit].Enabled     := not stEnable;
    Buttons[nbRefresh].Enabled  := not stEnable;
  end;
end;
procedure TDBNavigatorMax.EditingChanged;
var
  CanModify: boolean;
  IsEmpty: boolean;
begin
  CanModify := Enabled and FDataLink.Active and
FDataLink.DataSet.CanModify;
  IsEmpty := (FDataLink.Eof and FDataLink.Bof);
  if FDataLink.Editing and CanModify then
//  if (FButtonClick in [nbEdit, nbInsert]) and (CanModify) then
  begin
    Buttons[nbFirst].Enabled   := False;
    Buttons[nbPrior].Enabled   := False;
    Buttons[nbNext].Enabled    := False;
    Buttons[nbLast].Enabled    := False;
    Buttons[nbEdit].Enabled    := False;
    Buttons[nbDelete].Enabled  := False;
    Buttons[nbInsert].Enabled  := False;
    Buttons[nbRefresh].Enabled := False;
    Buttons[nbPost].Enabled    := True;
    Buttons[nbCancel].Enabled  := True;
  end
  else begin
    Buttons[nbInsert].Enabled  := CanModify;
    Buttons[nbEdit].Enabled    := CanModify and not FDataLink.Editing
and
                                    not IsEmpty;
    Buttons[nbDelete].Enabled  := CanModify and not FDataLink.Editing
and
                                    not IsEmpty;
    Buttons[nbPost].Enabled    := CanModify and FDataLink.Editing;
    Buttons[nbCancel].Enabled  := CanModify and FDataLink.Editing;
    Buttons[nbRefresh].Enabled := CanModify;
  end;
end;
function TDBNavigatorMax.GetDataSource: TDataSource;
begin
  Result := FDataLink.DataSource;
end;
procedure TDBNavigatorMax.SetDataSource(const Value: TDataSource);
begin
  FDataLink.DataSource := Value;
  if not (csLoading in ComponentState) then
    ActiveChanged;
  if Value <> nil then
    Value.FreeNotification(Self);
end;
procedure TDBNavigatorMax.SetGlyphs(Value: TImageList);
var
  t: TNavigateBtn;
begin
  //Imposto le Icone, se ci sono, altrimenti quelle di default
  FGlyphs := Value;
  //if (csLoading in ComponentState) then exit;
  for t:= Low(TNavigateBtn) to High(TNavigateBtn) do
  begin
    if Assigned(FGlyphs) then
    begin
      if (Ord(t) < FGlyphs.Count) then
      begin
        Buttons[t].Glyph     := nil;
        Buttons[t].NumGlyphs := FNumGlyph;
        Buttons[t].Layout    := FLayout;
        FGlyphs.GetBitmap(Ord(t), Buttons[t].Glyph);
      end;
    end
    else begin
      InitButtons;
    end;
  end;
  Invalidate;
end;
procedure TDBNavigatorMax.SetNumGlyph(const Value: integer);
begin
  FNumGlyph := Value;
  if not (csLoading in ComponentState) then
    SetGlyphs(FGlyphs);
end;
{ TNavDataLinkMX }
constructor TNavDataLinkMX.Create(ANav: TDBNavigatorMax);
begin
  inherited Create;
  FNavigator := ANav;
end;
destructor TNavDataLinkMX.Destroy;
begin
  FNavigator := nil;
  inherited Destroy;
end;
procedure TNavDataLinkMX.EditingChanged;
begin
  if FNavigator <> nil then FNavigator.EditingChanged;
end;
procedure TNavDataLinkMX.DataSetChanged;
begin
  if FNavigator <> nil then FNavigator.DataChanged;
end;
procedure TNavDataLinkMX.ActiveChanged;
begin
  if FNavigator <> nil then FNavigator.ActiveChanged;
end;
end.

 SBAGLIATO !!!!
Ehm, sono d'accordo, ma perché tanta violenza? :)
E' una zozzeria, ma è un altro modo per non usare (almeno in modo visuale)
il DBN.
Cambiando le icone (che in fondo era quello che aveva chiesto lui, ok), non
cambia la sostanza, cioè che il DBN fa schifo ;)
--
Jax
====
Non te la fare con chi non è mai soddisfatto.

 zozzeria... ;-P
sarà pure na zozzeria ma tutto l'ambaradan che ho cuttato di seguito per
cambiare otto icone? :o) Allora dico la mia!!! Editare il file dbctrls.res
con l'image editor?
[megacut]
-- 
Ciao, Anto', [37, 143, AQ] 
MB C SC 220 CDI Magma Rot
"Di sempre cio' che senti e fai cio' che pensi."
    G.G. Màrquez

Attenzione alla licensa !!
Con tutto il rispetto,ma perché 500 linee quando se ne possono usare
4?
var
  I: Integer;
begin
  for I := 0 to DBNavigator1.ControlCount - 1 do
    if DBNavigator1.Controls[I] is TNavButton then
ImageList1.GetBitmap(ord(TNavButton(DBNavigator1.Controls[I]).Index),
TNavButton(DBNavigator1.Controls[I]).Glyph);
-- 
"La velocità luce non è sufficiente Comandante Nunziatella, 
dobbiamo passare alla velocità smodata!"

 TNavButton(DBNavigator1.Controls[I]).Glyph);
Giusto, per arrivare alla soluzione ci sono piu' strade, io preferisco
ereditare e fare una nuova classe, magari te preferisci sovrascivere
le icone, entrambe le soluzioni sono valide; con tutto il rispetto non
credo la soluzione proposta di nascondere un DBNavigator e 'pilotarlo'
con dei bottoni ad hoc sia "object oriented", queste soluzioni non
fanno  che (a lungo termine) generare problemi.
Magari fra qualche tempo l'autore viene fuori a dire non risco ad
utilizzare il post perchè il dbnavigator mi risponde picche, o magari
richiamando il meotodo del DB sbagli a passare il sender e ti becchi
un Access Violation, poi sei qui a pingere perchè non funziona ?.
Il tono era accesso, e me ne scuso se a qualcuno ha dato fastidio, ma
e' per sottolineare il fatto che non se ne puo' piu di leggere post
che gridano aiuto per codice scritto male, se scrivessimo secondo
standard la meta' dei problemi sarebbe risolta in partenza.
Massimo

standard la meta' dei problemi sarebbe risolta in partenza.
Nessun problema, ma pensaci un pochino: arriva il "Bravo Lu' " di
turno che ti dice "u qui, tu la, io qui, io la" il mio primo impulso
era stato quello di mandarti a cagare O_o !
Alla prossima ;-)


standard la meta' dei problemi sarebbe risolta in partenza.
Hai ragione, quanto hai ragione!
MA...
Ma il problema non e' cosi' semplice: spesso ci si arrabatta con codice poco
OOP per due motivi fondamentali
1- tempo
2- studio
La maggior parte di noi non ha tempo, e' sempre di corsa, e spesso le prime
bozze di codice che poi andrebbero messe a posto, finiscono col diventare il
codice definitivo, non per colpa ma per esigenze.
Io sto scrivendo in fretta e furia un programma usando codice ridondante,
copia incolla per intendersi, perche' cosi' funziona e lo sviluppo e' piu'
veloce e cosi', *forse*, riusciro' a consegnare a fine mese perche' l'azienda
deve fatturare per motivi di contratto.
Se stessi li' ad ingegnerizzare e strutturare tutto quello che faccio in
maniera limpida e pulita, OOP al massimo, non consegnerei prima di Agosto,
pagando cosi' penali e sfiducia nel cliente.
Purtroppo lo so anche io che un perfetto codice OOP, pagato il costo di tempo
iniziale, poi diventa manutenibile in tempo zero; pero' non puoi dal punto di
vista pratico andare dal cliente e dirgli "3 mesi per questa modifica",
perche' oltre al costo esorbitante, quello si trova un altro programmatore
smanioso di vendere causa crisi del settore che glie lo fa "quick & dirty" in
un terzo del tempo.
L'altro parametro preso da me in considerazione e' lo studio: perche' molti
programmatori non usano i thread? Perche' nessuno (tranne qualche GRANDE che
ho la fortuna di conoscere) usano i patterns ?
Perche' programmare OOP come intendi tu, ci vuole molto studio, e non tutti
sono cosi' bravi ne' hanno tempo di studiarsi libri di notte e programmando di
giorno. A dimostrazione il fatto che tu stesso per una modifica OOP come l'hai
definita tu, hai preso e copia incollato il codice. dimmi tu se dovevi
scriverla da zero quanto ci mettevi...
La differenza tra la teoria e la pratica sta tutta li': la teoria riempie
molte pagine di libri e molte teste, la pratica e' quella che devi fatturare
(e tanto) scrivendo con le tue mani codice, per dare da mangiare alla famiglia
a fine mese. Copiando e incollando, se necessario.
:-))
Ciao!
-- 
Morde. (
mo...@despammed.com
)
M-List di icld: 
http://it.groups.yahoo.com/group/icld/
Firefox, il miglior browser: 
http://www.gxware.org/mozilla/

 Alla prossima ;-)
?!

problema, che cambia !
Vedi, mi dai tanto l'impressione del ragazzino che si è riempito la
bocca con qualche libro di OO e adesso crede di avere visto la
Madonna, ne riparliamo tra una venticinquina d'anni ok?
Cutti e pasti una accozzaglia di codice presentandoti come se fossi il
Grande Puffo in persona, ti si fa notare garbatamente che il badile
per togliere un moscerino dall'occhio è eccessivo, ti faccio notare
successivamente che *se proprio* voui ereditare tutta la classe basta
modificare *un metodo* e non ventisette e continui?
In ogni modo, proprio per evitarti di proseguire questa noiosa e poco
interessante discussione, ti ricordo che le 4 righe che avevo
suggerito (o altre 100 soluzioni alternative tutte di 4 righe) le puoi
tranquillamente aggiungere in un constructor che eredita il
constructor della classe TDBNavigator per la buona pace degli oopisti
a tutti i costi.


 Vedi, mi dai tanto l'impressione del ragazzino che si č riempito la
Dai su, non litigate. Non usiamo il TDBNavigator e viviamo felici ;)
--
Jax
====
Il malcontento č il primo passo verso il progresso. (Wilde)

 Dai su, non litigate. Non usiamo il TDBNavigator e viviamo felici ;)
Io avevo giŕ proposto l'uso delle "Standard Action" fruibili dal 
componente TActionList e associabili a qualsiasi tipo di controllo 
visuale che presuppone l'esecuzione di un comando, ma nessuno mi ha 
considerato. :-)


 considerato. :-)
Povero Calimero... ;)))
--
Jax
====
Amore non è guardarsi a vicenda, è guardare insieme nella stessa
direzione.(Antoine De Saint-Exupéry)

 Povero Calimero... ;)))
Il messaggio era questo...LOL! :-D
