Newsgroup: it.comp.lang.delphi
Titolo: domanda turpe

Salve a tutti...
Ho una domanda turpe per voi esperti e spero che voi abbiate una risposta 
per me! ;-)
Tutti i componenti hanno una proprietà chiamata Tag molto versatile che può 
essere usata per salvarci dei valori che possono servire durante 
l'esecuzione del progetto.
Vorrei aggiungere una proprietà di tipo stringa (es. Comment) ad ogni 
componente che mi permetta di fare la stessa cosa che mi permette di fare 
Tag, ma con valori di tipo stringa.
Armato di buona volontà ho aperto l'unità Classes in cui è contenuta la 
definizione di TComponent ed ho aggiunto quanto segue:
  private
    FComment: String;
  published
    property Comment: String read FComment write FComment default '';
  end;
a parte che avrei potuto fare come segue (forse più corretto):
  private
    FComment: String;
    procedure SetComment(Value: String);
  published
    property Comment: String read FComment write SetComment default '';
  end;
e a parte che non so se si possa dire _default ''_, non sono proprio 
riuscito a ricompilare l'unità Classes...
Come devo fare? Grazie in anticipo per ogni vostra gentile risposta,
   Stefano
ps: spesso la proprietà Hint fa all'uopo, ma nel mio caso è già utilizzata 
proprio come hint... 

La butto li al volo.
Un vettore di stringhe 'globale' o 'Statico' di dimensioni pari al numero di
componenti o di control.
Var
...
 s : Array [1..100] Of String ;
...
dove l'indice del vettore è il Tag di ogni control.
per cui
...
s [Edit1.Tag] := 'Ciao' ;
...
e viceversa.
Ciao
Mario - (
mari...@inwind.it
)
--------------------------------
Inviato via 
http://arianna.libero.it/usenet/

[...]
Che vuol dire "non sono proprio riuscito a ricompilare
l'unitą Classes" ... ?
Che errori di compilazione hai?
Hai fatto una copia del .pas nel tuo progetto ho stai
ricompilando lal unit originale nelle cartelle di
installazione di Delphi?
	Ciao
	MassimoB
 
---------------------------
http://www.massimobeschi.it/

questa è la scappatoia che sto utilizzando adesso...
amici "puristi" m'hanno detto che spreca molte risorse...
e di usare ResourceString (o StringResource?)...
non ho trovato nulla in merito, qualcuno può spiegarmi di cosa parlano?
grazie ancora,
    Ste

 Tag, ma con valori di tipo stringa.
scusa se faccio un passo indietro.: xche?
Magari, se spieghi sinteticamente i termini del problema vien fuori 
qualche idea...
AS

 l'unità Classes" ... ?


   Stefano


 definizione di TComponent ed ho aggiunto quanto segue:
Non e' buona norma modificare i sorgenti della VCL.
Se devi aggiungere una proprieta' ad un oggetto (o a piu' oggetti)
devi usare l'ereditarieta'.
I sorgenti della VCL vanno modificati solo in caso di BUG.
Nel caso, spiega perche' hai bisogno di una simile "espansione".
Ciao
P.S.: per favore, la prossima volta usa un subject piu' sensato.
ACSH.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

installazione di Delphi?
Non so se gli basta ricompilare Classes, richia di dover ricompilare
l'intera VCL perché il compilatore dovrebbe vedere che la sezione
interface è stata modificata in data successiva a quella delle altre DCU...
È un lavoro "rischioso" anche perché, il codice è compilabile solo con una
versione modificata della VCL, e occorre "riportare" le modifiche ogni
volta che si cambia versione di Delphi, oltre ai rischi di eventuali
conflitti con componenti di terze parti che introducessero proprietà simili.
Ci sono metodi meno "intrusivi" per fare la stessa cosa. Ad esempio un
componente a parte che permetta, anche a design time, di associare una
stringa ad un TComponent. Ci vuole poco a farlo. Non sempre ereditare è la
scelta migliore, spesso l'utilizzo del pattern composition o simili è una
scelta migliore.
In alternativa si può creare una classe che contenga Tag e Comment, ed
assegnare le istanze al tag (è a 32 bit, può contenere anche un
riferimento ad una istanza), solo che poi bisogna ricordarsi di farne il
free, ed effettuare un cast per leggere i dati.
Luigi D. Sandon - D&amp;D Support Team
--- posted by geoForum on 
http://www.delphiedintorni.it

