Перейти к содержанию
Авторизация  
Antonshka

C++ WinAPI UI Wrapper

Рекомендуемые сообщения

Привет, подскажите, как можно реализовать управление UI на С++ как например в Cheat Engine? С помощью чистого WinAPI, не MFC.

Также с помощью Visual Studio Dialog Editor.

 

В СЕ все максимально просто, - хочешь поменять параметр контролла?

Спойлер

UDF1.CEPanel.Left = 10

 

Хочешь указать функцию на событие например MouseClick?

Спойлер

UDF1.CEPanel.OnClick = SomeFooOnClick

 

 

Есть идея, что нужно использовать классы. Почитал в интернете, в частности вот эту статью

но не смог уловить мысль. Сложно пока для меня.

 

Хочу в итоге что-то типа

Спойлер

//Файл resources.h
//BTN_CAMERA_ACTIVATE - это ID контрола, который я создам через Dialog Editor, и помещю на немодальный диалог, созданный там же
//BTN_CAR_TELEPORT - тоже
#define BTN_CAMERA_ACTIVATE = 101
#define BTN_CAR_TELEPORT = 102
  
  
//Файл MainProject.cpp
int BtnCameraActiv_OnClick();
int BtnCarTelep_OnClick();


int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
	ControlManager cmBtnCamActiv(BTN_CAMERA_ACTIVATE) //ControlManager - это класс для установки параметров и функций для контрола
    cmBtnCamActiv.onClick = BtnCameraActiv_OnClick;
  	cmBtnCamActiv.width = 10;
  
  	ControlManager cmBtnCarTelep(BTN_CAR_TELEPORT)
    cmBtnCarTelep.onClick = BtnCarTelep_OnClick;
  	cmBtnCarTelep.width = 20;
  
   	while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
	{
      //...
    }
  return 0;
}

int BtnCameraActiv_OnClick()
{
  cmBtnCamActiv.top = 45; //К примеру изменить позицию по Y
  moveCameraX(0.2); //Или вызвать что-нибудь
}

int BtnCarTelep_OnClick()
{
  cmBtnCarTelep.top = 7; //К примеру изменить позицию по Y
  teleporting(); //Или вызвать что-нибудь
}

 

 

Изменено пользователем Antonshka

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
3 часа назад, Antonshka сказал:

Привет, подскажите, как можно реализовать управление UI на С++ как например в Cheat Engine? С помощью чистого WinAPI, не MFC.

для начала ты можешь посмотреть примеры готового кода. На гитхабе, например. Вот первое, что поиск выдал: https://github.com/Onelio/Win32GUI

Ну а вообще с винапи всё работает точно также, как и с любым другим апи и особенностей при создании классов-оболочек никаких нет. Вот только если ты пишешь простое приложение, то возможно с классами нет смысла заморачиваться. Достаточно например сделать функцию, которая будет создавать кнопочку и назначать ей все необходимые свойства.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
2 часа назад, youneuoy сказал:

для начала ты можешь посмотреть примеры готового кода. На гитхабе, например. Вот первое, что поиск выдал: https://github.com/Onelio/Win32GUI

Ну а вообще с винапи всё работает точно также, как и с любым другим апи и особенностей при создании классов-оболочек никаких нет. Вот только если ты пишешь простое приложение, то возможно с классами нет смысла заморачиваться. Достаточно например сделать функцию, которая будет создавать кнопочку и назначать ей все необходимые свойства.

Спасибо, то что нужно. Я пробовал искать "Wrapped Wraped Api UI C++".

Пишу большое приложение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
5 часов назад, Antonshka сказал:

Пишу большое приложение.

Если реально большое, удобнее будет использовать фреймворк типа wxWidgets или Qt

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
12 часов назад, Xipho сказал:

Если реально большое, удобнее будет использовать фреймворк типа wxWidgets или Qt

