Ir para conteúdo
Fórum Script Brasil
  • 0

Mudar Cursor


Paulo Nobre

Pergunta

Prezados Colegas

Gostaria de saber como faço para mudar o meu cursor

fora do domínio do programa, ou seja, que ele assuma,

por exemplo o formato de uma cruz quando estiver em cima do screen.

Só estou conseguindo fazer isto em cima do form.

Estou fazendo screen.cursor:= crCross, porém, só aparece a cruz em cima do form

e não na tela toda.

Obrigado

Paulo Nobre

Link para o comentário
Compartilhar em outros sites

24 respostass a esta questão

Posts Recomendados

  • 0

Você pode usar as API's do Windows:

'SetCursor', para trocar o cursor do sistema.

'LoadCursor', se necessário carregar algum arquivo 'cur' (arquivo de cursor).

'DestroyCursor', se você usou 'LoadCursor' para carrgar um arquivo 'cur'.

Mais detalhes sobre API's do Windows: www.allapi.net

Falows! Qualquer coisa 'stamos aí!

Link para o comentário
Compartilhar em outros sites

  • 0

Denis obrigado pela atenção.

Você pode me dizer se estas funções estão "encapsuladas"(nem sei se é este o termo), em alguma UNIT do delphi, por exemplo a WINDOWS. Estou sem o delphi neste momento.

Pelo que você colocou talvez eu precise apenas da função setcursor, pois usarei apenas o cursor cross num determinado momento e depois voltarei para o padrão.

Link para o comentário
Compartilhar em outros sites

  • 0

As três funções, mais algumas (comparado com o número real existente) API's do Windows, estão na unit Windows.

Falows!

Link para o comentário
Compartilhar em outros sites

  • 0

Mais detalhes sobre API's do Windows: www.allapi.net - Mencionou o colega Denis

No site acima sugerido pelo Denis existe um programa que contém todas(ou quase todas) APIS do windows.

Acontece que os exemplos são todos para VB e VB.net, que não estou acostumado.

O delphi nos acostumou mal com o uso das APIs( sem álias user lib etc...)

Alguém que já precisou mudar o cursor e depois voltar para o defaut poderia me ajudar postando o código de como fazer isto.

Gostaria de passar para crCross e depois voltar para o default.

Ficaria muito grato.

Link para o comentário
Compartilhar em outros sites

  • 0

Pode parecer estranho mas para voltar o cursor é o mesmo comando.

Não conseguí entender muito bem, mas pelo que ví, a função SetSystemCursor destroi o cursor que ela ativa e quando você aplica o mesmo comando, como o cursor não existe mais, ela volta ao cursor anterior.

Link para o comentário
Compartilhar em outros sites

  • 0

Faça o seguinte:

altere o comando utilizando os cursores OCR_SIZENS (resize norte/sul) pelo IDC_SIZEWE (resize leste/oeste)

procedure TForm1.Button1Click(Sender: TObject);
begin
  SetSystemCursor(LoadCursor(0, IDC_SIZEWE), OCR_SIZENS);
end;

Agora será possível entender porque a restauração é feita utilizando o mesmo comando. Clique no botão, vá até as bordas de uma janela (norte, sul, leste e oeste) e observe que na verdade o que ocorre é um swap (troca) entre os cursores!!!

[]s

Link para o comentário
Compartilhar em outros sites

  • 0

É verdade mas no meu caso preciso mudar da cruz para a seta(normal).

O que foi fornecido pelo s3c funciona perfeitamente porém, estou com um problema que não consigo resolver. Fiquei ontem umas 4 horas em cima e nada.

Veja se vocês podem me ajudar.

Preciso, que ao clicar na tecla F3 o cursor mude para cruz e ao soltar a F3 volte para a seta(normal).

Alguém diria, por exemplo coloque no onkeydown SetSystemCursor(LoadCursor(0, IDC_Normal), OCR_Normal); e depois no onkeyup SetSystemCursor(LoadCursor(0, IDC_Normal), OCR_Normal);

fazendo a chamada por if key = VK_F3 then.

O problema é que meu programa, que é um capturador da parte da tela do screen, funciona da seguinte maneira:

Você fica com f3 clicada(enquanto isto o código de captura está sendo executado) e arrasta o mouse. Nesta arrastada do mouse é que o cursor muda para a cruz.

Só que quando solto(onkeyup) ora o cursor termina na cruz ora termina na seta(onkeyup). Parece que ficar com F3 clicada equivale a ficar fazendo apertar(down) e soltar(up) um número n de vezes.

Já tentei de tudo:

Coloquei uma variável inteira para ver quantas vezes a tecla f3 ficou premida no onkeydown e verificar no onkeyup se é para ou ímpar no keyup e com um if ver se precisofazer duas vezes SetSystemCursor(LoadCursor(0, IDC_Normal), OCR_Normal); ou uma .

