C++ WinAPI - Przyciski nieładne

0

Witam
Pogłębiam wiedze z zakresu frameworka winapi, trochę nie jestem przekonany z powodu starodawnego wyglądu interfejsu, przyciski itd. Czy jest możliwość ustawienia innego stylu tych przycisków aby wyglądały jakość normlanie ? Ogólnie programowałem w java i znam ten język bardzo dobrze oraz samego swinga który daję bardzo dużo możliwości z zakresu modyfikacji interfejsu. Nic na ten temat nie potrafię znaleźć w internecie.

0

Rzuć okiem na to: https://docs.microsoft.com/en-gb/windows/win32/api/uxtheme/nf-uxtheme-drawthemebackground?redirectedfrom=MSDN

Pamiętam, że tam były jakieś pułapki na programistę, ale nie pamiętam już, jakie konkretnie…

6

Visual Studio 2022.

#include <windows.h>

int main()
{
    MessageBox(nullptr, L"Test", L"Test", MB_OK);
}

Wygląd buttona jest jak z Windows 9x, nie reaguje na najechanie myszką:

screenshot-20220807002450.png

O to ci chodzi?


We właściwościach projektu, w opcjach linkera, w pozycji "Additional Manifest Dependencies" (Dodatkowe zależności manifestu) wklejamy jako jedną linijkę:

type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'

Przebudowujemy (Rebuild) projekt.

screenshot-20220807002240.png

Button wygląda zgodnie ze skórką systemową (tutaj: Windows 10) i zmienia się przy najechaniu myszką.

Alternatywnie zamiast w opcjach projektu można wkleić poniższe gdziekolwiek w kodzie, efekt jest identyczny.

#pragma comment(linker,"\"/manifestdependency:type='Win32' \
	name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
	processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

Oskórkowane buttony (i inne kontrolki) pojawiły się w Windows XP wraz z systemową skórką Luna. Jednak z powodu dziwnie rozumianej kompatybilności exek musi w sobie zawierać powyższe zaklęcie żeby je aktywować, inaczej skórkę dostanie tylko sama rama okna.

0

Tutaj wklejam ten kod :


#include <windows.h>
#include <string>


MSG Komunikat;
HWND wHwnd;

const char klasa[] = "Klasa";

HWND przycisk, przycisk2;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

LPWSTR bufor;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
	WNDCLASSEX wc = {};

	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = 0;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = (LPCWSTR)klasa;
	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

	if (!RegisterClassEx(&wc)) {
		MessageBox(nullptr, L"Wysoka Komisja odmawia rejestracji tego okna!", L"Niestety...", MB_ICONEXCLAMATION | MB_OK);
		return 1;
	}


	wHwnd = CreateWindowEx(WS_EX_CLIENTEDGE, (LPCWSTR)klasa, L"Gra snake", WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT,500,500, NULL, NULL, hInstance, NULL);
	if (wHwnd == NULL) {
		MessageBox(NULL, L"Nie dziala!", L"Nie dziala...", MB_ICONEXCLAMATION | MB_OK);
		return 1;
	}
	przycisk = CreateWindowEx(0, L"BUTTON", L"start", WS_CHILD | WS_VISIBLE ,
		100, 0, 50, 50, wHwnd, nullptr, nullptr, nullptr);
	przycisk2 = CreateWindowEx(0, L"BUTTON", L"start", WS_CHILD | WS_VISIBLE ,
		0, 0, 50, 50, wHwnd, NULL, NULL, NULL);

	ShowWindow(wHwnd, nCmdShow);
	UpdateWindow(wHwnd);


	while (GetMessage(&Komunikat, NULL, 0, 0)){
		TranslateMessage(&Komunikat);
		DispatchMessage(&Komunikat);
	}

	return Komunikat.wParam;

}


LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {

	switch (msg){
	case WM_CLOSE:
		DestroyWindow(hwnd);
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	case WM_COMMAND :
		if ((HWND)lParam == przycisk) {
			bufor = (LPWSTR)GlobalAlloc(GPTR, GetWindowTextLength(przycisk) + 1);
			GetWindowText(przycisk, bufor, GetWindowTextLength(przycisk) + 1);
			if (std::wstring(bufor) == L"start") {
				SetWindowText(przycisk, L"stop");

			}
			else if (std::wstring(bufor) == L"stop") {
				SetWindowText(przycisk, L"start");
			}
			
		}
		else if ((HWND)lParam == przycisk2) {
			bufor = (LPWSTR)GlobalAlloc(GPTR, GetWindowTextLength(przycisk2) + 1);
			
			GetWindowText(przycisk2, bufor, GetWindowTextLength(przycisk2) + 1);
			if (std::wstring(bufor) == L"start") {
				SetWindowText(przycisk2, L"stop");
				

			}
			else if (std::wstring(bufor) == L"stop") {
				SetWindowText(przycisk2, L"start");
			}
		}


		GlobalFree(bufor);
		break;
	default:
		return DefWindowProc(hwnd, msg, wParam, lParam);
	}

	return 0;
}
1

"U mnie działa". W sensie, że wpisanie w Additional Manifest Dependencies tego co podałem wyżej zmienia wygląd przycisków. Pamiętaj żeby zrobić Rebuild Solution, zwykła kompilacja może nie wystarczyć.

Widzę natomiast w kodzie parę innych problemów:

	const char klasa[] = "Klasa";

	wc.lpszClassName = (LPCWSTR)klasa;

Rzutujesz na siłę const char* na const wchar_t*, czyli przekazujesz jakieś śmieci. Potem przekazujesz drugi raz te same śmieci więc jakoś to działa, ale nie musi.

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2);

To jest bardzo dziwne. Dokumentacja mówi, żeby do wybranego koloru dodać 1. Czyli jeśli chcesz COLOR_WINDOW, to powinno być (HBRUSH)(COLOR_WINDOW + 1).
Dodajesz 2, czyli robisz to samo co (HBRUSH)(COLOR_WINDOWFRAME + 1), i ten COLOR_WINDOWFRAME widzisz na ekranie.

bufor = (LPWSTR)GlobalAlloc(GPTR, GetWindowTextLength(przycisk) + 1);

To jest OK, ale nie ma sensu wydziwiać z GlobalAlloc. Użyj po prostu new.

GlobalFree(bufor);

Nie zabezpieczasz się przed ponownym zwalnianiem pamięci już raz zwolnionej. Ustaw bufor na nullptr. No i użyj delete.

1

Na pewno ktos gdzies juz o tym wspomnial, ale na wszelki wypadek: budowanie (zwlaszcza calego) GUI w winapi w 2022 to zagadnienie raczej czysto akademickie. Nie zabym nial z tym jakis problem, bo to fajna sprawa jak ktos chce poznac jak to funkcjonuje od podstaw (jak kiedys uczono asemblera) lub implementowac rozne bardzo specyficzne rozwiazania. Ewentualnie jako wstep przed rozpoczeciem nauki czegos pokroju: Qt / Tk / GTK / wxWidgets (/ to w strone czego powiewa obecnie choragiewka microsoftu) - ktore wydawaly by sie bardziej naturalnym kierunkiem przy przechodzeniu z swinga. Zwlaszcza, ze wiekszosc ma dostepne oprogramowanie do automatycznego budowania GUI i wrapper'y w innych jezykach co znacznie zwieksza wartosc poswieconego na nauke czasu.

Ps. Odpowiedz jest w tym kierunku ze wzgledu na wspomnianego swinga i wspomniany "starodawny wyglad", bo uzywajac paraleli to troche tak jak przejscie od standardowej naprawy silnika do odlewania wlasnych tlokow, co moze sie kiedys robilo ale w dzisiejszych czasach to raczej domena moto-faanatykow scigajacych sie w podbijaniu kolejnych rekordow czy przywracaniu do zycia historii.

1 użytkowników online, w tym zalogowanych: 0, gości: 1