Хочу именно на WinAPI, чтобы освоить его. Потом можно на Qt.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как сделать так, чтобы класс контролла, к примеру класс Button, имел поле, к примеру поле Height, и чтобы можно было считывать и записывать в это поле выражениями

Button* pBtn1 = new Button();
Button* pBtn2 = new Button();
pBtn1->m_Height = 10; //или так, запись
pBtn2->m_Height = pBtn1->Height //или так, считывание

Одна из идей, сделать поле m_Height объектом некоего класса Height, у которого есть перегруженный оператор =, или еще и другие операторы, +, -, +=, int.

Но с таким подходом для каждой арифметической операции придется писать свой соответствующий перегруженный оператор. А это накладно.

 

Сделать бы так, чтобы при считывании поля m_Height, оно автоматически преобразовывалось в тип Int. А с ним, операции заранее уже умеют работать.

Но не хочется писать так

pBtn1->Height()

Хочется в обоих случаях писать без скобок.

 

Можно было бы просто сделать поле m_Height обычной переменной типа Int, и сделать ее как Public. Но как тогда спровоцировать обновление отображения контролла, после того как будет совершена запись в поле m_Height. Как дать понять приложению обновить контролл.

Сделать ли таймер, поток, который работал бы как Anticheat Integrity Check, - если увидел что значение поля изменилось, то спровоцируй перерисоку контролла, тем же вызовом API InvalidateRect.

Но тогда, при таком способе, нужно для каждого объекта класса Button, создавать свой поток. А ведь сколько всего контроллов будет содержать приложение? Не накладно ли это, в отношении производительности работы приложения.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У тебя есть оконная процедура. Если для контрола ты вызовешь InvalidateRect, то в оконной процедуре ты можешь отловить WM_PAINT и перерисовать контрол. Только у контрола должен быть OWNERDRAW флаг, если мне не изменяет память. Но, имхо, заниматься этим - неблагодарное дело. Есть фреймворки, на них можно решать задачи нормально. Без кучи огородов и костылей.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
3 часа назад, Xipho сказал:

У тебя есть оконная процедура. Если для контрола ты вызовешь InvalidateRect, то в оконной процедуре ты можешь отловить WM_PAINT и перерисовать контрол. Только у контрола должен быть OWNERDRAW флаг, если мне не изменяет память.

 

Я наверно не так выразился, или я не понял твоего ответа.

Например я нажимаю на кнопку, на форме, когда приложение уже запущено. В процедуру этой кнопки поступает сообщение WM_LBUTTONDOWN. В Case этого сообщения идет вызов определенной мною функции, например функции где будет изменятся высота этой самой кнопки, или другой какой.

Button pBtn1 = new(Button);
Button pBtn2 = new(Button);
...

switch(msg)
case WM_LBUTTONDOWN:
	ChangeHeight(hWnd);

...
void ChangeHeight(hWnd)
{
	pBtn1->Height = 10;
	pBtn2->Height = pBtn1->Height;
}

И на этом все. То есть класс кнопки должен сам теперь позаботится о том, чтобы вызвать вначале функцию SetWindowPos, для изменения параметров кнопки, а затем функция InvalidateRect.

 

Но как классу дать понять, что теперь вот все,  можно вызвать эти две функции?

Если поле Height класса Button является типом int с доступом public. Класс никак к сожалению не уведомляется об изменениях, в нем происходящих.

 

Сейчас смотрел как это дело работает на Qt. Так там для Height нужно писать

->setWidth() //установить
->Width() //получить

  Но мне то хочется как в СЕ, без скобок, и одним и тем же выражением, что для получения, что для установки.

 

4 часа назад, Xipho сказал:

Но, имхо, заниматься этим - неблагодарное дело. Есть фреймворки, на них можно решать задачи нормально. Без кучи огородов и костылей.

Я это ради освоения WinAPI, и C++ в целом. Я вижу пользу от этого занятия.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
11 часов назад, Antonshka сказал:

