Ir ao conteúdo

C++ Callback em C++ como no delphi


Ir à solução Resolvido por _FBO_,

Posts recomendados

Postado

Olá. Será que é possível fazer um sistema de callback em C++ semelhante ao delphi (linguagem pascal)?

Meu objetivo é usar em microcontroladores, no qual vou mostrar num display uns campos editaveis.

Por exemplo, no delphi eu declaro os tipos de funções que serão usadas como callback e coloco como se fosse uma variavel numa classe:

 

//declaração dos tipos dos eventos
type TNotifyEvent = procedure(Sender: TObject) of object;
type TKeyPressEvent = procedure(Sender: TObject; Key: char) of object;

//definição da classe "MyEdit"
TMyEdit = class
private
  lastKey: char;
  Text: string;
  buff: string;
public
  OnEditingDone: TNotifyEvent; //declaração de um callback do tipo TNotifyEvent
  OnKeyPress: TKeyPressEvent; //declaração de um callback do tipo TKeyPressEvent
  constructor Create;
  destructor Destroy; override;
  procedure CheckKeys();
end; 
  
implementation
  
{ TMyEdit }

constructor TMyEdit.Create;
begin
  buff:= '';
  lastKey:= #0;
  OnEditingDone:= nil;
  OnKeyPress:= nil;
end;

destructor TMyEdit.Destroy;
begin

end;

procedure TMyEdit.CheckKeys;
begin
  if(GetAsyncKeyState(48) < 0)and(lastKey <> '0')then begin buff:= buff + '0'; lastKey:= '0'; end;
  if(GetAsyncKeyState(49) < 0)and(lastKey <> '1')then begin buff:= buff + '1'; lastKey:= '1'; end;
  if(GetAsyncKeyState(50) < 0)and(lastKey <> '2')then begin buff:= buff + '2'; lastKey:= '2'; end;
  if(GetAsyncKeyState(51) < 0)and(lastKey <> '3')then begin buff:= buff + '3'; lastKey:= '3'; end;
  if(GetAsyncKeyState(52) < 0)and(lastKey <> '4')then begin buff:= buff + '4'; lastKey:= '4'; end;
  if(GetAsyncKeyState(53) < 0)and(lastKey <> '5')then begin buff:= buff + '5'; lastKey:= '5'; end;
  if(GetAsyncKeyState(54) < 0)and(lastKey <> '6')then begin buff:= buff + '6'; lastKey:= '6'; end;
  if(GetAsyncKeyState(55) < 0)and(lastKey <> '7')then begin buff:= buff + '7'; lastKey:= '7'; end;
  if(GetAsyncKeyState(56) < 0)and(lastKey <> '8')then begin buff:= buff + '8'; lastKey:= '8'; end;
  if(GetAsyncKeyState(57) < 0)and(lastKey <> '9')then begin buff:= buff + '9'; lastKey:= '9'; end;

  if(GetAsyncKeyState(13) < 0)then
  begin
    lastKey:= #0;
    Text:= buff;
    buff:= '';
    if(Assigned(OnEditingDone))then
    begin
      OnEditingDone(self);
    end;
  end;
  
  if(Assigned(OnKeyPress))then
  begin
    OnKeyPress(self, lastKey);
  end;
end;

//------------------------------------------------------------------------------//

// no Formulario:

type

  { TForm1 }

  TForm1 = class(TForm)
    TimerProcess: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure TimerProcessTimer(Sender: TObject);
  private

  public
    edit1: TMyEdit;
    procedure Edit1_EditingDone(Sender: TObject);
  end;      
  
implementation

procedure TForm1.FormCreate(Sender: TObject);
begin
  edit1:= TMyEdit.Create;
  edit1.OnEditingDone:= @Edit1_EditingDone; //define a função a ser chamada no callback
  TimerProcess.Period:= 100; //mS
  TimerProcess.Enabled:= True;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  TimerProcess.Enabled:= False;
end; 

procedure TForm1.TimerProcessTimer(Sender: TObject);
begin
  edit1.CheckKeys();
end; 

procedure TForm1.Edit1_EditingDone(Sender: TObject);
begin
  ShowMessage('Callback EditingDone chamado!');
end;

 

Tem como fazer algo semelhante no C++?
Se não tiver, como funciona a questão de eventos no C++?

