Lazarus For Delphi Users/pt

From Free Pascal wiki
Revision as of 19:47, 12 January 2012 by Jrxds (talk | contribs) (→‎TCustomTreeView/TTreeView)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

Deutsch (de) English (en) español (es) français (fr) 日本語 (ja) 한국어 (ko) português (pt) русский (ru) slovenčina (sk)

Delphi -> Lazarus

Lazarus é uma ferramena de desevolvimento rápido de aplicações (RAD) como o Delphi. O que significa que ela contém uma biblioteca de componentes visuais e uma IDE. A biblioteca de componentes do Lazarus (LCL) é muito parecida com a do Delphi que é a VCL. Muitas unidades, classes e propriedades tem o mesmo nome e funcionalidade. Com isto converter entre eles é fácil. Mas Lazarus "não" é um 'clone do Delphi de código aberto'. Não espere 100% de compatibilidade.

As grandes diferenças

Lazarus é um software completamente de código aberto, escrito independente de plataforma, que utiliza o compilador Free Pascal (FPC). O FPC funciona em mais de 15 plataformas. Dentre elas, podemos citar o Windows (32 bits), o Linux, o FreeBSD e o MacOSX, mas, nem todos os pacotes e bibliotecas estão portados.

ATENÇÃO!!! O Lazarus não está completo, como não está este texto. Nós sempre procuramos novos desenvolvedores, geradores de pacotes, portadores e escritores de documentação.

Delphi IDE -> Lazarus IDE

Projetos

O arquivo principal de uma aplicação Delphi é o .dpr . Enquanto que para o Lazarus é o .lpi (Lazarus Project Information - informação do projeto do lazarus). Mas, um .dpr no Delphi contém o código fonte do programa principal, informações das unidades utilizadas e diretivas de compilação, enquanto que o arquivo .lpr no Lazarus contém o código fonte do programa principal e o restante fica na .lpi .

Por exemplo:

Delphi armazena os caminhos das unidades no arquivo .dpr . Pela instância: unit1 in 'path/Unit1.pas'. Este 'in' especifica os caminhos das unidades para o Delphi e não está pronto para ser usado na Lazarus IDE. Não o use. Use preferivelmente os trajetos (caminhos) da unidade nas opções do compilador.

Uma importante regra: há sempre um projeto. Somente feche um projeto para sair do Lazarus ou abrir outro projeto. É porque um projeto Lazarus também é uma "sessão". Isto significa que o corrente editor indica também para armazenar no arquivo .lpi e são restaurados quando você reabre o projeto. Por exemplo, você está debugando um projeto, indica vários pontos de parada e marcadores. Você pode salvar o projeto a qualquer momento, fechar o Lazarus ou abrir outro projeto. Quando você reabrir o projeto, mesmo em outro computador, todos os seus pontos de parada, marcadores, arquivos abertos, posições do cursor, histórico de pulos, ... são restaurados.

Editor de Código

Aproximadamente todas as teclas e atalhos podem ser definidos em environment->editor options->key mappings

A IDE (ambiente de desenvolvimento) do Lazarus tem várias ferramentas para fontes. Muitas delas são parecidas e trabalham de forma similar ao Delphi. Mas há uma importante diferença: Lazarus não usa o compilador para pegar informação do código. Ele interpreta os fontes diretamente. Isto tem muitas vantagens:

O editor de fonte trabalha com "comentários". Para Delphi os comentários no fonte são somente espaços entre o código. Nenhum comentário do código trabalha aqui e quando o código novo é automaticamente introduzido, seus comentários se perderão. Embora isto não seja completamente garantido, trabalha frequentemente. E quando o código novo é introduzido, o IDE usa algumas heuristicas para manter o comentário e codificá-lo junto. Por exemplo, isto não irá dividir a linha: "c:char; // comentário".

Delphi tem "Completar Código"(Ctrl+Space) é chamado "Identificar Completar" sobre o Lazarus. O Lazarus termo "Completar Código" tem uma característica, combinando "Completar Automaticamente Classe"(mesmo sobre Delphi), "Completar Variável Local" e "Completar Associação de Evento". Todos deles são invocados por Ctrl+Shift+C e a IDE determina pela posição do cursor, o que significa.