Fiz a mesma coisa jogando para o registro e fazendo a leitura no registro pelo onkeyup.

Só que nada deu certo.

Sempre na saída do onkeyup o resultado é aleatório ora termina na cruz ora termina na seta. Eu preciso que termine na seta.

Engraçado é que achava que tinha que dar certo pois se fosse ímpar o número de vezes(descobria pelo uso do MOD) você estava indo para a seta e se fosse para voltando para a cruz. Aí fazendo a leitura com um if você acertava no final?

Alguém poderia me ajudar com algum código?

Obrigado.

Link para o comentário
Compartilhar em outros sites

  • 0

Tente utilizar uma variável boolean:

 var bF3:Boolean;
procedure TForm1.FormCreate(Sender: TObject);
begin
  bF3 := false;
end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if (key = VK_F3) and not bF3 then
  begin
    bF3 := true;
    SetSystemCursor(LoadCursor(0, IDC_Cross), OCR_Normal);
  end;
end;
procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if (key = VK_F3) and bF3 then
  begin
    bF3 := false;
    SetSystemCursor(LoadCursor(0, IDC_Cross), OCR_Normal);
  end;
end;

Mas o formulário tem que estar em foco no onKeyDown e onKeyUp

Link para o comentário
Compartilhar em outros sites

  • 0

Tente utilizar uma variável boolean:

 var bF3:Boolean;
procedure TForm1.FormCreate(Sender: TObject);
begin
  bF3 := false;
end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if (key = VK_F3) and not bF3 then
  begin
    bF3 := true;
    SetSystemCursor(LoadCursor(0, IDC_Cross), OCR_Normal);
  end;
end;
procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if (key = VK_F3) and bF3 then
  begin
    bF3 := false;
    SetSystemCursor(LoadCursor(0, IDC_Cross), OCR_Normal);
  end;
end;

Mas o formulário tem que estar em foco no onKeyDown e onKeyUp

O problema é que a minha aplicação estará rodando no tray, fora de foco.

Teria como adaptar para quando estiver fora de foco?

Não conheço esta função SetCaptureControl.

Teria como adaptar para o código do s3c?

Link para o comentário
Compartilhar em outros sites

  • 0

Sim. Coloque dentro do if do KeyDown coloque o SetCaptureControl(Self) (self - seu form recebe as mensagens) e no if do KeyUp coloque o ReleaseCapture.

p.s. Nunca realizei este procedimento sem que o form estivesse visível. Não estou certo de que lhe servirá. Também para o caso que utilizei, ocorre que a coordenada tinha que ser remapeada com ScreenToClient (ou algo assim).

Link para o comentário
Compartilhar em outros sites

  • 0
Sim. Coloque dentro do if do KeyDown coloque o SetCaptureControl(Self) (self - seu form recebe as mensagens) e no if do KeyUp coloque o ReleaseCapture.
Acho que o primeiro problema não é capturar o mouse fora da aplicação e sim capturar a tecla F3 fora da aplicação.

Particularmente só conheço uma maneira de se fazer; com funções Hook (SetWindowsHookEx com idHook = WH_KeyBoard, CallNextHookEx e UnhookWindowsHookEx). Essas hooks devem ser globais e portanto precisam estar rodando numa dll.

Espero que algum colega do fórum conheça uma maneira mais simples de capturar teclas fora da aplicação.

Link para o comentário
Compartilhar em outros sites

  • 0
Espero que algum colega do fórum conheça uma maneira mais simples de capturar teclas fora da aplicação.

Não, não tem... Hooks (ganchos) são mecanismos de envio de informações entre uma aplicação e um objeto existente, um hardware, por exemplo... No caso acima, sua aplicação teria que ganchar o teclado, assim obtendo todos os eventos do mesmo..

Lembro de ter usado essas API's para ganchar uma caixa de mensagem (MessageBox), assim tendo total controle sobre a caixa de mensagem (alterei o rotúlo dos botões 'Sim' e 'Não'. Alterei também os tamanhos dos botões).

É um processo um pouco complicado, mas um resultado de tirar o chapéu : )

Falows!

Link para o comentário
Compartilhar em outros sites

  • 0

Pelo tudo que vi escrito vejo que seria complicado.

Vou deixar um pouco este projeto de lado e partir para outros estudos.

Mesmo não conseguindo aprendi muito aqui neste tópico.

A única coisa que fico intrigado é que vi este procedimento

no programa DGMScreen(capturas de telas, janelas e partes)

e o programa não tinha nenhuma dll(acho).

Ele era fornecido com um executável e um aquivo INI.

Obrigado