Muito obrigado

  • Obrigado 1
Postado

Sim a questão é que o que eu quero fazer é um ponteiro pra função pra ser usada como callback. Tentei fazer como o código abaixo mas dá erro, não compila... Eu dei uma pesquisada em algo que usa a biblioteca <Functionals> e usa Bind ou Lamba mas não entendi nada kkk
 

//Edit.h

using namespace std;

class Edit; //forward declaration

typedef void (*NotifyEvent)(void* Edit);
typedef void (*OnKeyPress)(void* Edit, char key);

class Edit{
private:
  char lastKey;
  string text;
  string buff;
public:
  OnKeyPress OnKeyPress;     // *** erro ***
  NotifyEvent OnEditingDone; // *** erro ***
  Edit();
  virtual ~Edit();
  void CheckKeys();
};

//Edit.cpp

Edit::Edit()
{
  lastKey= '\0';
  text.Clear();
  buff.Clear();	
  OnKeyPress = nullptr;
  OnEditingDone = nullptr;
}

Edit::~Edit()
{
}

void Edit::CheckKeys()
{
  if((GetAsyncKeyState(48) < 0)&&(lastKey != '0')){ buff+= '0'; lastKey= '0'; }
  if((GetAsyncKeyState(49) < 0)&&(lastKey != '1')){ buff+= '1'; lastKey= '1'; }
  if((GetAsyncKeyState(50) < 0)&&(lastKey != '2')){ buff+= '2'; lastKey= '2'; }
  if((GetAsyncKeyState(51) < 0)&&(lastKey != '3')){ buff+= '3'; lastKey= '3'; }
  if((GetAsyncKeyState(52) < 0)&&(lastKey != '4')){ buff+= '4'; lastKey= '4'; }
  if((GetAsyncKeyState(53) < 0)&&(lastKey != '5')){ buff+= '5'; lastKey= '5'; }
  if((GetAsyncKeyState(54) < 0)&&(lastKey != '6')){ buff+= '6'; lastKey= '6'; }
  if((GetAsyncKeyState(55) < 0)&&(lastKey != '7')){ buff+= '7'; lastKey= '7'; }
  if((GetAsyncKeyState(56) < 0)&&(lastKey != '8')){ buff+= '8'; lastKey= '8'; }
  if((GetAsyncKeyState(57) < 0)&&(lastKey != '9')){ buff+= '9'; lastKey= '9'; }

  if(GetAsyncKeyState(13) < 0)
  {
    lastKey= '\0';
    Text= buff;
    buff.Clear();
    if(OnEditingDone != nullptr)
    {
      OnEditingDone(this);
    }
  }
  
  if(OnKeyPress != nullptr)
  {
    OnKeyPress(this, lastKey);
  }
}

 

  • Obrigado 1
Postado
Em 05/09/2024 às 11:55, _FBO_ disse:

Tem como fazer algo semelhante no C++?
Se não tiver, como funciona a questão de eventos no C++?

 

Em C+ é igualzinho. E o sistema é o mesmo Windows nesse caso.

 

Pode usar bind ou lambdas mas pode também simplesmente colocar o nome da função de callback como argumento.

 

lambda é só uma (prática) notação compacta onde você pode salvar a função numa variável.

 

bind tem o mesmo sentido em todas linguagens. Como um alias para uma chamada de função.

 

Não precisa nem de um nem de outro.

Seu programa na versão C++ não compila por ter erros de sintaxe. A lógica em si não entendi.

 

Callbacks estariam mais para o caso de escrever isso em C, falando das linguagens desse forum. e typedef não é usado em C++ na prática.

 

E CheckKeys em Pascal ou Delphi ou C ou C++ parece ter muitos testes sem sentido.

 

Todos aqueles if devem ser mutualmente exclusivos. Mesmo que o sistema reporte várias teclas pressionadas sua lógica admite apenas um buff e um lastKey então só vai considerar o último....

 

E se não tem nenhuma tecla pressionada para que testar tantas vezes?

 

Veja esse trecho

 

    if ((GetAsyncKeyState(50) < 0) && (lastKey != '2'))
    {
        buff += '2';
        lastKey = '2';
    }

 

Se a função retornar <0 então lastKey vai ficar com '2'  de qualquer maneira....

 

e o valor de buff é o mesmo que o de lastKey ao final....

 