Ops... non ho fatto caso all'errore che mi dava il compilatore, ma ho 
proceduto come segue:
* ho creato una copia di Classes.pas nella cartella del mio progetto
* ho provato a compilare e lui mi ha risposto che la unità tal dei tali è 
stata compilata con un'altra versione di Classes.pas; ho creato quindi nella 
cartella del mio programma una copia di ogni unità che mi dava errore.
* alla fine il mio progetto viene compilato ed eseguito, solo che a questo 
punto io mi aspettavo di trovare la proprietà Comment dentro all'Object 
Inspector per ogni componente che selezionavo mentre non c'è!!! Si vede che 
l'Object Inspector guarda comunque ai dcu nelle posizioni originali... devo 
andare a sostituirli uno alla volta???
Grazie ancora,
   Ste 

--- posted by geoForum on 
http://www.delphiedintorni.it
	Ciao
	MassimoB
 
---------------------------
http://www.massimobeschi.it/

   Ste 


Dunque, breve premessa.
Il programma in esame è un utility che assiste l'utente nella compilazione 
di un certo tipo di report di documento. Questi documenti possono essere 
redatti in due modi, quindi il programma permette l'inserimento del report 
nella sua forma standard, lo visualizza e se serve lo converte nell'altra 
forma. Il programma, inoltre, deve permettere di scegliere la lingua in cui 
visualizzare il report (tipicamente inglese o italiano, ma deve essere 
possibile inserire altre lingue). Se viene scelta una nuova lingua chiede e 
memorizza tutti i termini che sono necessari per la traduzione.
Attenzione però, l'interfaccia del programma deve rimanere in italiano, 
mentre devono cambiare solo le etichette e i dati contenuti nei controlli 
che permettono l'inserimento dei dati.
Ho settato a 1, quindi, tutte le proprietà Tag dei componenti che cambiano 
selezionando una nuova lingua, ho pensato di usare la proprietà Hint per 
memorizzare ed avere sottomano nell'Object Inspector la stringa in inglese 
di testo relativa ad ogni controllo, ed ho scritto il seguente codice:
const
  NeedTranslation = 1;
  DefaultLanguage = 'English';
var
  CurrentLanguage: String;
  // Contiene il nome della lingua scelta per il report, es: 'Italiano' o 
'English', ecc.
for i := 0 to Pred (ComponentsCount) do
  if Components[i].Tag = NeedTranslation then
    begin
      if Components[i] is TLabel then
        with Components[i] as TLabel do
          if CurrentLanguage = DefaultLanguage then
            Caption := Hint
          else
            Caption := Translate (Hint);
      // ecc. per gli altri tipi di componenti
    end;
function TfMain.Translate (aTerm: String): String;
// questa funzione presuppone che esista e sia stato inizializzata:
//   var
//     LanguageFile: TIniFile;
var
  aString: String;
begin
  if Assigned (LanguageFile) then
    begin
      aString := LanguageFile.ReadString ('Glossary', aTerm, '');
      if aString = '' then
        case InputQuery ('Glossario', Format ('Il termine %s non è stato 
trovato nel glossario %s.'#13'Inserire la traduzione:', [aTerm, 
CurrentLanguage]), aString) of
          True:  if aString = '' then
                      aString := aTerm
                    else
                      LanguageFile.WriteString ('Glossary', aTerm, aString);
          False:  aString := aTerm;
        end;
  else
    aString := aTerm;
    Result := aString;
end;
Per finire, un file di glossario è fatto così:
[General]
LanguageName=Italiano
[Glossary]
Amount=Quantità
ecc. ecc.
Il problema qual è? Il problema è che il programma usa gli Hint... Il metodo 
TApplication.OnHint è stato settato in modo che l'Hint lungo venga 
visualizzato in una StatusBar. I componenti con Tag <> 0 e Hint che contiene 
il termine Inglese (es.: Label1.Hint := 'Amount';) per la traduzione anche 
se hanno ShowHint e ShowParentHint settati a False, mostrano comunque il 
valore contenuto in Hint nella Statusbar. Non sono riuscito in alcun modo ad 
evitare la cosa. Così avevo pensato di aggiungere ad ogni TComponent (ed ad 
ogni suo derivato) una proprietà Comment, come Tag, in cui mettere il valore 
in Inglese da tradurre.
Ecco fatto, prolisso come al solito, ma credo che fosse necessario per 
spiegare bene il problema.
Scusate per il post lungo e grazie in anticipo anchse solo per esservi presi 
la briga di leggere queste righe.
Perdonate eventuali errori e il pessimo italiano,
    Stefano 