Exemplo para Completar Variável Local

Assuma que você tenha criado um novo método e escrito o seguinte "i:=3;"

procedure
TForm1.DoSomething;
begin
i:=
3
;
end
;

Posicionando o cursor sobre o identificador "i" e precionando Ctrl+Shift+C pegará:

procedure
TForm1.DoSomething;
var
i: Integer;
begin
i:=
3
;
end
;

Exemplo para Completar Associação de Evento

Um ótimo recurso do Object Inspector é automaticamente criar métodos. O mesmo você pode pegar no editor de fonte.
Por Exemplo:

Button1.OnClick:=

Posicione o cursor atrás do operador de atribuição ":=" e precione Ctrl+Shift+C.

"Completar Palavras" Ctrl+W

Este trabalha igualmente ao "Identificar Completar", mas não trabalha em identificadores do Pascal, mas em todas as palavras. Deixa-o escolher de todas as palavras em todos os arquivos abertos que começam com as mesmas letras.

Suporte a Inclusão de Arquivos

Delphi não suporta isto, e você provavelmente não criará muitos arquivos incluídos ainda. Mas arquivos incluídos tem uma grande vantagem: Eles tornam possível escrever código (in)dependente de plataforma sem confundir com IFDEFs.

Por exemplo: método pulando, Completar Classe, encontrar declaração, ... todos trabalham com arquivos incluídos.

Há muitas opções para as características do código.

Designer

- Guidelines

Inspetor de Objetos

Nos ambientes de desenvolvimento do Delphi e do Lazarus temos o Inspetor de Objeto (Object Inspector) que é utilizado para editar e atribuir as propriedades, eventos, etc... do componente. Temos a seguir pequenas diferenças reparadas no uso:

  1. Começando no Delphi 5 há uma árvore de objeto(Object TreeView) que pode ser usada para navegar e selecionar objetos de acordo com a hierarquia adicionando ao tradicional arrastar e soltar no Inspetor de Objeto. No Lazarus é parte do Inspetor de Objeto e é usada no lugar do padrão arrastar e soltar, você pode selecionar para usar ou não isto através do clique do botão direito do mouse no menu "Show Component Tree"
  2. No Delphi duplo clique em um evento em branco irá auto criar um e abrir o Editor de Código(Source Editor) na posição, no Lazarus há um botão à direita do listar(...) selecionado que executa esta ação preferivelmente
  3. No Delphi você deve manualmente apagar o nome de um evento no editor para remover a ligação, no Lazarus você pode listar os eventos(...) e selecionar "(None)".
  4. Igualmente a Eventos, duplo clique em propriedades como booleana não irá mudar o valor, você deve selecionar o valor da lista. E para abrir aqueles com um editor de formulário associado, você deve clicar o botão '...' à direita do editor/lista

Pacotes

O Lazarus pode instalar e usar pacotes do Delphi ?

Não, porque eles requerem a magia do compilador Delphi.

Nós necessitamos que sejam feitos especialmente para Lazarus?