E não seria o caso de apenas retornar depois disso ao invés de testar por mais teclas?

  • Obrigado 1
Postado

A logica eu vou refinar depois, é mais o conceito que estou tentando acertar.
Poderia fazer um exemplo de como eu indico pra uma instancia de uma classe qual função ela deve chamar quando ocorrer uma determinada ação?
Por exemplo no caso de um campo de texto, quando o usuario terminar de editar, quero que ele chame uma função que foi apontada pra receber o evento "OnEditingDone". Poderia fazer um exemplo pra mim por favor de como eu declaro isso na classe e como eu passo a função pra instancia dessa classe?

 

Exemplo:

//Edit.h

Classe Edit{
private:
  //declarações privadas
public:
  //declarações publicas
  OnEditingDone(Edit* sender); // <------- como fica a declaração na classe?
};

//main.cpp

#include <stdio>
#include <Edit.h>
  
Edit* edit;

void Edit_OnEditDone(Edit* sender)
{
  printf("Evento OnEditingDone chamado!");
}

int main()
{
  edit = new Edit;
  edit->SetOnEditDone(&Edit_OnEditDone); // <------  como indicar a função que quero que seja executada?
  while(1)
  {
    //...
  }
}
                                                    

 

  • Obrigado 1
Postado

@_FBO_  o primeiro código que postou é do Delphi , com linguagem pascal ,  e esse outro em c++  não estava compilando por que faltava a função "main" , e corrigido  ele compila , 

//Edit.h
#include   <iostream>
#include   <iomanip>
#include   <vector>
#include   <windows.h>
using namespace std;

class Edit; //forward declaration

typedef void (*NotifyEvent)(void* Edit);
typedef void (*OnKeyPress )(void* Edit, char key);

class Edit{
private:
  char   lastKey;
  string text;
  string buff;
public:
  OnKeyPress OnKeyPress;     // *** erro ***
  NotifyEvent OnEditingDone; // *** erro ***
  Edit();
  virtual ~Edit();
  void CheckKeys();
};

//Edit.cpp

Edit::Edit()
{
  lastKey= '\0';
  text.clear(); /// c minusculo
  buff.clear(); /// c minusculo
  OnKeyPress = nullptr;
  OnEditingDone = nullptr;
}

Edit::~Edit()
{
  puts("esta no 'Edit'");
}

void Edit::CheckKeys()
{
  if((GetAsyncKeyState(48) < 0)&&(lastKey != '0')){ buff+= '0'; lastKey= '0'; }
  if((GetAsyncKeyState(49) < 0)&&(lastKey != '1')){ buff+= '1'; lastKey= '1'; }
  if((GetAsyncKeyState(50) < 0)&&(lastKey != '2')){ buff+= '2'; lastKey= '2'; }
  if((GetAsyncKeyState(51) < 0)&&(lastKey != '3')){ buff+= '3'; lastKey= '3'; }
  if((GetAsyncKeyState(52) < 0)&&(lastKey != '4')){ buff+= '4'; lastKey= '4'; }
  if((GetAsyncKeyState(53) < 0)&&(lastKey != '5')){ buff+= '5'; lastKey= '5'; }
  if((GetAsyncKeyState(54) < 0)&&(lastKey != '6')){ buff+= '6'; lastKey= '6'; }
  if((GetAsyncKeyState(55) < 0)&&(lastKey != '7')){ buff+= '7'; lastKey= '7'; }
  if((GetAsyncKeyState(56) < 0)&&(lastKey != '8')){ buff+= '8'; lastKey= '8'; }
  if((GetAsyncKeyState(57) < 0)&&(lastKey != '9')){ buff+= '9'; lastKey= '9'; }

  if(GetAsyncKeyState(13) < 0)
  {
    lastKey = '\0';
    text    = buff;
    buff.clear();
    if(OnEditingDone != nullptr)
    {
      OnEditingDone(this);
    }
  }

  if(OnKeyPress != nullptr)
  {
    OnKeyPress(this, lastKey);
  }
}
int main()
{
  Edit();
  return 0;
}

 

  • Solução
Postado

Deu certo, muito obrigado pela sua ajuda e paciência.

Segue o codigo funcionando:

 

//Edit1.h

class Edit;

typedef void (*TNotifyEvent)(Edit* sender);
typedef void (*TOnKeyPress )(Edit* sender, char Key);