Anche qui sono al buio :)
I pattern sono delle soluzioni, diciamo così, consigliate, a problemi
ricorrenti di programmazione. Sono state classificate, e ad ogni soluzione
è stato assegnato un nome. Attenzione, non sono algoritmi belli e pronti,
ma delle specifiche di design.


--- posted by geoForum on 
http://www.delphiedintorni.it
	Ciao
	MassimoB
 
---------------------------
http://www.massimobeschi.it/

Scusa, ma non è più furbo usare il nome del componente?
Ti fai un file dove per ogni componente da tradurre hai le caption in
inglese e in italiano, che so qualcosa tipo:
[Italian]
LabelPippo=Pippo
[English]
LabelPippo=Goofy
Un'intera sezione la puoi agevolmente caricare in una TStringList, e
accedervi con le proprietà Names e Values.
A questo punto se hai il tag = NeedsTranslation 
Caption := TranslatedStringList.Values[Components[i].Name]
Questo però ti obbliga ad avere stringhe ripetute se due componenti usano
lo stesso nome...
In alternativa puoi assegnare ad ogni stringa un codice numerico diverso
[Italian]
1=Pippo
2=Topolino
[English]
1=Goofy
2=Mickey Mouse
E assegnare il codice nel tag...
Questi sistemi sono però un po' meno "automatici" del tuo. In cambio
supportano più di due linguaggi...
Per ultima cosa potresti usare un tool di localizzazione (Multilizer o
simili), controllando che permetta di localizzare solo parte
dell'applicazione.


e di usare ResourceString (o StringResource?)...
L'array è brutto perché poco flessibile, userei magari una StringList o
simili, finché le stringhe non sono migliaia o milioni... :)
Oppure puoi salvarle come risorse e caricarle solo quando ti servono. La
parola chiave resourcestring permette di dichiarare delle costanti di
stringa che vengono memorizzate nelle risorse dell'eseguibile anziché che
nel segmento codice. Ogni risorsa ha un nome e un numero associato, e puoi
caricarle quando ti servono con LoadResource (anche LoadString per le
stringhe). Il problema con resourcestring è che non ti permette di
asseganre il numero, lo puoi vedere aprendolo con un editor di risorse ma
non è detto che non cambi. Oppure puoi preparare il file di risorse
separatamente, e caricarlo quando ti serve (puoi anche fare una DLL di
sole risorse da caricare dinamicamente in base alla lingua selezionata).


andare a sostituirli uno alla volta???
No, l'IDE e l'Object Inspector usano i package... (VCLXX.BPL, in questo
caso) e quelli non puoi ricompilarli perché Borland - per buone ragioni -
non fornisce i sorgenti.


ereditare o modificare la classe stessa.
No, con Delphi in questo momento non è possibile aggiungere una proprietà
ad una classe esistente tramite un'altra, l'idea base era quella di usare
due classi cooperanti invece di modificare la classe base.