Sim. Crie um novo pacote, salve-o no diretório fonte do pacote (normalmente o mesmo diretório do .dpk(arquivo), adicion a LCL como pacote necessário e finalmente adicione os arquivos .pas . Você pode instalá-lo, ou usá-lo nos seus projetos agora. Há algumas diferenças entre pacotes do Lazarus e do Delphi, então por favor leia:

- docs/Packages.txt nos fontes do lazarus.

VCL -> LCL

Mesmo que a VCL e a LCL sirvam ao mesmo propósito - de uma Hierarquia de Componentes de Orientação a Objeto para RAD - elas não são idênticas. Por exemplo, enquanto a VCL provê muitos componentes não visuais, a LCL provê somente componentes visuais, pois a maioria dos componentes não visuais (como aceso a bancos de dados) são providos pela FCL, incluída no Free Pascal .

Adicionalmente muitos controles da VCL podem não existir na LCL ou vice-versa, ou mesmo quando os controles existem em ambas, não são clones, e é necessário fazer modificações nas aplicações para portá-los.

O que segue é uma tentativa de descrever as maiores diferenças ou incompatibilidades entre as duas para usuários Delphi. Cobre primariamente as diferenças com a VCL do Delphi 4, às vezes do Delphi 5 e Delphi 6 ou Delphi 7 também, e com a LCL atual, como está no CVS. Pode não coincidir com a versão da VCL que você usa, ou com a LCL que você tem. Se você observar disparidades com a LCL do CVS atual ou com o seu Delphi, esteja à vontade para acrescentar ou modificar de modo que fique compreensível para todos.

TControl.Font/TControl.ParentFont

Na VCL é muito comum e normal usar nomes ou propriedades de fontes específicas, como negrito ou itálico para controles e esperar que estes valores sejam semmpre seguidos. Também se provê a propriedade TControl.ParentFont que certifica que o controle vai seguir a fonte do seu Parent. A suposição implícita sendo a de que esses valores vão ser sempre seguidos, independente da configuração da aparência das janelas.

Isto nem sempre é verdade na LCL, nem pode ser. Sendo a LCL cross-plataforma e cross-interface, naturalmente prefere fazer uma abordagem balanceada e vai procurar sempre usar Desktop/Aparência e Temas de Toolkit nativas de cada widget. Por exemplo, ao usar a interface GTK, o o GTK Theme supre uma fonte específica para botões, a LCL vai sempre procurar usar esta fonte.

Isto quer dizer que a maioria dos controles da LCL não têm o mesmo controle nível de desing que é freqüentemente esperado da VCL, a não ser somente para os controles que são desenhados no Canvas em vez de alocados na interface e que podem ser consistentemente modificados indepententemente da interface usada.

Control Dragging/Docking

Na VCL a maioria dos WinControls implementam métodos e funções de callback para manejar dragging e docking de controles, por exemplo para arrastar um controle de um painel e soltar em outro em tempo de execução.

Esta funcionalidade está atualmente não-implementada ou não-finalizada na LCL, em estágios iniciais de planejamento, e deve eventualmente dar suporte em algum nível de compatibilidade a este comportamento, se não da mesma maneira.

Isto atualmente significa que nenhum controle vai herdar ou usar as seguintes funções, procedimentos, propriedades ou eventos:

Protected
function
GetDockEdge(MousePos: TPoint): TAlign;
function
GetDragImages: TDragImageList;
function
GetFloating: Boolean;
function
GetFloatingDockSiteClass: TWinControlClass;
procedure
DoEndDrag(Target:TObject); X, Y: Integer);
procedure
DockTrackNoTarget(Source: TDragDockObject; X, Y: Integer);
procedure
DoEndDock(Target: TObject; X, Y: Integer);
procedure
DoDock(NewDockSite: TWinControl;
var
ARect: TRect);
procedure
DoStartDock(
var
DragObject: TDragObject);
procedure
DragCanceled;
procedure
DragOver(Source: TObject; X, Y: Integer; State: TDragState;
var
Accept: Boolean);
procedure
DoEndDrag(Target: TObject; X, Y: Integer);
procedure
DoStartDrag(
var
DragObject: TDragObject);
procedure
DrawDragDockImage(DragDockObject: TDragDockObject);
procedure
EraseDragDockImage(DragDockObject: TDragDockObject);
procedure
PositionDockRect(DragDockObject: TDragDockObject);
procedure
SetDragMode(Value: TDragMode);
property
DragKind: TDragKind;
property
DragCursor: TCursor;
property
DragMode: TDragMode;
property
OnDragDrop: TDragDropEvent;
property
OnDragOver: TDragOverEvent;
property
OnEndDock: TEndDragEvent;
property
OnEndDrag: TEndDragEvent;
property
OnStartDock: TStartDockEvent;
property
OnStartDrag: TStartDragEvent;
public
function
Dragging: Boolean;
function
ManualDock(NewDockSite: TWinControl; DropControl: TControl;
ControlSide: TAlign): Boolean;
function
ManualFloat(ScreenPos: TRect): Boolean;
function
ReplaceDockedControl(Control: TControl; NewDockSite: TWinControl;
DropControl: TControl; ControlSide: TAlign): Boolean;
procedure
BeginDrag(Immediate: Boolean; Threshold: Integer);
procedure
Dock(NewDockSite: TWinControl; ARect: TRect);
procedure
DragDrop(Source: TObject; X, Y: Integer);
procedure
EndDrag(Drop: Boolean);
property
DockOrientation: TDockOrientation;
property
Floating: Boolean;
property
FloatingDockSiteClass: TWinControlClass;
property
HostDockSite: TWinControl;
property
LRDockWidth: Integer;
property
TBDockHeight: Integer;
property
UndockHeight: Integer;
property
UndockWidth: Integer;