class Edit{
private:
  char   lastKey;
  string buff;
public:
  Edit();
  virtual ~Edit();
  void CheckKeys();
  string text;
  TOnKeyPress OnKeyPress;
  TNotifyEvent OnEditingDone;
};

//Edit.cpp

#include "Edit.h"

Edit::Edit()
{
  text.clear();
  buff.clear();
  lastKey= '\0';
  OnKeyPress = NULL;
  OnEditingDone = NULL;
}

Edit::~Edit()
{
}

void Edit::CheckKeys()
{
  if((GetAsyncKeyState(48) < 0)&&(lastKey != '0')){ buff+= '0'; lastKey= '0'; }
  if((GetAsyncKeyState(49) < 0)&&(lastKey != '1')){ buff+= '1'; lastKey= '1'; }
  if((GetAsyncKeyState(50) < 0)&&(lastKey != '2')){ buff+= '2'; lastKey= '2'; }
  if((GetAsyncKeyState(51) < 0)&&(lastKey != '3')){ buff+= '3'; lastKey= '3'; }
  if((GetAsyncKeyState(52) < 0)&&(lastKey != '4')){ buff+= '4'; lastKey= '4'; }
  if((GetAsyncKeyState(53) < 0)&&(lastKey != '5')){ buff+= '5'; lastKey= '5'; }
  if((GetAsyncKeyState(54) < 0)&&(lastKey != '6')){ buff+= '6'; lastKey= '6'; }
  if((GetAsyncKeyState(55) < 0)&&(lastKey != '7')){ buff+= '7'; lastKey= '7'; }
  if((GetAsyncKeyState(56) < 0)&&(lastKey != '8')){ buff+= '8'; lastKey= '8'; }
  if((GetAsyncKeyState(57) < 0)&&(lastKey != '9')){ buff+= '9'; lastKey= '9'; }

  if(GetAsyncKeyState(13) < 0)
  {
    lastKey = '\0';
    text    = buff;
    buff.clear();
    if(this->OnEditingDone != NULL)
    {
      this->OnEditingDone(this);
    }
  }
  else
  {
    if(this->OnKeyPress != NULL)
    {
      this->OnKeyPress(this, lastKey);
    }
  }
}

//Main.cpp
#include "Edit.h"
#include <stdio.h>
#include <windows.h>

using namespace std;

Edit* edit1;

void Edit1_OnKeyPress(Edit* Sender, char Key)
{
  printf("OnKeyPress chamado: %c", Key);
}

void Edit1_OnEditingDone(Edit* Sender)
{
  printf("OnEditingDone chamado: %s", Sender->text);
}

int main()
{
  edit1 = new Edit;
  edit1->OnKeyPress = Edit1_OnKeyPress;
  edit1->OnEditingDone = Edit1_OnEditingDone;
  while(1)
  {
    edit1->CheckKeys();
  }
  delete edit1;
  return 0;
}

 

  • Amei 1
Postado

@_FBO_

Em 06/09/2024 às 17:27, _FBO_ disse:

quando o usuario terminar de editar, quero que ele chame uma função que foi apontada pra receber o evento "OnEditingDone"

 

Os eventos no Delphi são mapeados para eventos e mensagens do Windows, que foi escrito em C --- e C++ em alguma extensão nos últimos anos. Pode usar a API diretamente.

 

Se quer vincular uma função a ser executada quando acontecer algo pode passar isso no construtor de classe, se não for sempre a mesma função. A noção de callback aqui não acho que se aplica: afinal os eventos aqui são síncronos, referentes às teclas pressionadas. Se você quer usar isso em Windows o mais simples para manter a familiaridade com o que usa é usar o RAD Studio e usar o C++ da Borland. Ou o C++ Bullder, que é o IDE C++ do RAD Studio mas acho que pode ser usado à parte.

 

Direto do site de venda do produto:
 

image.thumb.png.b2c9465ef646eb4ae6f6594276905234.png
 

Delphi introduz uma abstração para a camada de mensagens e eventos do Windows (ou do Mac ou do linux ou Android). Delphi é um framework tipo RAD --- de Rapid Application Development. E essa é a razão do sucesso desse IDE. Você escreve mais ou menos como no Visual Basic no Windows, ou no JavaFX. Preenche simples formulários de propriedades e callbacks e o framework faz o resto para você. Por isso você pode escrever aplicativos em Delphi para 5 plataformas ao mesmo tempo. E o IDE ainda inclui um criador do programa de instalação, o tal setup. 😉  

 