Sono punti di vista interessanti, ma non fanno completamente al caso mio...
Tra le varie cose, il programma deve permettere la selezione di alcuni 
elementi da un elenco di stringhe a cui deve essere associato un numero, 
deve permettere la modifica dell'elenco di elementi selezionati e deve 
creare il report contestualmente agli elementi selezionati.
Parte dell'interfaccia ad esempio è composta da:
* un TLabel (Tag settato, Hint = 'Elements:')
* un TComboBox: contiene l'elenco di stringhe tra cui scegliere, deve 
permettere l'aggiunta di nuove stringhe (OnAcceptText) ed ognuna di queste 
strignhe deve poter essere modificata (Tag settato)
* un TLabel (Tag settato, Hint = 'Amount:')
* un TSpinEdit: contiene il numero da assegnare alla stringa selezionata nel 
TComboBox. E' un numero e non c'è bisogno di traduzioni!
* un TButton il cui Caption è 'Aggiungi': non c'è bisogno di tradurre è un 
elemento dell'interfaccia e deve sempre rimanere in italiano. Se viene 
premuto aggiunge ad un TListBox una stringa composta dalla stringa del 
TComboBox e il numero convertito in testo del TSpinEdit.
* un TListBox: come detto contiene le stringhe selezionate. Tag è settato: 
la parte alfabetica della stringa deve essere di ogni stringa deve 
rispecchiare la lingua corrente.
* un TButton il cui Caption è 'Elimina': niente traduzione, serve per 
eliminare la stringa attualmente selezionata nel TListBox.
* un TRichEdit: contiene il report. Ogni volta che viene modificato 
qualcosa, il report viene rigenerato, in modo che rispecchi le modifiche. Il 
suo contenuto è completamente nella lingua selezionata.
Questo dovrebbe spiegare perchè non posso utilizzare il formato 
LabelPippo=Pippo per il file di lingua. Inoltre, uno stesso termine può 
essere utilizzato parecchie volte quindi preferirei evitare  ripetizioni 
inutili...
Infine vorrei tenere separate le lingue tra di loro. Un file ini corrisponde 
ad una ed una sola lingua. Così se dovessi aver bisogno del report in 
spagnolo, mi basterebbe chiedere al programma di aggiungere lo spagnolo e 
lui mi chiederebbe la traduzione in spagnolo dei termini necessari, senza 
ripetizioni ridondanti. In caso di problemi, saprei che tutto ciò che 
riguarda lo spagnolo è nel file espanol.ini (editarlo o cancellarlo... farei 
tutto in un lampo).
A puro scopo speculativo, mi viene in mente ora che potrei complicare un po' 
il mio codice per permettere non solo di tradurre le cose relative al 
report, ma pure l'interfaccia utente per eventuali utenti stranieri, usando 
poi due controlli per selezionare la lingua dell'interfaccia e del report 
separatamente. Sia:
const
  UIItem = 1;
  ReportItem = 2;
Quando cambio la lingua dell'interfaccia utente faccio un ciclo per 
esaminare tutti i componenti, cercando quelli il cui Tag vale UIItem, quando 
cambio la lingua per il report, invece, faccio la stessa cosa, ma 
confrontanfo ogni Tag con ReportItem.
Non ho mai utilizzato strumenti di Internazionalizzazione, non so nemmeno da 
che parte iniziare a guardare, so che Delphi ne ha uno proprietario ma non 
l'ho mai studiato. Dubito comunque che permetta di fare quello che ho in 
mente io, soprattutto appoggiandosi ad una sola funzione.
Insomma... BOH!!!
Ciao,
   Stefano 

 mente io, soprattutto appoggiandosi ad una sola funzione.