Link para o comentário
Compartilhar em outros sites

  • 0

Paulo, eu até tinha uma versão antiga utilizada no tempo do Pascal for Windows (só uns 10 anos), porém após tentar adaptar não funcionou a contento. Então, fazendo uso do jargão do meu rodapé, dei umas fuçadas e acho que irá servir para o que você quer.

Código da DLL:

library keyhook;
uses
  Windows, Messages;

const
  WH_KEYBOARD_LL = 13;
  LLKHF_UP       = $8;

type
  PKBDLLHOOKSTRUCT = ^TKBDLLHOOKSTRUCT;
  TKBDLLHOOKSTRUCT = packed record
    vkCode :DWORD;
    scanCode :DWORD;
    flags :DWORD;
    time :DWORD;
    dwExtraInfo :^ULONG;
  end;

var
  HKeyHook :HHook;
  WndHandle :THandle;


function KeyboardHookProc(Code: Integer; wParam: Word; lParam: Longint): LongInt; stdcall;
var
  KeyMessage :Integer;
  PKeyStruct :PKBDLLHOOKSTRUCT;
begin
  if Code >= 0 then
    if (wParam = WM_KEYDOWN) or (wParam = WM_KEYUP) then
    begin
      PKeyStruct := PKBDLLHOOKSTRUCT(lParam);
      if PKeyStruct^.vkCode = VK_F3 then
      begin
        PostMessage(WndHandle, wParam, PKeyStruct^.vkCode, 0);  // passa apenas o código da tecla
        Result := 1;  // Não deixa outro aplicativo processar a tecla
        Exit;
      end;
    end;
  Result := CallNextHookEx(HKeyHook, code, wParam, lParam);  // Passa evento para outros ganchos
end;

function InstallKeyHook(FormHandle :THandle): LongInt; stdcall;
begin
  WndHandle := FormHandle;
  HKeyHook := SetWindowsHookEx(WH_KEYBOARD_LL, @KeyboardHookProc, hInstance, 0);
  if HKeyHook = 0 then
    Result := GetLastError
  else
    Result := 0;
end;

procedure UninstallKeyHook; stdcall;
begin
  UnhookWindowsHookEx(HKeyHook);
end;

  exports InstallKeyHook;
  exports UninstallKeyHook;

begin
end.
link de ref. da função (callback): http://msdn.microsoft.com/library/default....eyboardProc.asp Supondo o form principal do seu projeto seja Form2:
...
implementation
{$R *.DFM}

// carga dinâmica da DLL
function InstallKeyHook(FormHandle :THandle): LongInt; stdcall; external 'keyhook.dll';
procedure UninstallKeyHook; stdcall; external 'keyhook.dll';

procedure TForm2.FormCreate(Sender: TObject);
begin
  if InstallKeyHook(Handle) <> 0 then
    ShowMessage('Houve um erro inicializando a Hook!');
end;

procedure TForm2.FormDestroy(Sender: TObject);
begin
  UninstallKeyHook;
end;
...

Em meus testes funcionou.

[]s

Link para o comentário
Compartilhar em outros sites

  • 0
A única coisa que fico intrigado é que vi este procedimento

no programa DGMScreen(capturas de telas, janelas e partes)

e o programa não tinha nenhuma dll(acho).

Ele era fornecido com um executável e um aquivo INI.

Se não tiver outra maneira, a dll de funções hook poderia estar no .exe como um arquivo de recursos.
Link para o comentário
Compartilhar em outros sites

  • 0

Realmente s3c, pode ser que o programa que citei tenha uma dll embutida no arquivo de recursos.

Pensei até em manadr um email para o autor do programa e perguntar a ele.

Micheus muito muito agradecido por você colocar o código da dll, realmente sozinho não conseguiria nunca escrever este código.

Vou adaptar para o meu programa no final de semana.

Link para o comentário
Compartilhar em outros sites

  • 0

Quando estava tentando reimplementar este recurso, também achei que poderia faze-la funcionar dentro do executável, porém não estava funcionando. O programa não interseptava a tecla. Porém, utilizava o filtro WH_KEYBOARD. Não tentei verificar se foi algum outro procedimento incorreto que realizei, para o uso deste filtro.

Após implementar utilizando o filtro WH_KEYBOARD_LL, que postei anteriormente, resolvi tentar novamente juntar tudo no executável e a resposta foi positiva - Funciona. Assim sendo, você pode colocar todo o código da DLL dentro do executável e retirar do mesmo a carga dinâmica da DLL.

Lembrei depois que você quer verificar a tecla control pressionada, um meio de fazer isto é adicionar algo como

CTRLPressed := (GetAsyncKeyState(VK_CONTROL) and $8000) <> 0;