E assim é muito, mas muito mais simples escrever em Delphi usando Pascal. Porque o Delphi costura tudo pra você.

 

É claro que em C ou C++ é perfeitamente possível. Delphi foi escrito em C, bem como o Windows. o Linux, o MacOS é linux, O Android é linux.

 

De volta ao programa

 

Se quer fazer isso em C++ deve usar uma aplicação desktop para Windows no seu caso. E não um simples programa de console, que roda tudo em uma thread só. E lá vai ver que é tudo igual ao Delphi: você associa mensagens a funções, o conceito de callback. 

 

Se quer associar algo a OnEditingDone ou OnKeyPress use variáveis. Aqui não são de fato callbacks. Trata-se de simples atribuições.

 

9 horas atrás, _FBO_ disse:
edit1 = new Edit;

 

Não precisa disso em C++. Nem new nem delete nem o ponteiro this. Não é java.

 

E mesmo a existência de uma classe Edit associada ao teclado é algo curioso. Só tem um teclado e está usando a API do Windows. Nem se pode garantir que uma tecla vá de fato para seu programa, e se vai iria para qual de várias instâncias de Edit, se as tivesse?

 

Se vai usar uma série de microcontroladores então imagino que nada disso se aplica e vai usar comunicação serial ou USB para ler direto do dispositivo.

 

Em 06/09/2024 às 17:27, _FBO_ disse:

A logica eu vou refinar depois, é mais o conceito que estou tentando acertar.

 

Bem, nem é assim um caso de lógica. Só faz pouco sentido. Esse trecho

 

   if ((GetAsyncKeyState(48) < 0) && (lastKey != '0'))
    {
        buff += '0';
        lastKey = '0';
    }
    if ((GetAsyncKeyState(49) < 0) && (lastKey != '1'))
    {
        buff += '1';
        lastKey = '1';
    }
    if ((GetAsyncKeyState(50) < 0) && (lastKey != '2'))
    {
        buff += '2';
        lastKey = '2';
    }
    if ((GetAsyncKeyState(51) < 0) && (lastKey != '3'))
    {
        buff += '3';
        lastKey = '3';
    }
    if ((GetAsyncKeyState(52) < 0) && (lastKey != '4'))
    {
        buff += '4';
        lastKey = '4';
    }
    if ((GetAsyncKeyState(53) < 0) && (lastKey != '5'))
    {
        buff += '5';
        lastKey = '5';
    }
    if ((GetAsyncKeyState(54) < 0) && (lastKey != '6'))
    {
        buff += '6';
        lastKey = '6';
    }
    if ((GetAsyncKeyState(55) < 0) && (lastKey != '7'))
    {
        buff += '7';
        lastKey = '7';
    }
    if ((GetAsyncKeyState(56) < 0) && (lastKey != '8'))
    {
        buff += '8';
        lastKey = '8';
    }
    if ((GetAsyncKeyState(57) < 0) && (lastKey != '9'))
    {
        buff += '9';
        lastKey = '9';
    }

 

É equivalente a esse:

 

    for (int ch = '0'; ch <= '9'; ch += 1)
        if ((GetAsyncKeyState(ch) < 0))
        {
            buff += ch;
            lastKey = (char)ch;
            return;
        }

 

E provavelmente é melhor tratar ENTER em outra chamada

 

 

Em 06/09/2024 às 17:27, _FBO_ disse:

Poderia fazer um exemplo de como eu indico pra uma instancia de uma classe qual função ela deve chamar quando ocorrer uma determinada ação?
Por exemplo no caso de um campo de texto, quando o usuario terminar de editar, quero que ele chame uma função que foi apontada pra receber o evento "OnEditingDone".

 

Se leu o que escrevi até aqui já deve ter entendido que num programa de console você vai ter que executar a ação dentro da sua lógica. Se quer um evento associado a algo vai ter que usar uma aplicação desktop e o loop de mensagens. Vou te mostrar um exemplo de todo modo. Em C++ porque foi a linguagem que tentou usar.

 

E X E M P L O 

 

Vou usar essa classe cEdit

 