que as seguintes classes não existem ou não são utilizáveis:

TDragImageList =
class
(TCustomImageList) TDockZone =
class
TDockTree =
class
(TInterfacedObject, IDockManager) TDragObject =
class
(TObject) TBaseDragControlObject =
class
(TDragObject) TDragControlObject =
class
(TBaseDragControlObject) TDragDockObject =
class
(TBaseDragControlObject)

e que as seguintes funções são inutilizáveis ou incompatíveis:

function
FindDragTarget(
const
Pos: TPoint;
AllowDisabled: Boolean) : TControl;
procedure
CancelDrag;
function
IsDragObject(sender: TObject): Boolean;

TEdit/TCustomEdit

Os controles Edit, ainda que funcionem essencialmente do mesmo modo na LCL como na VCL, não tem alguns itens que facilitariam a conversão

  1. Devido a restrições em Interfaces, TEdit.PasswordChar não funciona em todas as interfaces ainda (mas deverá funcionar), em lugar de TCustomEdit.EchoMode emPassword deve ser usado em eventos em que o texto precisa ser escondido.
  2. Os eventos OnDrag e OnDock não estão implementados ainda. Para mais informações veja a seção anterior Control Dragging/Docking.
  3. Propriedades de fonte são ignorada por consitência com interface, para uma explanação detalhada veja TControl.Font/TControl.ParentFont

(optional) TSplitter -> TPairSplitter

Please Improve Me

Existe agora um controle TSplitter na LCL, não é mais necessário convertê-lo.

No entanto, se você o quiser, ele está explicado aqui:

O que segue é baseado em perguntas feitas por Vincent Snijders na mailing list, respondidas por Andrew Johnson:

Na VCL, controles de splitting, que são um handle que pode ser arrastado entre dois componentes para dar mais ou menos espaço a um ou a outro, é realizado por um Splitter. Ele é visto por exemplo na IDE do Delphi entre o Code Explorer e o Source Viewer.

A LCL fornece o seu próprio controle chamado TPairSplitter, que serve ao mesmo propósito, mas não é compatível, de modo que "reparar" código quebrado da VCL ou de arquivos DFM do Delphi será necessário para portar código, ainda que haja muito em comum entre os dois controles.

Então o que são exatamente essas diferenças?

Well the biggest differences are a VCL TSplitter has no children, instead it is placed between two controls aligned properly, and allows resizing between them at runtime, regardless its own size. It must have two controls aligned on each size to do anything. A simple example would be form with a Left Aligned Panel, a left aligned Splitter, and a second client aligned panel. On run time you could then realign the size given each panel by dragging on the handle provided by this Splitter control.

On the LCL hand however, a TPairSplitter is a special kind of control, with two panels, and it can only be usefull if the controls to split are on these panels, but it will still perform a split between those panel whether or not anything is on them. So following the prior example, you would have a form with a TPairSplitter aligned client, and a panel aligned client on its left side, and a panel aligned client on its right side.

The other important difference is that in the VCl, since the TSplitter is its own TControl, then the position is kept relative to the other controls on resize, so for instance a client panel will grow while the other panels will not, thus the split position is relative to the alignment of the split controls,

In the LCL since the side panels are separate then the TPairSplitter has a Position property which is absolute relative to top or left. so on resize the actual position does not change according to contents, so a callback must be set to ensure the ratio is kept on resize if this is important.

For example if the Right side of a vertical split needs to have alClient like behaviour, you need to add a form resize callback which does something like :

PairSplitter.Position := PairSplitter.Width - PairSplitter.Position; 
Então como posso converter um código existente usando TSplitter para TPairSplitter?

If the splitter and controls are created within an actual function(like form oncreate), conversion shouldn't be too difficult, primarily reorganize the code to create the controls in order of new hierarchy and set the parents of the child controls to split to the left/top and right/bottom portions of the PairSplitter. An example of the changes being -

