Dúvida sobre eventos em runtime

Delphi

19/12/2012

Bom dia, estou criando ToolButtons em runtime para organizar as janelas abertas no meu programa. Toda vez que eu clicar no ToolButton a janela que corresponder a ele terá de ser mostrada. O problema é que eu não consigo atribuir essa função ao OnClick do ToolButton no código que uso para cria-lo e o evento OnClick da ToolBar "pai" só é ativado quando você clica nela, não nos seus filhos. Gostaria de uma alternativa para isso.
Júnior Garcia

Júnior Garcia

Curtidas 0

Respostas

Pjrm1470

Pjrm1470

19/12/2012

Se há um procedimento exato para cada tipo de "botão" (toolButton) que você cria em run-time... então não vejo problema.
transforme esses procedimentos no escopo do TNotifyEvent (TNotifyEvent = procedure(Sender: TObject) of object;), ou seja:

procedimento do Botao01:
procedure CodeToolButton01(Sender: TObject);
begin
{ seu codigo }
end;


com um case (ou if) indo para o botão desejado, basta atribuir o OnClick:
SeuToolButton.OnClick := CodeToolButton01;


E quando clicar nele o codigo será executado.
Não sei como está seu codigo, então não posso dizer ao certo como fazer ou como instruílo das maneiras que pode-se fazer.
Espero que ajude.
GOSTEI 0
Júnior Garcia

Júnior Garcia

19/12/2012

eae cara. Mais detalhes aí pra vc entender melhor: Tenho uma unit chamada NavigationUtils onde faço tarefas relacionadas a navegação, como por exemplo, a criação desse botão em Runtime, a procedure é a seguinte para criá-lo:

procedure addFormBtn(formReference: TForm; toolbar: TToolBar);
var
  btnCaption: String;
  toolBtn: TToolButton;
  lastBtnIndex: Integer;
begin
  //Guarda o mesmo caption do formulário de referência
  btnCaption := formReference.Caption;

  //Cria um novo TToolButton
  toolBtn := TToolButton.Create(formReference);
  toolBtn.Caption := btnCaption;

  //Armazena o índice do último botão
  lastBtnIndex := Pred(toolbar.ButtonCount);

  {Verifica se o último índice é maior que -1 (significa que existem botões)}
  if lastBtnIndex > -1 then
    toolBtn.Left := toolbar.Buttons[lastBtnIndex].Left +
                    toolbar.Buttons[lastBtnIndex].Width
  else
    toolBtn.Left := 0;

  toolBtn.Parent := toolbar;
end;


Eu até tentei fazer isso que você disse, porém me retornava o erro: Incompatible types: 'TNotifyEvent' and 'procedure, untyped pointer or untyped parameter'.
GOSTEI 0
Pjrm1470

Pjrm1470

19/12/2012

Se não for pedir muito... posta o codigo que você fez que deu o erro. junto a procedure do evento que ele deve executar quando fizer o click do botão.

Assim da pra te dizer no que errou ou o que pode ser feito para melhorar (se quiser, rs).
Abraço.
GOSTEI 0
Júnior Garcia

Júnior Garcia

19/12/2012

na hora cara, taí o código de toda a unit:
unit NavigationUtils;

interface
  uses
    ComCtrls,
    Forms,
    Classes,
    Controls;
  procedure addFormBtn(formReference: TForm; toolbar: TToolBar);
  procedure openFormByToolButton(Sender: TObject);

implementation

procedure addFormBtn(formReference: TForm; toolbar: TToolBar);
var
  btnCaption: String;
  toolBtn: TToolButton;
  lastBtnIndex: Integer;
begin
  //Guarda o mesmo caption do formulário de referência
  btnCaption := formReference.Caption;

  //Cria um novo TToolButton
  toolBtn := TToolButton.Create(formReference);
  toolBtn.Caption := btnCaption;

  //Atribuo o evento OnClick
  toolBtn.OnClick := openFormByToolButton(formReference);

  //Armazena o índice do último botão
  lastBtnIndex := Pred(toolbar.ButtonCount);

  {Verifica se o último índice é maior que -1 (significa que existem botões)}
  if lastBtnIndex > -1 then
    toolBtn.Left := toolbar.Buttons[lastBtnIndex].Left +
                    toolbar.Buttons[lastBtnIndex].Width
  else
    toolBtn.Left := 0;

  toolBtn.Parent := toolbar;
end;

procedure openFormByToolButton(Sender: TObject);
begin
  with Sender as TForm do
  begin
    Show;
    BringToFront;
  end;
end;

end.
GOSTEI 0
Pjrm1470

Pjrm1470

19/12/2012

ok... vejamos...
No caso:
toolBtn := TToolButton.Create(formReference);

Utilize o seu ToolBar como o owner do botão. Apenas objetos já na memoria devem ser usados no create. Caso contrario utilize "nil"
if assigned(toolbar) then
  toolBtn := TToolButton.Create(toolbar)
else
  toolBtn := TToolButton.Create(nil);


Não sei como é o create do TToolButton, pois não estou com o delphi aqui para averiguar, mas por via de dúvidas... devida o "Parent" do seu toolButton com o toolbar (o pai dele será o toolbar, assim ele será automaticamente posicionado no toolbar)
toolBtn.Parent := toolbar;


Em vez de:
toolBtn.OnClick := openFormByToolButton(formReference);

use:
toolBtn.OnClick := openFormByToolButton;

Obs.: Você está definindo o evento e não fazendo a chamada dele. O compilador precisa entender que a estrutura do evento tem de ser a mesma para ser aceita. Quando o botão é clicado, o Sender já terá o TToolButton como o sender, pois quem está chamando o evento é o botão.


E por último,
with Sender as TForm do

Não faça Cast diretamente. É perigoso e pode vir a causar access violation se o sender não for do tipo espero. Verifique com um IF antes. Sempre tenha esse costume, pois evita muito erros indesejáveis:
if (Sender is TForm) then


Utilize uma variavel no evento do botão para chamar a tela. não sei quantas telas tem, mas cada evento pode fazer uma chamada para a respectiva variável.

Espero que ajude.
qualquer coisa so perguntar.
GOSTEI 0
Júnior Garcia

Júnior Garcia

19/12/2012

Já adaptei todo o código, mas na linha:
toolBtn.OnClick := openFormByToolButton;

ele mostra o erro Incompatible types: 'method pointer and regular procedure'
GOSTEI 0
Pjrm1470

Pjrm1470

19/12/2012

Pelo fato do TNotifyEvent ser uma procedure of Object.
O proprio nome ja diz "of Object"

Seu evento precisa ser implementado em alguma classe.
Crie uma classe so de escopo para que funcione.
Faça o teste e me diga.

interface
{...}
TNaoSeiOQueClass = class
public
  procedure OpenFormByToolButton(Sender: TObject);
end;

implementation

procedure TNaoSeiOQueClass.OpenFormByToolButton(Sender: TObject);
begin
{...}
end;


Não sei se dará certo... tudo requer tentativas e mudanças.
se não conseuir acessar o metodo do objeto use um "class" antes da palavra "procedure"
class procedure .....

Tanto na interface do objeto quanto na implementação. Mas creio que apenas tento uma procedure do objeto ja resolve.
GOSTEI 0
POSTAR