A classe cEdit

 

#pragma once
#include <windows.h>
#include <iostream>

using namespace std;
using On_KeyPress  = void (*)(char);
using Notify_event = void (*)();

class cEdit
{
   private:
    char   lastKey;
    string text;
    string buff;

   public:
    On_KeyPress  OnKeyPress;
    Notify_event OnEditingDone;
    cEdit();
    cEdit(On_KeyPress, Notify_event);
    virtual ~cEdit();
    void checkK();
};

 

Uma possível implementação

 

#include "cEdit.h"

cEdit::cEdit()
{
    lastKey = 0;
    text.clear();
    buff.clear();
    OnKeyPress    = nullptr;
    OnEditingDone = nullptr;
}

cEdit::cEdit(On_KeyPress kp, Notify_event ne) {
    lastKey = 0;
    text.clear();
    buff.clear();
    OnKeyPress    = kp;
    OnEditingDone = ne;
}

cEdit::~cEdit()
{
    std::cout << "Destruindo instancia de cEdit\n";
};

void cEdit::checkK()
{
    for (int ch = '0'; ch <= '9'; ch += 1)
        if ((GetAsyncKeyState(ch) < 0))
        {
            buff += ch;
            lastKey = (char)ch;
            return;
        }

    if (GetAsyncKeyState(VK_RETURN) < 0)
    {
        lastKey = 0;
        text    = buff;
        buff.clear();
        if (OnEditingDone != nullptr) OnEditingDone();
        return;
    }

    if (OnKeyPress != nullptr) { OnKeyPress(lastKey); }
}

 

Um exemplo que usa isso

 

#include <Windows.h>

#include <format>
#include <iostream>

#include "cEdit.h"

using namespace std;

void f_kp1(char);
void f_kp2(char);

int main(void)
{
    {
        cEdit teste;
        teste.OnKeyPress = f_kp1;
        teste.OnKeyPress(17);
    }
    cEdit outra(f_kp2, nullptr);
    outra.OnKeyPress(42);
    return 0;
}

void f_kp1(char ch)
{
    std::print(
        cout, "Callback #1. Codigo da tecla = {}\n", (int) ch);
    return;
}

void f_kp2(char ch)
{
    std::print(
        cout, "Callback #2. Codigo da tecla = {}\n", (int) ch);
    return;
}

 

Pode ver duas maneiras de usar isso, no construtor ou via atribuição. Em geral se usa o nome das callbacks como private.

 

A saida do programa

 

Callback #1. Codigo da tecla = 17
Destruindo instancia de cEdit
Callback #2. Codigo da tecla = 42
Destruindo instancia de cEdit

 

Entenda que não existem eventos no programa. De nada adianta o nome. E nesse contexto as funções também não são callbacks, ao menos não no estilo javascript por exemplo.
 

 

 

 

  • Obrigado 1
Postado
14 horas atrás, arfneto disse:
int main(void)
{
    {
        cEdit teste;
        teste.OnKeyPress = f_kp1;
        teste.OnKeyPress(17);
    }
    cEdit outra(f_kp2, nullptr);
    outra.OnKeyPress(42);
    return 0;
}

Era isso mesmo o que eu estava querendo saber: como vincular uma função de fora do contexto da classe de modo que a classe pudesse chamá-la em sua rotina. Esse seu exemplo de passar como parâmetro ou atribuir a função diretamente à propriedade da instancia da classe era o que eu não estava conseguindo fazer.

No final das contas eu vou programar em C++ numa IDE própria de um microcontrolador que será montado num hardware que tem teclas e um display. O objetivo é poder apresentar campos digitáveis na tela, em que eu possa pegar os valores que o usuario digita e colocá-los em variáveis que serão usadas para controlar o comportamento do sistema.

Muito obrigado a todos que ajudaram

  • Curtir 1
Postado

@_FBO_ Entenda a diferença entre um aplicativo de console e um aplicativo desktop para Windows. Ou use o IDE da Borland para C++.

 

Não existem eventos em C++ para associar com callbacks. O Windows por exemplo gera uma mensagem WM-KEYUP quando o usuário solta uma tecla em seu programa. E você precisa colocar uma callback para essa mensagem no seu programa C ou C++. Simples assim.

 