Я это ради освоения WinAPI

Нужно понимать, что винапи проектировался еще во времена 16-битной винды, и никак не был рассчитан на то, что его будут натягивать на ООП. Отсюда необходимость в огромном количестве всевозможных костылей вокруг этого дела. Но, если так уж хочется упарываться, почитай книгу Фень Юаня "Программирование графики для Windows". Основная тема у него там, конечно же, не оборачивание окошек в ООП, но это он делает. Возможно, там почерпнешь какие-нибудь приемы полезные.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
10 часов назад, Xipho сказал:

Нужно понимать, что винапи проектировался еще во времена 16-битной винды, и никак не был рассчитан на то, что его будут натягивать на ООП. Отсюда необходимость в огромном количестве всевозможных костылей вокруг этого дела. Но, если так уж хочется упарываться, почитай книгу Фень Юаня "Программирование графики для Windows". Основная тема у него там, конечно же, не оборачивание окошек в ООП, но это он делает. Возможно, там почерпнешь какие-нибудь приемы полезные.

 

Приемы полезные у него конечно есть, и не мало, но как я сейчас посмотрел, он использует только геттеры и сеттеры. Мне же нужно чтобы было без них.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
1 час назад, Antonshka сказал:

Мне же нужно чтобы было без них

Это когда для lua поля структур делаешь возможно геттеры/сеттеры в т.ч. и на знак равенства назначать. А в c++ так нельзя🙂Разве что ты можешь попробовать что-нибудь с дефайнами или шаблонами вперемешку с перегруженными операторами. Но это всё равно будет выглядеть не так, как требуется. Хочешь улучшать навыки программирования - выстраивай логику программы наиболее удобным образом.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
4 часа назад, youneuoy сказал:

Это когда для lua поля структур делаешь возможно геттеры/сеттеры в т.ч. и на знак равенства назначать. А в c++ так нельзя🙂Разве что ты можешь попробовать что-нибудь с дефайнами или шаблонами вперемешку с перегруженными операторами. Но это всё равно будет выглядеть не так, как требуется. Хочешь улучшать навыки программирования - выстраивай логику программы наиболее удобным образом.

Да, я сам за то чтобы программа была устроена самым простым и понятным образом. Без наворотов, только необходимый минимум.

Краткость и простота и удобство, это по мне.

СЕ же на Паскале как я понял написан. DB говорит в СЕ реализация записи и считывания полей через RTTI. Но в С++ RTTI только и умеет что получать имя типа, не более. Да и потом, я не понимаю что толку от этого. Ну получил я значения полей класса, а дальше что? Таймер там нужен для периодической оценки смены значений полей, или еще что, не знаю.

 

С перегруженными операторами работает как надо, просто приходится для каждой арифметической операции писать свою функцию.

Пока я остановился на основных

Спойлер

class ctrlHeight
{
public:
	ctrlHeight() = delete;
	ctrlHeight(Control&);
	ctrlHeight(Control&, int);
	~ctrlHeight();
	int getHeight();
	int operator=(int);
	int operator=(ctrlHeight&);
	int operator+(int);
	int operator-(int);
	int operator+=(int);
	int operator-=(int);
	int operator*(int);
	int operator/(int);
	int operator*=(int);
	int operator/=(int);
	int operator%(int);
	int operator%=(int);
	operator int();
private:
	void InitHeight();
private:
	bool isHeightInit = false;
	Control& m_Owner;
	int m_Height{ 0 };
};

 

Это класс для параметра высоты окна.

Работает как в СЕ.

Можно писать и так и сяк

Спойлер

DLG_CAR->Height = 200;
DLG_CAR->Width = DLG_CAMERA->Height;
DLG_CAR->Width += DLG_CAMERA->Height;
DLG_CAR->Width = 500 - DLG_CAMERA->Height + 20 *  DLG_CAR->Width / 4;

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Предпросмотр
Авторизация  

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.