VCL LCL
var
BottomPanel: TPanel
;
VerticalSplitter: TSplitter
;
LeftPanel: TPanel
;
HorizontalSplitter: TSplitter
;
MainPanel: TPanel
;
begin
BottomPanel:= TPanel.Create(Self)
;
with
(BottomPanel)
do
begin
Parent:= Self
;
Height:=
75
;
Align:= alBottom
;
end
;
VerticalSplitter:= TSplitter.Create(Self)
;
with
(VerticalSplitter)
do
begin
Parent:= Self
;
Align:= alBottom
;
end
;
HorizontalSplitter:= TSplitter.Create(Self)
;
with
(HorizontalSplitter)
do
begin
Parent:= Self
;
align:= alLeft
;
end
;
LeftPanel:= TPanel.Create(Self)
;
with
(LeftPanel)
do
begin
Parent:= Self
;
Width:=
125
;
Align:= alLeft
;
end
;
MainPanel:= TPanel.Create(Self)
;
with
(MainPanel)
do
begin
Parent:= Self
;
Align:= alClient
;
Caption:=
'Hello'
;
end
;
end
;
var
BottomPanel: TPanel
;
VerticalSplitter: TPairSplitter
;
LeftPanel: TPanel
;
HorizontalSplitter: TPairSplitter
;
MainPanel: TPanel
;
begin
VerticalSplitter:= TPairSplitter.Create(Self)
;
with
(VerticalSplitter)
do
begin
Parent:= Self
;
Align:= alClient
;
Width:= Self.Width
;
Height:= Self.Height
;
SplitterType:= pstVertical
;
Position:= Height -
75
;
Sides[
0
].Width:= Width
;
Sides[
0
].Height:= Position
;
end
;
HorizontalSplitter:= TPairSplitter.Create(Self)
;
with
(HorizontalSplitter)
do
begin
Parent:= VerticalSplitter.Sides[
0
]
;
Width:= Self.Width
;
Height:= VerticalSplitter.Position
;
align:= alClient
;
SplitterType:= pstHorizontal
;
Position:=
125
;
end
;
LeftPanel:= TPanel.Create(Self)
;
with
(LeftPanel)
do
begin
Parent:= HorizontalSplitter.Sides[
0
]
;
Align:= alClient
;
end
;
MainPanel:= TPanel.Create(Self)
;
with
(MainPanel)
do
begin
Parent:= HorizontalSplitter.Sides[
1
]
;
Align:= alClient
;
Caption:=
'Hello'
;
end
;
BottomPanel:= TPanel.Create(Self)
;
with
(BottomPanel)
do
begin
Parent:= VerticalSplitter.Sides[
1
]
;
Align:= alClient
;
end
;
end
;

So as you can see, farely consistant with most control hierarchy. And if you are familiar with DFM's, the changes needed for DFM->LFM conversion should be farely obvious from the above, as they are the same sort of changes in Parent/Owner etc.

So the above example would be something like -

Delphi DFM
(extraneous values removed)
Lazarus LFM
(most width, height, etc. removed)
object
VerticalSplitter: TSplitter Height
=
3
Cursor
=
crVSplit Align
=
alBottom
end
object
HorizontalSplitter: TSplitter Width
=
3
Align
=
alLeft
end
object
BottomPanel: TPanel Height
=
75
Align
=
alBottom
end
object
LeftPanel: TPanel Width
=
125
Align
=
alLeft
end
object
MainPanel: TPanel Align
=
alClient
end
object
VerticalSplitter: TPairSplitter Align
=
alClient SplitterType
=
pstVertical Position
=
225
Height
=
300
Width
=
400
object
Pairsplitterside1: TPairSplitterIde
object
HorizontalSplitter: TPairSplitter Align
=
alClient Position
=
125
object
Pairsplitterside3: TPairSplitterIde Width
=
125
object
LeftPanel: TPanel Align
=
alClient Width
=
125
end
end
object
Pairsplitterside4: TPairSplitterIde
object
MainPanel: TPanel Align
=
alClient
end
end
end
end
object
Pairsplitterside2: TPairSplitterIde
object
BottomPanel: TPanel Align
=
alClient Height
=
75
end
end
end

