C++ WinAPI - Przyciski nieładne

C++ WinAPI - Przyciski nieładne
P3
  • Rejestracja:około 4 lata
  • Ostatnio:ponad rok
  • Postów:103
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.

Althorion
Moderator C/C++
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 12 godzin
  • Postów:1605
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…

Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 9 godzin
6

Visual Studio 2022.

Kopiuj
#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ę:

Kopiuj
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.

Kopiuj
#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.

edytowany 2x, ostatnio: Azarien
P3
Działą faktycznie na messagebox ale na komponenty znajdujące się w okienku już nie. Tworze komponenty za pomocą "CreateWindowEx"
Azarien
jakie komponenty? pokaż jakiś minimalny kod.
P3
#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.hbrBac
P3
  • Rejestracja:około 4 lata
  • Ostatnio:ponad rok
  • Postów:103
0

Tutaj wklejam ten kod :

Kopiuj

#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;
}
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 9 godzin
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:

Kopiuj
	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.

Kopiuj
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.

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

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

Kopiuj
GlobalFree(bufor);

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

edytowany 1x, ostatnio: Azarien
P3
zrobiłem przebudowałem, wyczyściłem projekt i dalej nic, fatycznie button w messageboxie się zmienił ale w okienku już nie
Azarien
coś źle robisz. w tym samym programie, jednocześnie, masz dobry button w MessageBox a zły na własnym oknie? to raczej nieprawdopodobne.
LO
  • Rejestracja:ponad 2 lata
  • Ostatnio:ponad 2 lata
  • Postów:1
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.

edytowany 3x, ostatnio: Lobeoqsyfep
CZ
Ale są jeszcze na rynku pracy oferty z winapi i comem, więc teoretycznie może mu się to przydać. Sam na staż trafiłem do takiego g****. Nie polecam ale niestety rynek c++ w Polsce to nadal technologia sprzed 10-20 lat
ZK
@Czitels: rynek c++ w Polsce - a czy w polsce jest w ogóle jakikolwiek rynek C++ lub czegokolwiek ? Czy tylko produkujemy meble i cukier na export ?
CZ
LO
@zkubinski: w gierkach i grach jest pewnie troche. C ma tez duzo zastosowan poza rynkiem PC gdzie zastopil asemblera, a w kombinacjach z C++ mozna tez kozystac na dokladke do jezykow programowania wyzszego poziomu, np. kiedy akurat jest komus na reke zeby konkretna operacja sie wykonywala pare godzin szybciej - "zaledwie X%" be damned, bo np. zlapalby sie akurat na godziny biurowe czyli technicznie dzien wczesniej. WinApi tez ma swoje zastosowania ale te o ktorych slyszalem sa raczej egzotyczne, a czesciej w przypadku interfejsu uzytkownika, towarzysza innemu toolkitowi.
Azarien
@Lobeoqsyfep: ktoś te wszystkie toolkity też musi pisać i utrzymywać, a napisanie w miarę złożonego UI w czystym WinAPI bez toolkitów ma tu sporą wartość dydaktyczną. No i mamy całą niejułajową część WinAPI, te wszystkie COMy, DirectX-y, które wydaje mi się że są dość mało znane.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.