Mi intrometto per dire che anche io, in passato, avevo iniziato un 
progetto di questo tipo realizzando un componente di internazionalizzazione.
La soluzione che avevo realizzato prevedeva l'uso delle funzioni della 
RTTI di Delphi (messe a disposizione dalla unit /Typinfo.pas/) per 
esplorare le proprietŕ della form in cui il componente veniva 
posizionato, inclusi i componenti e i controlli ivi contenuti e relativi 
figli.
Le proprietŕ ricondubicili ad una stringa (string, TCaption, TStrings, 
TCollection contenenti TCollectionItem con proprietŕ del tipo descritto 
e cosě via) venivano "mappate" e memorizzate in una struttura ad oggetti 
gerarchicamente strutturata ad albero interna al componente.
Inoltre, venivano caricati file di testo esterni che contenevano le 
traduzioni dei testi sui controlli nelle varie lingue.
Selezionando una lingua, si provvedeva a caricare tali stringhe; ove si 
trovavano corrispondenze nella struttura gerarchica, le stringhe 
venivano sostituite e l'operazione si ripeteva automaticamente ad ogni 
cambio del linguaggio selezionato.
La soluzione č stata poi abbandonata per il fatto che sono stati 
successivamente introdotti i Frame, i quali dovevano essere gestiti in 
modo diverso, poichč si trattava di un'unitŕ contenitrice diversa dal 
form classico.
L'automatismo funzionava correttamente ma, come avviene in ogni 
progetto, emergono sempre dei "casi particolari"; per poterli gestire, 
ciascun caso particolare doveva divenire un "caso frequente" e 
consentire l'interazione attraverso eventi o altri espedienti per 
modificare il comportamento predefinito del componente.
Infine, senza un buon editor a designtime in grado di presentare i 
controlli in forma gerarchica e consentire di introdurre comodamente 
stringhe nei diversi linguaggi, la compilazione del file diventata 
difficoltosa, con la necessitŕ di revisionare frequentemente gli 
identificatori delle stringhe, la difficoltŕ di aggiungere "macro" 
speciali e altro ancora.
In definitiva, il "mostro" diventava troppo grande per la semplicitŕ del 
suo compito e del progetto in cui doveva convivere.
Attualmente, nello sviluppo di componenti per la localizzazione, 
preferisco rendere piů comodo il reperimento di stringhe dalla base dati 
"custom" che utilizzo per inserire i testi semplificando la 
codifica...ma prelevo le stringhe attraverso righe esplicite di codice, 
senza usare un automatismo come quello che ho descritto.
Nonostante il componente precedente fosse mastodontico, la versione 
semplificata mi "gusta" di piů perchč l'assenza di complessi automatismi 
lo rende piů sicuro e affidabile. :-)
Concludendo, prima di imbarcarti nella modifica dei sorgenti della VCL, 
valuta se non esistano soluzioni piů semplici da realizzare per il 
progetto che stai sviluppando. :-)
Per dirlo con una frase sola, non fare il mio stesso errore! :-D
-- 
Marco «Alka» Breveglieri
  ABLS Team S.n.c. - Software & Web
  Via De Gasperi, 14
  42019 Scandiano (Reggio Emilia)
 
http://www.abls.it

Un'ultima annotazione: tu utilizzi come "chiave" per la ricerca delle
stringhe la stringa stessa. Non č una buona chiave perché nulla ti
garantisce che sia univoca. Potresti trovarti con una parola che va
tradotta con due parole diverse. Tanto per farti un esempio con la prima
parola che mi viene in mente, la parola inglese "net" significa sia "rete"
che "netto". Se ti capitasse un caso simile e dovessi usare entrambi i
significati nella lingua tradotta, avresti un problema...


> la parola inglese "net" significa sia "rete" che "netto".
vero, ma per definizione, ho tutti termini univoci...
adesso mi faccio un paio di considerazioni tra me e me, e poi vi faccio 
sapere come ho risolto!
Stefano 

 definizione di TComponent ed ho aggiunto quanto segue:
Mai modificare i sorgenti forniti!!
In questo caso dovresti procedere cosi':
Una possibilita' e' ereditare da ogni componente un nuovo componente che 
abbia la stringa in piu'. E' laborioso se devi fare molti diversi controlli.
L'altra, che e' quella che userei io, e' di castare l'attributo tag come 
pointer e attaccarci una classe.
Es:
TStringContainer = class
  private
    fS:String
  public
    property MyString:string read fs write fs;
    constructor Create(s:string);
end;
e poi:
button1.tag:=integer( TStringContainer.create('ciccio')  );
per leggere:
MyStringContainer := TStringContainer(button.tag);

 proprio come hint... 
No comment...
Andrea

No queste soluzioni (la tua come quella suggerita da MSX) saranno pure 
eleganti, ma inutilizzabili...
Il mio scopo era quello di avere direttamente nell'Object Inspector, al 
momento della progettazione dell'interfaccia utente, tutto ciň che poteva 
servirmi per il problema delle lingue...
A tirar dentro i puntatori non si ottiene _MAI_ qualcosa di semplice...
Ste 

 Tag, ma con valori di tipo stringa.
Non ho seguito l'intera discussione ma se ti serve usare la proprietà tag 
per riferimenti a stringhe una soluzione potrebbe essere la seguente:
Panel1.Tag := Integer(PChar('123'));
ShowMessage(PChar(Panel1.Tag));
Acqua 