TCustomTreeView/TTreeView

Ambas, VCL e LCL, fornecem um componente TCustomTreeView/TTreeView, usado ​​para lista estruturada de árvore de dados com múltiplos nós e seleção avançada e, listas de imagens, e enquanto características reais são comparáveis, nem todas as propriedades são inteiramente compatíveis. As principais diferenças são as seguintes -

Incomplete list, also update to include TCustomTreeView Mark functions and protected methods

  1. A LCL provê para o componente TCustomTreeView.Options, um conjunto de opções que podem ser ajustadas no controle para mudar seu comportamento e aparência. Estas opções são:
    • tvoAllowMultiselect - enables multi node select mode, equivalent to enabling TCustomTreeView.MultiSelect in the D6 VCL
    • tvoAutoExpand - Auto Expand nodes, equivalent to enabling TCustomTreeView.AutoExpand
    • tvoAutoInsertMark - Update the Drag preview on mouse move.
    • tvoAutoItemHeight - Adjust the item heights automatically.
    • tvoHideSelection - Do not mark the selected item.
    • tvoHotTrack - use Hot Tracking, equivalent to enabling TCustomTreeview.HotTrack
    • tvoKeepCollapsedNodes - When shrinking/folding nodes, keep the child nodes
    • tvoReadOnly - make Treeview read only, equivalent to enabling TCustomTreeview.ReadOnly
    • tvoRightClickSelect - allow using Mouse Right Clicks to select nodes, equivalent to enabling TCustomTreeView.RightClickSelect
    • tvoRowSelect - allow selecting rows, equivalent to enabling TCustomTreeView.RowSelect
    • tvoShowButtons - show buttons, equivalent to enabling TCustomTreeView.ShowButtons
    • tvoShowLines - show node lines, equivalent to enabling TCustomTreeView.ShowLines
    • tvoShowRoot - show root note, equivalent to enabling TCustomTreeView.ShowRoot
    • tvoShowSeparators - show seperators
    • tvoToolTips - show tooltips for individual nodes
  2. The LCL provides additional properties:
    • TCustomTreeView.OnSelectionChange event
    • TCustomTreeView.DefaultItems, for the default number of Items
    • TCustomTreeView.ExpandSignType to determine sign used on expandable/collapsible nodes
  3. While most On Drag/Dock Events are available in the LCL they do not work. For more information please see earlier section on Control Dragging/Docking.

Messages / Events

The order and frequency of messages and events (OnShow, OnActivate, OnEnter, ...) differ from the VCL and depend on the widgetset. The LCL provides a subset of WinAPI like messages to make porting of Delphi components easier, but almost all LCL messages work a little bit different than the VCL/WinAPI counterpart. The biggest part of Delphi code using WinAPI messages uses them, because the VCL lacks a feature or for speed reasons. Such things will seldom work the same under the LCL, so they must be checked manually. That's why LCL messages are called for example LM_SIZE instead of WM_SIZE (unit lmessages).

Original Contributors and changes

This page has been converted from the epikwiki version.

  • Initial import and formatting - VlxAdmin 9/26/2003
  • Begin VCL -> LCL with a section on TSplitter -> TPairSplitter - Andrew Johnson 9/30/2003
  • Add TControl.Font/TControl.ParentFont to VCL -> LCL - Andrew Johnson 9/30/2003
  • Update TEdit/TCustomEdit section in VCL -> LCL - Andrew Johnson 10/1/2003
  • Add Control Dragging/Docking to VCL -> LCL - Andrew Johnson 10/1/2003
  • Added "Object Inspector" to Delphi IDE -> Lazarus IDE - Andrew Johnson 10/1/2003
  • Added initial "TCustomTreeView/TTreeView" to VCL -> LCL - Andrew Johnson 10/1/2003
  • Added introduction to VCL -> LCL - Andrew Johnson 10/1/2003
  • Fixed some typos - Vincent 10/2/2003
  • Fixed Typo User:Kirkpatc 20 May 2004
  • Portuguese translation and small corrections - User: jrxds 12/01/2012

See Also

Code Conversion Guide (from Delphi & Kylix)

Compile With Delphi