na callback, para que você apenas chame seu aplicativo com a combinação CTRL+F3.

[]s

p.s. valeu pela oportunidade de aprender mais esta.

Link para o comentário
Compartilhar em outros sites

  • 0

Micheus,

Testei o código e a dll colocando setsystemcursor no onkeydown e onkeyup e funcionou porém, estou com o seguinte problema: O código que era para ser executado quando apertasse F3 não está sendo executado o programa fica parado.

Lembro que o objetivo da captura da tecla F3 era para o seguinte:

Clicando na F3 e segurando o cursor passava para uma cruz, arrastava uma parte do screen, soltava a tecla ele voltava para o padrão e este pedaço da tela era capturado.

Quando o usuário clica em capturar parte da tecla um timer é acionado (veja abaixo)

O código que é executado é o seguinte:

Será que o GETKeyState está causando algum problema.

procedure TfrmPrincipal.TimerParteDaTelaTimer(Sender: TObject);
Var
   formato : Word;
   dados : Cardinal;
   paleta : HPALETTE;
begin
TimerParteDaTela.Enabled:= False;
  try
    if GetKeyState(VK_F3) < 0 then
    begin
      Capturando := True;
      if X1 = 0 then
        begin
          X1 := Mouse.CursorPos.X;
          Y1 := Mouse.CursorPos.Y;
          X2 := X1;
          Y2 := Y1;
        end
      else
        if (X2 <> Mouse.CursorPos.X) or (Y2 <> Mouse.CursorPos.Y) then
          begin
            Canv.Rectangle(X1, Y1, X2, Y2);
            X2 := Mouse.CursorPos.X;
            Y2 := Mouse.CursorPos.Y;
            Canv.Rectangle(X1, Y1, X2, Y2);
          end;
    end
    else
      if Capturando then
        begin
          Canv.Rectangle(X1, Y1, X2, Y2);
          Timer1.Enabled:=True;
          CopiaTela(Image1.Picture.Bitmap, X1, Y1, X2, Y2);
          Image1.Picture.SaveToClipBoardFormat(formato, dados, paleta);
          ClipBoard.SetAsHandle(formato, dados);
          X1 := 0;
          Capturando := False;
        end
      Else
        begin
          //SetSystemCursor(LoadCursor(0,IDC_Cross),OCR_Normal);
        end;
  finally
    TimerParteDaTela.Enabled:= True;
  end;
end;

É possível contornar este problema?

Obrigado.

Link para o comentário
Compartilhar em outros sites

  • 0

Paulo, não entendi ao certo a aplicação do timer para a captura. Nas rotinas similares que já fiz, simplesmente tilizava os eventos do Mouse para capturar a posição e movimentação do mesmo, juntamente com variáveis de controle (como seria o caso da VK_F3 pressionada). você nem precisaria chamar esta funçao se ao ser pressionada a tecla F3 você utilizasse uma variável booleana para indicar isto. Dentro do que eu tinha proposto anteriormente, incrementei mais um pouco o programa que fiz e percebí que mesmo utilizando SetCapture, quando o meu form, não está visível, ou seja, quando clico numa área da janela em que o mesmo não está, o foco passa para a janela onde cliquei. Isto estava descrito no help:

Also, even if the foreground window has captured the mouse, the user can still click another window, bringing it to the foreground.

Bom, parece que ficou um pouco mais complicado. Então imaginei o seguinte, se você ao pressionar sua combinação de teclas, capturar a área da screen (http://www.swissdelphicenter.ch/torry/showcode.php?id=259) e então abrir a janela do seu aplicativo maximizada, sem bordas e com um image (alinhado a área client) contendo a imagem capturada, você poderia utilizar os eventos do mouse direto sobre seu form, e assim marcar e capturar parte da imagem. Assim que você largar o mouse, seu form "some" e tudo fica parecendo ok.

Um lance legal para marcar a área delimitada é utilizar a função da API DrawFocusRect, quando você desenha nas coordenas do retangulo pela primeira vez o retângulo pontilhado aparece, quando você a desenha na mesma posição o retangulo desaparece, facilitando bastante a criação do visual da área selecionada.

Link para o comentário
Compartilhar em outros sites

Participe da discussão

Você pode postar agora e se registrar depois. Se você já tem uma conta, acesse agora para postar com sua conta.

Visitante
Responder esta pergunta...

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emoticons são permitidos.

×   Seu link foi incorporado automaticamente.   Exibir como um link em vez disso

×   Seu conteúdo anterior foi restaurado.   Limpar Editor

×   Você não pode colar imagens diretamente. Carregar ou inserir imagens do URL.



  • Estatísticas dos Fóruns

    • Tópicos
      152,1k
    • Posts
      651,8k
×
×
  • Criar Novo...