"Stefano Bragaglia" ha scritto nel messaggio
[cut]
Ammetto di non aver letto nel dettaglio tutta la discussione, ma ci sono una 
serie di problematiche nella modifica diretta della VCL:
- è illegale;
- la tua modifica potrebbe non essere compatibile con componenti di terze 
parti;
- applicando una qualunque patch (questo è un pò meno scontato, ma non 
impossibile) potresti doverla riscrivere da zero.
Un ottimo modo di procedere è quello di derivarti, per ogni componente a cui 
ti interessa aggiungere le nuove proprietà, un tuo componente custom, in 
modo da non intaccare la quella che è la VCL standard fornita da Borland.
E' un lavoraccio, lo so, ma trattandosi di una proprietà gestita sempre allo 
stesso modo, con uno o due file .inc ed un pò di direttive di compilaione $I 
puoi raggiungere velocemente lo scopo.
Diversamente, perchè non pensi a progettarti un componente non visuale 
"Container" che tra le sue proprietà punti a tutti gli oggetti che ti 
interessa gestire (magari una lista di TComponent o di TControl o una lista 
di oggetti al cui interno ci sia un riferimento ancora al TComponent, ecc.). 
Invece di interrogare direttamente gli oggetti, potresti rivolgerti a 
quest'ultimo e sarebbe appunto quest'ultimo il responsabile della 
visualizzazione nelle varie lingue (immagino scorrendo la lista di 
componenti) Sviluppandolo da zero, potresti gestire le proprietà nell'Object 
Inspector come meglio credi.
Sicuramente è una soluzione molto piu' pulita.
Ciao,
Gianluca. 

Luigi D. Sandon - D&amp;D Support Team
	Ciao
	MassimoB
 
---------------------------
http://www.massimobeschi.it/

Ti allego in codice che a me con delphi 7 ent non ha dato problemi di sorta.
Devi ricordare di memorizzare il package se no perdi l'installazione.
Ovviamente si puo' provare ad eseguire più in alto (nell'albro genealogico)
le modifiche effettuate per la classe tButton StdControl ma possono
ricomparire i problemi incontrati in precedenza.
Ciao
Mario - (
mari...@inwind.it
)
...
unit MarioButton;
interface
uses
  SysUtils, Classes, Controls, StdCtrls;
Type
  tEnumType = ( etUno, etDue, etTre, etQuattro, etCinque ) ;
type
  TMarioButton = class(TButton)
  private
    fIntegerProp : Integer ;
    fRealProp : Real ;
    fBooleanProp : Boolean ;
    fStringProp : String ;
    fEnumProp : tEnumType ;
  protected
  public
  published
    Property IntegerProp : Integer Read fIntegerProp Write fIntegerProp ;
    Property RealProp : Real Read fRealProp Write fRealProp ;
    Property BooleanProp : Boolean Read fBooleanProp Write fBooleanProp ;
    Property StringProp : String Read fStringProp Write fStringProp ;
    Property EnumProp : tEnumType Read fEnumProp Write fEnumProp ;
  end;
procedure Register;
implementation
procedure Register;
begin
  RegisterComponents ( 'MieClassi', [TMarioButton] ) ;
end;
end.
--------------------------------
Inviato via 
http://arianna.libero.it/usenet/

A me quello che segue gira.
Vedi tu se ti può essere utile.
Ciao
Mario - (
mari...@inwind.it
)
unit MyComponent;
interface
uses
  SysUtils, Classes;
Const
  MAI = 'ABC' ;
type
  TMyComponent = class(TComponent)
  private
    fStringa : String ;
  protected
  public
    Constructor Create ( AOwner : tComponent ) ; Override ;
    Destructor Destroy ; Override ;
    Procedure SetStringa ( Const Valore : String ) ;
  published
    Property Stringa : String Read fStringa Write SetStringa ;
  end;
procedure Register;
implementation
// __________________________________________________
Constructor TMyComponent.Create ( AOwner : tComponent) ;
Begin
  Inherited Create ( AOwner ) ;
  SetStringa ( MAI ) ;
End ;
// _________________________________________
Destructor TMyComponent.Destroy ;
Begin
  fStringa := '' ;
  Inherited Destroy ;
End ;
// __________________________________________________________
Procedure TMyComponent.SetStringa ( Const Valore : String ) ;
Begin
  If FStringa <> Valore Then FStringa := Valore ;
End ;
// _________________
Procedure Register ;
Begin
  RegisterComponents('MieClassi', [TMyComponent]);
End ;
END.