Só que o Delphi esconde isso e é muito mais fácil programar assim, daí o sucesso desse ambiente. Fora o fato de poder usar o mesmo código em vários sistemas...

 

Esse é o loop de mensagens do Windows, gerado automaticamente pelo IDE:

 

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code that uses hdc here...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

 

Então já dá para você entender. Você inclui aí a mensagem WM_KEYUP e sua função de tratamento, a tal callback. Nada mais. Você trata todas as mensagens de que precisa e o Windows roda o programa junto com os outros.

 

 

 

 

Estou simplificando as coisas, é só um exemplo. 

 

Os controles do Windows são como os componentes VCL do Delphi. E tem seus próprios eventos e mensagens. Mas o mecanismo é esse que eu expliquei, mas aplicados nesse caso a coisas como EditBox, ProgressBar, Menus e tal.

  • Obrigado 1
Postado

Talvez seja útil ter algo assim aqui então vou deixar um exemplo bem ingênuo de uma aplicação C ou C++ que usa um edit box em Windows

 

A documentação sobre essas coisas é extensa e completa. Sobre esse controle veja em português do Brasil em https://learn.microsoft.com/pt-br/windows/win32/controls/about-edit-controls por exemplo

 

Essa é a janela da aplicação

 

image.png.4c54d61c1da1b201a0c4f6baee92bed4.png 

Tem 3 controles e ao apertar o botão copia o texto de um edit box para outro

 

#include <windows.h>

#define ID_EDIT1 1
#define ID_EDIT2 2
#define ID_BUTTON 3

LRESULT CALLBACK WindowProcedure(
    HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static HWND hEdit1, hEdit2, hButton;

    switch (msg)
    {
        case WM_CREATE:

            // ao criar a janela da aplicacao cria os 3 controles

            hEdit1 = CreateWindow(
                TEXT("EDIT"), TEXT(""),
                WS_CHILD | WS_VISIBLE | WS_BORDER, 50, 50,
                200, 20, hwnd, (HMENU)ID_EDIT1, NULL, NULL);

            hEdit2 = CreateWindow(
                TEXT("EDIT"), TEXT(""),
                WS_CHILD | WS_VISIBLE | WS_BORDER, 50, 100,
                200, 20, hwnd, (HMENU)ID_EDIT2, NULL, NULL);

            hButton = CreateWindow(
                TEXT("BUTTON"), TEXT("Copia do primeiro para o segundo EditBox "),
                WS_CHILD | WS_VISIBLE, 50, 150, 300, 30,
                hwnd, (HMENU)ID_BUTTON, NULL, NULL);
            break;

            // um click no botao vai gerar a mensagem WM_COMMAND para
            // a janela do aplicativo com a indicacao de quem enviou
            // em wParam

        case WM_COMMAND:
            if (LOWORD(wParam) == ID_BUTTON)
            {
                wchar_t wtext[512];
                LPWSTR  ptr = wtext;
                GetWindowText(hEdit1, ptr, 512);
                SetWindowText(hEdit2, ptr);
            }
            break;

        case WM_DESTROY:
            PostQuitMessage(0);
            break;

        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(
    HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    const char className[] = "MyWindowClass";
    WNDCLASS   wc          = {};
    wc.lpfnWndProc         = WindowProcedure;
    wc.hInstance           = hInstance;

    wchar_t wtext[512];
    mbstowcs(
        wtext, className,
        strlen(className) + 1);  // Plus null

    wc.lpszClassName = wtext;

    RegisterClass(&wc);

    HWND hwnd = CreateWindowEx(
        0,                 // Optional window styles.
        wc.lpszClassName,  // Window class
        L"Aperte o botão para copiar o texto de um edit "
        L"box para outro",    // Window text
        WS_OVERLAPPEDWINDOW,  // Window style

        // Size and position
        CW_USEDEFAULT, CW_USEDEFAULT, 400,
        300,

        NULL,       // Parent window
        NULL,       // Menu
        hInstance,  // Instance handle
        NULL        // Additional application data
    );

    if (hwnd == NULL) { return 0; }

    ShowWindow(hwnd, nCmdShow);

    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

 

Delphi apenas cria uma camada sobre isso, assim como se faz com Windows Forms ou MFC ou Qt ou wxWidgets ou ou qualquer outro framework.

 

É só Windows e C afinal. 

 

 

  • Obrigado 1

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!